diff --git a/ui/src/dashboards/components/GraphOptionsCustomizableField.tsx b/ui/src/dashboards/components/GraphOptionsCustomizableField.tsx new file mode 100644 index 000000000..829f05443 --- /dev/null +++ b/ui/src/dashboards/components/GraphOptionsCustomizableField.tsx @@ -0,0 +1,62 @@ +import React, {PureComponent} from 'react' + +import InputClickToEdit from 'src/shared/components/InputClickToEdit' + +type Field = { + internalName: string + displayName: string + visible: boolean +} + +interface Props { + internalName: string + displayName: string + visible: boolean + onFieldUpdate: (field: Field) => void +} + +class GraphOptionsCustomizableField extends PureComponent { + constructor(props) { + super(props) + + this.handleFieldRename = this.handleFieldRename.bind(this) + this.handleToggleVisible = this.handleToggleVisible.bind(this) + } + + handleFieldRename(rename: string) { + const {onFieldUpdate, internalName, visible} = this.props + onFieldUpdate({internalName, displayName: rename, visible}) + } + + handleToggleVisible() { + const {onFieldUpdate, internalName, displayName, visible} = this.props + onFieldUpdate({internalName, displayName, visible: !visible}) + } + + render() { + const {internalName, displayName, visible} = this.props + + return ( +
+
+ + {internalName} +
+ +
+ ) + } +} + +export default GraphOptionsCustomizableField diff --git a/ui/src/dashboards/components/GraphOptionsCustomizeFields.tsx b/ui/src/dashboards/components/GraphOptionsCustomizeFields.tsx new file mode 100644 index 000000000..7683e329d --- /dev/null +++ b/ui/src/dashboards/components/GraphOptionsCustomizeFields.tsx @@ -0,0 +1,36 @@ +import React, {SFC} from 'react' + +import GraphOptionsCustomizableField from 'src/dashboards/components/GraphOptionsCustomizableField' +import uuid from 'uuid' + +type Field = { + internalName: string + displayName: string + visible: boolean +} + +interface Props { + fields: Field[] + onFieldUpdate: (field: Field) => void +} + +const GraphOptionsCustomizeFields: SFC = ({fields, onFieldUpdate}) => { + return ( +
+ + {fields.map(field => { + return ( + + ) + })} +
+ ) +} + +export default GraphOptionsCustomizeFields diff --git a/ui/test/dashboards/components/GraphOptionsCustomizableField.test.tsx b/ui/test/dashboards/components/GraphOptionsCustomizableField.test.tsx new file mode 100644 index 000000000..cf41d10e3 --- /dev/null +++ b/ui/test/dashboards/components/GraphOptionsCustomizableField.test.tsx @@ -0,0 +1,102 @@ +import React from 'react' + +import GraphOptionsCustomizableField from 'src/dashboards/components/GraphOptionsCustomizableField' +import InputClickToEdit from 'src/shared/components/InputClickToEdit' + +import {shallow} from 'enzyme' + +const setup = (override = {}) => { + const props = { + internalName: '', + displayName: '', + visible: true, + onFieldUpdate: () => {}, + ...override, + } + + const wrapper = shallow() + const instance = wrapper.instance() as GraphOptionsCustomizableField + + return {wrapper, props, instance} +} + +describe('Dashboards.Components.GraphOptionsCustomizableField', () => { + describe('rendering', () => { + it('displays both label div and InputClickToEdit', () => { + const {wrapper} = setup() + const label = wrapper.find('div').last() + const input = wrapper.find(InputClickToEdit) + const icon = wrapper.find('span') + + expect(label.exists()).toBe(true) + expect(icon.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() + const icon = wrapper.find('span') + + expect(label.exists()).toBe(true) + expect(label.children().contains(internalName)).toBe(true) + expect(icon.exists()).toBe(true) + }) + }) + + describe('when visible is false', () => { + it('displays disabled inputClickToEdit', () => { + const visible = false + const {wrapper} = setup({visible}) + const input = wrapper.find(InputClickToEdit) + + expect(input.prop('disabled')).toBe(!visible) + }) + }) + }) + + describe('instance methods', () => { + describe('#handleFieldUpdate', () => { + it('calls onFieldUpdate once with internalName, new name, and visible', () => { + const onFieldUpdate = jest.fn() + const internalName = 'test' + const {instance, props: {visible}} = setup({ + onFieldUpdate, + internalName, + }) + const rename = 'TEST' + + instance.handleFieldRename(rename) + + expect(onFieldUpdate).toHaveBeenCalledTimes(1) + expect(onFieldUpdate).toHaveBeenCalledWith({ + internalName, + displayName: rename, + visible, + }) + }) + }) + + describe('#handleToggleVisible', () => { + it('calls onFieldUpdate once with !visible, internalName, and displayName', () => { + const onFieldUpdate = jest.fn() + const visible = true + const {instance, props: {internalName, displayName}} = setup({ + visible, + onFieldUpdate, + }) + + instance.handleToggleVisible() + + expect(onFieldUpdate).toHaveBeenCalledTimes(1) + expect(onFieldUpdate).toHaveBeenCalledWith({ + internalName, + displayName, + visible: !visible, + }) + }) + }) + }) +}) diff --git a/ui/test/dashboards/components/GraphOptionsCustomizeFields.test.tsx b/ui/test/dashboards/components/GraphOptionsCustomizeFields.test.tsx new file mode 100644 index 000000000..107a191d7 --- /dev/null +++ b/ui/test/dashboards/components/GraphOptionsCustomizeFields.test.tsx @@ -0,0 +1,34 @@ +import React from 'react' + +import GraphOptionsCustomizeFields from 'src/dashboards/components/GraphOptionsCustomizeFields' +import GraphOptionsCustomizableField from 'src/dashboards/components/GraphOptionsCustomizableField' +import {TIME_FIELD_DEFAULT} from 'src/shared/constants/tableGraph' + +import {shallow} from 'enzyme' + +const setup = (override = {}) => { + const props = { + fields: [], + onFieldUpdate: () => {}, + ...override, + } + + const wrapper = shallow() + + return {wrapper, props} +} + +describe('Dashboards.Components.GraphOptionsCustomizableField', () => { + describe('rendering', () => { + it('displays label and all fields passed in', () => { + const fields = [TIME_FIELD_DEFAULT] + const {wrapper} = setup({fields}) + const label = wrapper.find('label') + const CustomizableFields = wrapper.find(GraphOptionsCustomizableField) + + expect(label.exists()).toBe(true) + expect(CustomizableFields.exists()).toBe(true) + expect(CustomizableFields.length).toBe(fields.length) + }) + }) +})