From c6da352204dd50a4c9074c0ea0a943c3d937f44d Mon Sep 17 00:00:00 2001 From: Jared Scheib Date: Tue, 13 Mar 2018 18:34:34 -0700 Subject: [PATCH 01/48] Add dummy data for KapacitorRules component test Signed-off-by: Deniz Kusefoglu --- ui/test/resources.ts | 98 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 98 insertions(+) diff --git a/ui/test/resources.ts b/ui/test/resources.ts index caee2f9c51..ffad271a17 100644 --- a/ui/test/resources.ts +++ b/ui/test/resources.ts @@ -59,3 +59,101 @@ export const kapacitor = { proxy: '/proxy/kapacitor/1', }, } + +export const kapacitorRules = [ + { + id: 'chronograf-v1-1bb60c5d-9c46-4601-8fdd-930ac5d2ae3d', + tickscript: + "var db = 'telegraf'\n\nvar rp = 'autogen'\n\nvar measurement = 'cpu'\n\nvar groupBy = ['cpu']\n\nvar whereFilter = lambda: (\"cpu\" != 'cpu-total' OR \"cpu\" != 'cpu1')\n\nvar period = 1h\n\nvar name = 'asdfasdfasdfasdfbob'\n\nvar idVar = name + ':{{.Group}}'\n\nvar message = ''\n\nvar idTag = 'alertID'\n\nvar levelTag = 'level'\n\nvar messageField = 'message'\n\nvar durationField = 'duration'\n\nvar outputDB = 'chronograf'\n\nvar outputRP = 'autogen'\n\nvar outputMeasurement = 'alerts'\n\nvar triggerType = 'deadman'\n\nvar threshold = 0.0\n\nvar data = stream\n |from()\n .database(db)\n .retentionPolicy(rp)\n .measurement(measurement)\n .groupBy(groupBy)\n .where(whereFilter)\n\nvar trigger = data\n |deadman(threshold, period)\n .stateChangesOnly()\n .message(message)\n .id(idVar)\n .idTag(idTag)\n .levelTag(levelTag)\n .messageField(messageField)\n .durationField(durationField)\n .stateChangesOnly()\n .pushover()\n .pushover()\n .sensu()\n .source('Kapacitorsdfasdf')\n .handlers()\n\ntrigger\n |eval(lambda: \"emitted\")\n .as('value')\n .keep('value', messageField, durationField)\n |eval(lambda: float(\"value\"))\n .as('value')\n .keep()\n |influxDBOut()\n .create()\n .database(outputDB)\n .retentionPolicy(outputRP)\n .measurement(outputMeasurement)\n .tag('alertName', name)\n .tag('triggerType', triggerType)\n\ntrigger\n |httpOut('output')\n", + query: { + id: 'chronograf-v1-1bb60c5d-9c46-4601-8fdd-930ac5d2ae3d', + database: 'telegraf', + measurement: 'cpu', + retentionPolicy: 'autogen', + fields: [], + tags: { + cpu: ['cpu-total', 'cpu1'], + }, + groupBy: { + time: '', + tags: ['cpu'], + }, + areTagsAccepted: false, + rawText: null, + range: null, + shifts: null, + }, + every: '', + alertNodes: { + typeOf: 'alert', + stateChangesOnly: true, + useFlapping: false, + post: [], + tcp: [], + email: [], + exec: [], + log: [], + victorOps: [], + pagerDuty: [], + pushover: [ + { + userKey: '', + device: '', + title: '', + url: '', + urlTitle: '', + sound: '', + }, + { + userKey: '', + device: '', + title: '', + url: '', + urlTitle: '', + sound: '', + }, + ], + sensu: [ + { + source: 'Kapacitorsdfasdf', + handlers: [], + }, + ], + slack: [], + telegram: [], + hipChat: [], + alerta: [], + opsGenie: [], + talk: [], + }, + message: '', + details: '', + trigger: 'deadman', + values: { + period: '1h0m0s', + rangeValue: '', + }, + name: 'asdfasdfasdfasdfbob', + type: 'stream', + dbrps: [ + { + db: 'telegraf', + rp: 'autogen', + }, + ], + status: 'enabled', + executing: true, + error: '', + created: '2018-01-05T15:40:48.195743458-08:00', + modified: '2018-03-13T17:17:23.991640555-07:00', + 'last-enabled': '2018-03-13T17:17:23.991640555-07:00', + links: { + self: + '/chronograf/v1/sources/1/kapacitors/1/rules/chronograf-v1-1bb60c5d-9c46-4601-8fdd-930ac5d2ae3d', + kapacitor: + '/chronograf/v1/sources/1/kapacitors/1/proxy?path=%2Fkapacitor%2Fv1%2Ftasks%2Fchronograf-v1-1bb60c5d-9c46-4601-8fdd-930ac5d2ae3d', + output: + '/chronograf/v1/sources/1/kapacitors/1/proxy?path=%2Fkapacitor%2Fv1%2Ftasks%2Fchronograf-v1-1bb60c5d-9c46-4601-8fdd-930ac5d2ae3d%2Foutput', + }, + }, +] From afa0acb63ec9009b1d9d1b91b362ec23aba3d74c Mon Sep 17 00:00:00 2001 From: Jared Scheib Date: Wed, 14 Mar 2018 16:06:34 -0700 Subject: [PATCH 02/48] Add initial passing enzyme test for KapacitorRules render --- .../components/KapacitorRules.test.tsx | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 ui/test/kapacitor/components/KapacitorRules.test.tsx diff --git a/ui/test/kapacitor/components/KapacitorRules.test.tsx b/ui/test/kapacitor/components/KapacitorRules.test.tsx new file mode 100644 index 0000000000..733571bf7b --- /dev/null +++ b/ui/test/kapacitor/components/KapacitorRules.test.tsx @@ -0,0 +1,39 @@ +import React from 'react' +import {shallow} from 'enzyme' + +import KapacitorRules from 'src/kapacitor/components/KapacitorRules' + +import {source, kapacitorRules} from 'test/resources' + +jest.mock('src/shared/apis', () => require('mocks/shared/apis')) + +const setup = (override = {}) => { + const props = { + source, + rules: kapacitorRules, + hasKapacitor: true, + loading: false, + onDelete: () => {}, + onChangeRuleStatus: () => {}, + } + + const wrapper = shallow() + + return { + wrapper, + props, + } +} + +describe('Kapacitor.Containers.KapacitorRules', () => { + afterEach(() => { + jest.clearAllMocks() + }) + + describe('rendering', () => { + it('renders the KapacitorRules', () => { + const {wrapper} = setup() + expect(wrapper.exists()).toBe(true) + }) + }) +}) From e0111010c7acd77602b8b33a9a19663f1bf61d0e Mon Sep 17 00:00:00 2001 From: Jared Scheib Date: Wed, 14 Mar 2018 16:17:00 -0700 Subject: [PATCH 03/48] Test KapacitorRules to render two tables --- ui/test/kapacitor/components/KapacitorRules.test.tsx | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/ui/test/kapacitor/components/KapacitorRules.test.tsx b/ui/test/kapacitor/components/KapacitorRules.test.tsx index 733571bf7b..03756083a9 100644 --- a/ui/test/kapacitor/components/KapacitorRules.test.tsx +++ b/ui/test/kapacitor/components/KapacitorRules.test.tsx @@ -35,5 +35,10 @@ describe('Kapacitor.Containers.KapacitorRules', () => { const {wrapper} = setup() expect(wrapper.exists()).toBe(true) }) + + it('renders two tables', () => { + const {wrapper} = setup() + expect(wrapper.find('.panel-body').length).toEqual(2) + }) }) }) From d9002cf55777366ae82793316a70a738080c9cea Mon Sep 17 00:00:00 2001 From: Jared Scheib Date: Wed, 14 Mar 2018 16:32:20 -0700 Subject: [PATCH 04/48] Test KapacitorRules to render KapacitorRulesTable & TasksTable --- .../kapacitor/components/KapacitorRules.test.tsx | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/ui/test/kapacitor/components/KapacitorRules.test.tsx b/ui/test/kapacitor/components/KapacitorRules.test.tsx index 03756083a9..500863c941 100644 --- a/ui/test/kapacitor/components/KapacitorRules.test.tsx +++ b/ui/test/kapacitor/components/KapacitorRules.test.tsx @@ -2,6 +2,8 @@ import React from 'react' import {shallow} from 'enzyme' import KapacitorRules from 'src/kapacitor/components/KapacitorRules' +import KapacitorRulesTable from 'src/kapacitor/components/KapacitorRulesTable' +import TasksTable from 'src/kapacitor/components/TasksTable' import {source, kapacitorRules} from 'test/resources' @@ -14,14 +16,14 @@ const setup = (override = {}) => { hasKapacitor: true, loading: false, onDelete: () => {}, - onChangeRuleStatus: () => {}, + onChangeRuleStatus: () => {} } const wrapper = shallow() return { wrapper, - props, + props } } @@ -38,7 +40,12 @@ describe('Kapacitor.Containers.KapacitorRules', () => { it('renders two tables', () => { const {wrapper} = setup() - expect(wrapper.find('.panel-body').length).toEqual(2) + + const kapacitorRulesTable = wrapper.find('KapacitorRulesTable') + expect(kapacitorRulesTable.length).toEqual(1) + + const tasksTable = wrapper.find('TasksTable') + expect(tasksTable.length).toEqual(1) }) }) }) From 568ca6b5edb14ec0367490beccfc86d16be8c7a5 Mon Sep 17 00:00:00 2001 From: Jared Scheib Date: Wed, 14 Mar 2018 16:46:40 -0700 Subject: [PATCH 05/48] Split KapacitorRules render test into two tests --- ui/test/kapacitor/components/KapacitorRules.test.tsx | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/ui/test/kapacitor/components/KapacitorRules.test.tsx b/ui/test/kapacitor/components/KapacitorRules.test.tsx index 500863c941..ac13c05155 100644 --- a/ui/test/kapacitor/components/KapacitorRules.test.tsx +++ b/ui/test/kapacitor/components/KapacitorRules.test.tsx @@ -38,7 +38,7 @@ describe('Kapacitor.Containers.KapacitorRules', () => { expect(wrapper.exists()).toBe(true) }) - it('renders two tables', () => { + it('renders KapacitorRulesTable', () => { const {wrapper} = setup() const kapacitorRulesTable = wrapper.find('KapacitorRulesTable') @@ -47,5 +47,12 @@ describe('Kapacitor.Containers.KapacitorRules', () => { const tasksTable = wrapper.find('TasksTable') expect(tasksTable.length).toEqual(1) }) + + it('renders TasksTable', () => { + const {wrapper} = setup() + + const tasksTable = wrapper.find('TasksTable') + expect(tasksTable.length).toEqual(1) + }) }) }) From beaa18658633d2bf73aed4e156a3e75445bf2241 Mon Sep 17 00:00:00 2001 From: Jared Scheib Date: Wed, 14 Mar 2018 16:48:15 -0700 Subject: [PATCH 06/48] Remove unused imports --- ui/test/kapacitor/components/KapacitorRules.test.tsx | 2 -- 1 file changed, 2 deletions(-) diff --git a/ui/test/kapacitor/components/KapacitorRules.test.tsx b/ui/test/kapacitor/components/KapacitorRules.test.tsx index ac13c05155..92bad4b6f0 100644 --- a/ui/test/kapacitor/components/KapacitorRules.test.tsx +++ b/ui/test/kapacitor/components/KapacitorRules.test.tsx @@ -2,8 +2,6 @@ import React from 'react' import {shallow} from 'enzyme' import KapacitorRules from 'src/kapacitor/components/KapacitorRules' -import KapacitorRulesTable from 'src/kapacitor/components/KapacitorRulesTable' -import TasksTable from 'src/kapacitor/components/TasksTable' import {source, kapacitorRules} from 'test/resources' From ab360fa1f8d1bbcb7660cf864ca986336533076b Mon Sep 17 00:00:00 2001 From: Jared Scheib Date: Wed, 14 Mar 2018 16:50:24 -0700 Subject: [PATCH 07/48] Remove unused override var --- ui/test/kapacitor/components/KapacitorRules.test.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/test/kapacitor/components/KapacitorRules.test.tsx b/ui/test/kapacitor/components/KapacitorRules.test.tsx index 92bad4b6f0..65e7b63baf 100644 --- a/ui/test/kapacitor/components/KapacitorRules.test.tsx +++ b/ui/test/kapacitor/components/KapacitorRules.test.tsx @@ -7,7 +7,7 @@ import {source, kapacitorRules} from 'test/resources' jest.mock('src/shared/apis', () => require('mocks/shared/apis')) -const setup = (override = {}) => { +const setup = () => { const props = { source, rules: kapacitorRules, From 90ac8ad8dbddbb957b1bb6d47f85f2790808f469 Mon Sep 17 00:00:00 2001 From: Jared Scheib Date: Wed, 14 Mar 2018 16:51:33 -0700 Subject: [PATCH 08/48] Remove unused jest.mock --- ui/test/kapacitor/components/KapacitorRules.test.tsx | 2 -- 1 file changed, 2 deletions(-) diff --git a/ui/test/kapacitor/components/KapacitorRules.test.tsx b/ui/test/kapacitor/components/KapacitorRules.test.tsx index 65e7b63baf..b3e726c1f3 100644 --- a/ui/test/kapacitor/components/KapacitorRules.test.tsx +++ b/ui/test/kapacitor/components/KapacitorRules.test.tsx @@ -5,8 +5,6 @@ import KapacitorRules from 'src/kapacitor/components/KapacitorRules' import {source, kapacitorRules} from 'test/resources' -jest.mock('src/shared/apis', () => require('mocks/shared/apis')) - const setup = () => { const props = { source, From 7f493204db72bac86ea71a4e93c428f5a92582de Mon Sep 17 00:00:00 2001 From: Jared Scheib Date: Wed, 14 Mar 2018 16:53:58 -0700 Subject: [PATCH 09/48] Clean up --- ui/test/kapacitor/components/KapacitorRules.test.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/test/kapacitor/components/KapacitorRules.test.tsx b/ui/test/kapacitor/components/KapacitorRules.test.tsx index b3e726c1f3..68cb31aa9c 100644 --- a/ui/test/kapacitor/components/KapacitorRules.test.tsx +++ b/ui/test/kapacitor/components/KapacitorRules.test.tsx @@ -29,7 +29,7 @@ describe('Kapacitor.Containers.KapacitorRules', () => { }) describe('rendering', () => { - it('renders the KapacitorRules', () => { + it('renders KapacitorRules', () => { const {wrapper} = setup() expect(wrapper.exists()).toBe(true) }) From 13da9bec6fa81b8497f6f07ac9880d28ac39308d Mon Sep 17 00:00:00 2001 From: Jared Scheib Date: Wed, 14 Mar 2018 17:06:27 -0700 Subject: [PATCH 10/48] Add initial enzyme test for component TasksTable render --- .../kapacitor/components/TasksTable.test.tsx | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 ui/test/kapacitor/components/TasksTable.test.tsx diff --git a/ui/test/kapacitor/components/TasksTable.test.tsx b/ui/test/kapacitor/components/TasksTable.test.tsx new file mode 100644 index 0000000000..007362d86e --- /dev/null +++ b/ui/test/kapacitor/components/TasksTable.test.tsx @@ -0,0 +1,35 @@ +import React from 'react' +import {shallow} from 'enzyme' + +import TasksTable from 'src/kapacitor/components/TasksTable' + +import {source, kapacitorRules} from 'test/resources' + +const setup = () => { + const props = { + source, + tasks: kapacitorRules, + onDelete: () => {}, + onChangeRuleStatus: () => {} + } + + const wrapper = shallow() + + return { + wrapper, + props + } +} + +describe('Kapacitor.Components.TasksTable', () => { + afterEach(() => { + jest.clearAllMocks() + }) + + describe('rendering', () => { + it('renders the TasksTable', () => { + const {wrapper} = setup() + expect(wrapper.exists()).toBe(true) + }) + }) +}) From 81e2551053bfde2f78781dfb5eb220b15e525631 Mon Sep 17 00:00:00 2001 From: Jared Scheib Date: Wed, 14 Mar 2018 17:17:16 -0700 Subject: [PATCH 11/48] Add initial enzyme test for component KapacitorRulesTable render --- .../components/KapacitorRulesTable.test.tsx | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 ui/test/kapacitor/components/KapacitorRulesTable.test.tsx diff --git a/ui/test/kapacitor/components/KapacitorRulesTable.test.tsx b/ui/test/kapacitor/components/KapacitorRulesTable.test.tsx new file mode 100644 index 0000000000..22705d885d --- /dev/null +++ b/ui/test/kapacitor/components/KapacitorRulesTable.test.tsx @@ -0,0 +1,31 @@ +import React from 'react' +import {shallow} from 'enzyme' + +import KapacitorRulesTable from 'src/kapacitor/components/KapacitorRulesTable' + +import {source, kapacitorRules} from 'test/resources' + +const setup = () => { + const props = { + source, + rules: kapacitorRules, + onDelete: () => {}, + onChangeRuleStatus: () => {} + } + + const wrapper = shallow() + + return { + wrapper, + props + } +} + +describe('Kapacitor.Components.KapacitorRulesTable', () => { + describe('rendering', () => { + it('renders KapacitorRulesTable', () => { + const {wrapper} = setup() + expect(wrapper.exists()).toBe(true) + }) + }) +}) From a4cf6276f51902ff27794e764c48dd0ef61fe217 Mon Sep 17 00:00:00 2001 From: Jared Scheib Date: Wed, 14 Mar 2018 17:18:29 -0700 Subject: [PATCH 12/48] Remove unused jest in Kapacitor tests --- ui/test/kapacitor/components/KapacitorRules.test.tsx | 4 ---- ui/test/kapacitor/components/TasksTable.test.tsx | 4 ---- 2 files changed, 8 deletions(-) diff --git a/ui/test/kapacitor/components/KapacitorRules.test.tsx b/ui/test/kapacitor/components/KapacitorRules.test.tsx index 68cb31aa9c..2b2f49d7ec 100644 --- a/ui/test/kapacitor/components/KapacitorRules.test.tsx +++ b/ui/test/kapacitor/components/KapacitorRules.test.tsx @@ -24,10 +24,6 @@ const setup = () => { } describe('Kapacitor.Containers.KapacitorRules', () => { - afterEach(() => { - jest.clearAllMocks() - }) - describe('rendering', () => { it('renders KapacitorRules', () => { const {wrapper} = setup() diff --git a/ui/test/kapacitor/components/TasksTable.test.tsx b/ui/test/kapacitor/components/TasksTable.test.tsx index 007362d86e..cf0e2ddd53 100644 --- a/ui/test/kapacitor/components/TasksTable.test.tsx +++ b/ui/test/kapacitor/components/TasksTable.test.tsx @@ -22,10 +22,6 @@ const setup = () => { } describe('Kapacitor.Components.TasksTable', () => { - afterEach(() => { - jest.clearAllMocks() - }) - describe('rendering', () => { it('renders the TasksTable', () => { const {wrapper} = setup() From a81fa3c01e4b8d278bc4be8516dbd047ea2d2286 Mon Sep 17 00:00:00 2001 From: Jared Scheib Date: Wed, 14 Mar 2018 18:31:09 -0700 Subject: [PATCH 13/48] Add string validator & tests for UUIDv4 --- ui/src/utils/stringValidators.js | 6 ++++++ ui/test/utils/stringValidators.test.js | 24 ++++++++++++++++++++++++ 2 files changed, 30 insertions(+) create mode 100644 ui/src/utils/stringValidators.js create mode 100644 ui/test/utils/stringValidators.test.js diff --git a/ui/src/utils/stringValidators.js b/ui/src/utils/stringValidators.js new file mode 100644 index 0000000000..e94aeced7d --- /dev/null +++ b/ui/src/utils/stringValidators.js @@ -0,0 +1,6 @@ +// uses Gajus' regex matcher from https://stackoverflow.com/questions/136505/searching-for-uuids-in-text-with-regex +export const isUUIDv4 = str => + str.length === 36 && + !!str.match( + /[a-f0-9]{8}-[a-f0-9]{4}-4[a-f0-9]{3}-[89aAbB][a-f0-9]{3}-[a-f0-9]{12}/ + ) diff --git a/ui/test/utils/stringValidators.test.js b/ui/test/utils/stringValidators.test.js new file mode 100644 index 0000000000..c110c2aafc --- /dev/null +++ b/ui/test/utils/stringValidators.test.js @@ -0,0 +1,24 @@ +import uuid from 'uuid' + +import {isUUIDv4} from 'src/utils/stringValidators' + +describe('isUUIDv4', () => { + it('returns false for non-matches', () => { + const inputWrongLength = 'abcd' + expect(isUUIDv4(inputWrongLength)).toEqual(false) + + const inputWrongFormat = 'abcdefghijklmnopqrstuvwxyz1234567890' + expect(isUUIDv4(inputWrongFormat)).toEqual(false) + + const inputWrongCharRange = 'z47ac10b-58cc-4372-a567-0e02b2c3d479' + expect(isUUIDv4(inputWrongCharRange)).toEqual(false) + }) + + it('returns true for matches', () => { + const inputRight = 'a47ac10b-58cc-4372-a567-0e02b2c3d479' + expect(isUUIDv4(inputRight)).toEqual(true) + + const inputRightFromLibrary = uuid.v4() + expect(isUUIDv4(inputRightFromLibrary)).toEqual(true) + }) +}) From bd6674859cb23500fd24d4cfbdf5503aeef0c831 Mon Sep 17 00:00:00 2001 From: Jared Scheib Date: Wed, 14 Mar 2018 18:44:51 -0700 Subject: [PATCH 14/48] Test KapacitorRulesTable tr keys to be UUIDv4 --- .../components/KapacitorRulesTable.test.tsx | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/ui/test/kapacitor/components/KapacitorRulesTable.test.tsx b/ui/test/kapacitor/components/KapacitorRulesTable.test.tsx index 22705d885d..fb1423b66f 100644 --- a/ui/test/kapacitor/components/KapacitorRulesTable.test.tsx +++ b/ui/test/kapacitor/components/KapacitorRulesTable.test.tsx @@ -1,6 +1,8 @@ import React from 'react' import {shallow} from 'enzyme' +import {isUUIDv4} from 'src/utils/stringValidators' + import KapacitorRulesTable from 'src/kapacitor/components/KapacitorRulesTable' import {source, kapacitorRules} from 'test/resources' @@ -10,14 +12,14 @@ const setup = () => { source, rules: kapacitorRules, onDelete: () => {}, - onChangeRuleStatus: () => {} + onChangeRuleStatus: () => {}, } const wrapper = shallow() return { wrapper, - props + props, } } @@ -27,5 +29,13 @@ describe('Kapacitor.Components.KapacitorRulesTable', () => { const {wrapper} = setup() expect(wrapper.exists()).toBe(true) }) + + it('renders each row with key that is a UUIDv4', () => { + const {wrapper} = setup() + wrapper + .find('tbody') + .children() + .forEach(child => expect(isUUIDv4(child.key())).toEqual(true)) + }) }) }) From f7dbdb8a33d05857731661c6328a38b00ad08355 Mon Sep 17 00:00:00 2001 From: Jared Scheib Date: Wed, 14 Mar 2018 18:45:13 -0700 Subject: [PATCH 15/48] Fix KapacitorRulesTable to use UUIDv4 for tr keys --- ui/src/kapacitor/components/KapacitorRulesTable.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ui/src/kapacitor/components/KapacitorRulesTable.js b/ui/src/kapacitor/components/KapacitorRulesTable.js index d894600457..5f91553da2 100644 --- a/ui/src/kapacitor/components/KapacitorRulesTable.js +++ b/ui/src/kapacitor/components/KapacitorRulesTable.js @@ -2,6 +2,7 @@ import React from 'react' import PropTypes from 'prop-types' import {Link} from 'react-router' import _ from 'lodash' +import uuid from 'uuid' import ConfirmButton from 'src/shared/components/ConfirmButton' import {parseAlertNodeList} from 'src/shared/parsing/parseHandlersFromRule' @@ -33,7 +34,7 @@ const KapacitorRulesTable = ({rules, source, onDelete, onChangeRuleStatus}) => {_.sortBy(rules, r => r.name.toLowerCase()).map(rule => { return ( Date: Fri, 16 Mar 2018 14:18:16 -0700 Subject: [PATCH 16/48] Revert "Fix KapacitorRulesTable to use UUIDv4 for tr keys" This reverts commit f7dbdb8a33d05857731661c6328a38b00ad08355. --- ui/src/kapacitor/components/KapacitorRulesTable.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/ui/src/kapacitor/components/KapacitorRulesTable.js b/ui/src/kapacitor/components/KapacitorRulesTable.js index 5f91553da2..d894600457 100644 --- a/ui/src/kapacitor/components/KapacitorRulesTable.js +++ b/ui/src/kapacitor/components/KapacitorRulesTable.js @@ -2,7 +2,6 @@ import React from 'react' import PropTypes from 'prop-types' import {Link} from 'react-router' import _ from 'lodash' -import uuid from 'uuid' import ConfirmButton from 'src/shared/components/ConfirmButton' import {parseAlertNodeList} from 'src/shared/parsing/parseHandlersFromRule' @@ -34,7 +33,7 @@ const KapacitorRulesTable = ({rules, source, onDelete, onChangeRuleStatus}) => {_.sortBy(rules, r => r.name.toLowerCase()).map(rule => { return ( Date: Fri, 16 Mar 2018 14:18:57 -0700 Subject: [PATCH 17/48] Revert "Test KapacitorRulesTable tr keys to be UUIDv4" This reverts commit bd6674859cb23500fd24d4cfbdf5503aeef0c831. --- .../components/KapacitorRulesTable.test.tsx | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/ui/test/kapacitor/components/KapacitorRulesTable.test.tsx b/ui/test/kapacitor/components/KapacitorRulesTable.test.tsx index fb1423b66f..22705d885d 100644 --- a/ui/test/kapacitor/components/KapacitorRulesTable.test.tsx +++ b/ui/test/kapacitor/components/KapacitorRulesTable.test.tsx @@ -1,8 +1,6 @@ import React from 'react' import {shallow} from 'enzyme' -import {isUUIDv4} from 'src/utils/stringValidators' - import KapacitorRulesTable from 'src/kapacitor/components/KapacitorRulesTable' import {source, kapacitorRules} from 'test/resources' @@ -12,14 +10,14 @@ const setup = () => { source, rules: kapacitorRules, onDelete: () => {}, - onChangeRuleStatus: () => {}, + onChangeRuleStatus: () => {} } const wrapper = shallow() return { wrapper, - props, + props } } @@ -29,13 +27,5 @@ describe('Kapacitor.Components.KapacitorRulesTable', () => { const {wrapper} = setup() expect(wrapper.exists()).toBe(true) }) - - it('renders each row with key that is a UUIDv4', () => { - const {wrapper} = setup() - wrapper - .find('tbody') - .children() - .forEach(child => expect(isUUIDv4(child.key())).toEqual(true)) - }) }) }) From 9cfac3450c54e61678299896bce45267b503abae Mon Sep 17 00:00:00 2001 From: Jared Scheib Date: Fri, 16 Mar 2018 14:37:03 -0700 Subject: [PATCH 18/48] Add more kapacitor rules test data --- ui/test/resources.ts | 175 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 175 insertions(+) diff --git a/ui/test/resources.ts b/ui/test/resources.ts index ffad271a17..6e8c873bb2 100644 --- a/ui/test/resources.ts +++ b/ui/test/resources.ts @@ -156,4 +156,179 @@ export const kapacitorRules = [ '/chronograf/v1/sources/1/kapacitors/1/proxy?path=%2Fkapacitor%2Fv1%2Ftasks%2Fchronograf-v1-1bb60c5d-9c46-4601-8fdd-930ac5d2ae3d%2Foutput', }, }, + { + id: 'chronograf-v1-75b638b0-1530-4163-adab-c9631386e0a2', + tickscript: + "var db = 'telegraf'\n\nvar rp = 'autogen'\n\nvar measurement = 'disk'\n\nvar groupBy = []\n\nvar whereFilter = lambda: TRUE\n\nvar name = 'Untitled bob'\n\nvar idVar = name + ':{{.Group}}'\n\nvar message = ''\n\nvar idTag = 'alertID'\n\nvar levelTag = 'level'\n\nvar messageField = 'message'\n\nvar durationField = 'duration'\n\nvar outputDB = 'chronograf'\n\nvar outputRP = 'autogen'\n\nvar outputMeasurement = 'alerts'\n\nvar triggerType = 'threshold'\n\nvar crit = 0\n\nvar data = stream\n |from()\n .database(db)\n .retentionPolicy(rp)\n .measurement(measurement)\n .groupBy(groupBy)\n .where(whereFilter)\n |eval(lambda: \"inodes_free\")\n .as('value')\n\nvar trigger = data\n |alert()\n .crit(lambda: \"value\" == crit)\n .stateChangesOnly()\n .message(message)\n .id(idVar)\n .idTag(idTag)\n .levelTag(levelTag)\n .messageField(messageField)\n .durationField(durationField)\n .stateChangesOnly()\n .email()\n .pagerDuty()\n .alerta()\n .environment('bob')\n .origin('kapacitoadfr')\n .services()\n\ntrigger\n |eval(lambda: float(\"value\"))\n .as('value')\n .keep()\n |influxDBOut()\n .create()\n .database(outputDB)\n .retentionPolicy(outputRP)\n .measurement(outputMeasurement)\n .tag('alertName', name)\n .tag('triggerType', triggerType)\n\ntrigger\n |httpOut('output')\n", + query: { + id: 'chronograf-v1-75b638b0-1530-4163-adab-c9631386e0a2', + database: 'telegraf', + measurement: 'disk', + retentionPolicy: 'autogen', + fields: [ + { + value: 'inodes_free', + type: 'field', + alias: '', + }, + ], + tags: {}, + groupBy: { + time: '', + tags: [], + }, + areTagsAccepted: false, + rawText: null, + range: null, + shifts: null, + }, + every: '', + alertNodes: { + typeOf: 'alert', + stateChangesOnly: true, + useFlapping: false, + post: [], + tcp: [], + email: [ + { + to: [], + }, + ], + exec: [], + log: [], + victorOps: [], + pagerDuty: [ + { + serviceKey: '', + }, + ], + pushover: [], + sensu: [], + slack: [], + telegram: [], + hipChat: [], + alerta: [ + { + token: '', + resource: '', + event: '', + environment: 'bob', + group: '', + value: '', + origin: 'kapacitoadfr', + service: [], + }, + ], + opsGenie: [], + talk: [], + }, + message: '', + details: '', + trigger: 'threshold', + values: { + operator: 'equal to', + value: '0', + rangeValue: '', + }, + name: 'Untitled bob', + type: 'stream', + dbrps: [ + { + db: 'telegraf', + rp: 'autogen', + }, + ], + status: 'disabled', + executing: false, + error: '', + created: '2018-01-05T15:41:22.759905067-08:00', + modified: '2018-03-14T18:46:37.940091231-07:00', + 'last-enabled': '2018-03-14T18:46:32.409262103-07:00', + links: { + self: + '/chronograf/v1/sources/1/kapacitors/1/rules/chronograf-v1-75b638b0-1530-4163-adab-c9631386e0a2', + kapacitor: + '/chronograf/v1/sources/1/kapacitors/1/proxy?path=%2Fkapacitor%2Fv1%2Ftasks%2Fchronograf-v1-75b638b0-1530-4163-adab-c9631386e0a2', + output: + '/chronograf/v1/sources/1/kapacitors/1/proxy?path=%2Fkapacitor%2Fv1%2Ftasks%2Fchronograf-v1-75b638b0-1530-4163-adab-c9631386e0a2%2Foutput', + }, + }, + { + id: 'chronograf-v1-7734918d-b8b6-460d-a416-34767ba76faa', + tickscript: + "var db = 'telegraf'\n\nvar rp = 'autogen'\n\nvar measurement = 'cpu'\n\nvar groupBy = []\n\nvar whereFilter = lambda: (\"host\" == 'Jareds-MacBook-Pro.local')\n\nvar period = 24h\n\nvar name = 'xena'\n\nvar idVar = name + ':{{.Group}}'\n\nvar message = ''\n\nvar idTag = 'alertID'\n\nvar levelTag = 'level'\n\nvar messageField = 'message'\n\nvar durationField = 'duration'\n\nvar outputDB = 'chronograf'\n\nvar outputRP = 'autogen'\n\nvar outputMeasurement = 'alerts'\n\nvar triggerType = 'deadman'\n\nvar threshold = 0.0\n\nvar data = stream\n |from()\n .database(db)\n .retentionPolicy(rp)\n .measurement(measurement)\n .groupBy(groupBy)\n .where(whereFilter)\n\nvar trigger = data\n |deadman(threshold, period)\n .stateChangesOnly()\n .message(message)\n .id(idVar)\n .idTag(idTag)\n .levelTag(levelTag)\n .messageField(messageField)\n .durationField(durationField)\n .hipChat()\n .room('asdf')\n\ntrigger\n |eval(lambda: \"emitted\")\n .as('value')\n .keep('value', messageField, durationField)\n |eval(lambda: float(\"value\"))\n .as('value')\n .keep()\n |influxDBOut()\n .create()\n .database(outputDB)\n .retentionPolicy(outputRP)\n .measurement(outputMeasurement)\n .tag('alertName', name)\n .tag('triggerType', triggerType)\n\ntrigger\n |httpOut('output')\n", + query: { + id: 'chronograf-v1-7734918d-b8b6-460d-a416-34767ba76faa', + database: 'telegraf', + measurement: 'cpu', + retentionPolicy: 'autogen', + fields: [], + tags: { + host: ['Jareds-MacBook-Pro.local'], + }, + groupBy: { + time: '', + tags: [], + }, + areTagsAccepted: true, + rawText: null, + range: null, + shifts: null, + }, + every: '', + alertNodes: { + typeOf: 'alert', + stateChangesOnly: true, + useFlapping: false, + post: [], + tcp: [], + email: [], + exec: [], + log: [], + victorOps: [], + pagerDuty: [], + pushover: [], + sensu: [], + slack: [], + telegram: [], + hipChat: [ + { + room: 'asdf', + token: '', + }, + ], + alerta: [], + opsGenie: [], + talk: [], + }, + message: '', + details: '', + trigger: 'deadman', + values: { + period: '24h0m0s', + rangeValue: '', + }, + name: 'xena', + type: 'stream', + dbrps: [ + { + db: 'telegraf', + rp: 'autogen', + }, + ], + status: 'disabled', + executing: false, + error: '', + created: '2018-01-05T15:44:54.657212781-08:00', + modified: '2018-03-13T17:17:19.099800735-07:00', + 'last-enabled': '2018-03-13T17:17:15.964357573-07:00', + links: { + self: + '/chronograf/v1/sources/1/kapacitors/1/rules/chronograf-v1-7734918d-b8b6-460d-a416-34767ba76faa', + kapacitor: + '/chronograf/v1/sources/1/kapacitors/1/proxy?path=%2Fkapacitor%2Fv1%2Ftasks%2Fchronograf-v1-7734918d-b8b6-460d-a416-34767ba76faa', + output: + '/chronograf/v1/sources/1/kapacitors/1/proxy?path=%2Fkapacitor%2Fv1%2Ftasks%2Fchronograf-v1-7734918d-b8b6-460d-a416-34767ba76faa%2Foutput', + }, + }, ] From eeda415eb716c73ad658cd22438ff7669c7046a3 Mon Sep 17 00:00:00 2001 From: Jared Scheib Date: Fri, 16 Mar 2018 15:58:06 -0700 Subject: [PATCH 19/48] Add failing test for KapacitorRules renders both tables with unique checkbox IDs --- .../components/KapacitorRules.test.tsx | 30 +++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/ui/test/kapacitor/components/KapacitorRules.test.tsx b/ui/test/kapacitor/components/KapacitorRules.test.tsx index 2b2f49d7ec..fa06a2aef9 100644 --- a/ui/test/kapacitor/components/KapacitorRules.test.tsx +++ b/ui/test/kapacitor/components/KapacitorRules.test.tsx @@ -1,6 +1,8 @@ import React from 'react' import {shallow} from 'enzyme' +import _ from 'lodash' + import KapacitorRules from 'src/kapacitor/components/KapacitorRules' import {source, kapacitorRules} from 'test/resources' @@ -12,14 +14,14 @@ const setup = () => { hasKapacitor: true, loading: false, onDelete: () => {}, - onChangeRuleStatus: () => {} + onChangeRuleStatus: () => {}, } const wrapper = shallow() return { wrapper, - props + props, } } @@ -46,5 +48,29 @@ describe('Kapacitor.Containers.KapacitorRules', () => { const tasksTable = wrapper.find('TasksTable') expect(tasksTable.length).toEqual(1) }) + + it('renders each rule/task checkboxes with unique "id" attribute', () => { + const {wrapper} = setup() + + const kapacitorRulesTableRowsIDs = wrapper + .find('KapacitorRulesTable') + .dive() + .find('tbody') + .children() + .map(child => child.dive().find({type: 'checkbox'}).props().id) + + const tasksTableIDs = wrapper + .find('TasksTable') + .dive() + .find('tbody') + .children() + .map(child => child.dive().find({type: 'checkbox'}).props().id) + + const allCheckboxesIDs = kapacitorRulesTableRowsIDs.concat(tasksTableIDs) + + const containsAnyDuplicate = arr => _.uniq(arr).length !== arr.length + + expect(containsAnyDuplicate(allCheckboxesIDs)).toEqual(false) + }) }) }) From 4ed4be638dea66b526e35404ccaac52b54f176a1 Mon Sep 17 00:00:00 2001 From: Jared Scheib Date: Fri, 16 Mar 2018 16:04:04 -0700 Subject: [PATCH 20/48] Add failing test for KapacitorRules renders both tables rows with unique label FORs --- .../components/KapacitorRules.test.tsx | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/ui/test/kapacitor/components/KapacitorRules.test.tsx b/ui/test/kapacitor/components/KapacitorRules.test.tsx index fa06a2aef9..6f344e0776 100644 --- a/ui/test/kapacitor/components/KapacitorRules.test.tsx +++ b/ui/test/kapacitor/components/KapacitorRules.test.tsx @@ -72,5 +72,31 @@ describe('Kapacitor.Containers.KapacitorRules', () => { expect(containsAnyDuplicate(allCheckboxesIDs)).toEqual(false) }) + + it('renders each rule/task table row label with unique "for" attribute', () => { + const {wrapper} = setup() + + const kapacitorRulesTableRowsLabelFors = wrapper + .find('KapacitorRulesTable') + .dive() + .find('tbody') + .children() + .map(child => child.dive().find('label').props().htmlFor) + + const tasksTableLabelFors = wrapper + .find('TasksTable') + .dive() + .find('tbody') + .children() + .map(child => child.dive().find('label').props().htmlFor) + + const allCheckboxesLabelFors = kapacitorRulesTableRowsLabelFors.concat( + tasksTableLabelFors + ) + + const containsAnyDuplicate = arr => _.uniq(arr).length !== arr.length + + expect(containsAnyDuplicate(allCheckboxesLabelFors)).toEqual(false) + }) }) }) From dcc05ee3829c01ef6ed37540bf06c8f40b4752c7 Mon Sep 17 00:00:00 2001 From: Jared Scheib Date: Fri, 16 Mar 2018 16:16:33 -0700 Subject: [PATCH 21/48] Make KapacitorRulesTable 'id' & 'for' html props unique --- ui/src/kapacitor/components/KapacitorRulesTable.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ui/src/kapacitor/components/KapacitorRulesTable.js b/ui/src/kapacitor/components/KapacitorRulesTable.js index d894600457..783d66218b 100644 --- a/ui/src/kapacitor/components/KapacitorRulesTable.js +++ b/ui/src/kapacitor/components/KapacitorRulesTable.js @@ -65,13 +65,13 @@ const RuleRow = ({rule, source, onDelete, onChangeRuleStatus}) =>
-
From 7acae388f60790b8a6279921479c840fd3230d2b Mon Sep 17 00:00:00 2001 From: Jared Scheib Date: Fri, 16 Mar 2018 16:17:25 -0700 Subject: [PATCH 22/48] Make TasksTable 'id' & 'for' html props unique --- ui/src/kapacitor/components/TasksTable.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ui/src/kapacitor/components/TasksTable.js b/ui/src/kapacitor/components/TasksTable.js index ea49157366..ca9e5b9113 100644 --- a/ui/src/kapacitor/components/TasksTable.js +++ b/ui/src/kapacitor/components/TasksTable.js @@ -53,13 +53,13 @@ const TaskRow = ({task, source, onDelete, onChangeRuleStatus}) =>
-
From 322470ffae1625fd3be92181ca286ce6af661fdd Mon Sep 17 00:00:00 2001 From: Jared Scheib Date: Fri, 16 Mar 2018 18:41:48 -0700 Subject: [PATCH 23/48] Add & clean up many Kapacitor-related TypeScript types for RulesTable --- ui/src/types/index.tsx | 7 +- ui/src/types/kapacitor.tsx | 187 +++++++++++++++++++++++++++++++++++++ ui/src/types/query.tsx | 25 ++++- ui/src/types/sources.tsx | 16 +--- 4 files changed, 217 insertions(+), 18 deletions(-) create mode 100644 ui/src/types/kapacitor.tsx diff --git a/ui/src/types/index.tsx b/ui/src/types/index.tsx index a1013345f1..618e7410e9 100644 --- a/ui/src/types/index.tsx +++ b/ui/src/types/index.tsx @@ -1,4 +1,5 @@ -import {Query} from './query' -import {Source, Kapacitor} from './sources' +import { Kapacitor, AlertRule } from "./kapacitor" +import { Query, QueryConfig } from "./query" +import { Source } from "./sources" -export {Query, Source, Kapacitor} +export { Kapacitor, AlertRule, Query, QueryConfig, Source } diff --git a/ui/src/types/kapacitor.tsx b/ui/src/types/kapacitor.tsx new file mode 100644 index 0000000000..f97fde7c4d --- /dev/null +++ b/ui/src/types/kapacitor.tsx @@ -0,0 +1,187 @@ +import { QueryConfig } from "./" + +export interface Kapacitor { + id?: string + url: string + name: string + username?: string + password?: string + active: boolean + links: { + self: string + } +} + +export interface AlertRule { + id?: string + tickscript: TICKScript + query: QueryConfig + every: string + alertNodes: AlertNodes + message: string + details: string + trigger: string + values: TriggerValues + name: string + type: string + dbrps: DBRP[] + status: string + executing: boolean + error: string + created: string + modified: string + "last-enabled"?: string +} + +type TICKScript = string + +// AlertNodes defines all possible kapacitor interactions with an alert. +type AlertNodes = { + stateChangesOnly: boolean + useFlapping: boolean + post: Post[] + tcp: TCP[] + email: Email[] + exec: Exec[] + log: Log[] + victorOps: VictorOps[] + pagerDuty: PagerDuty[] + pushover: Pushover[] + sensu: Sensu[] + slack: Slack[] + telegram: Telegram[] + hipChat: HipChat[] + alerta: Alerta[] + opsGenie: OpsGenie[] + talk: Talk[] +} + +type Headers = { + [key: string]: string +} + +// Post will POST alerts to a destination URL +type Post = { + url: string + headers: Headers +} + +// Log sends the output of the alert to a file +type Log = { + filePath: string +} + +// Alerta sends the output of the alert to an alerta service +type Alerta = { + token: string + resource: string + event: string + environment: string + group: string + value: string + origin: string + service: string[] +} + +// Exec executes a shell command on an alert +type Exec = { + command: string[] +} + +// TCP sends the alert to the address +type TCP = { + address: string +} + +// Email sends the alert to a list of email addresses +type Email = { + to: string[] +} + +// VictorOps sends alerts to the victorops.com service +type VictorOps = { + routingKey: string +} + +// PagerDuty sends alerts to the pagerduty.com service +type PagerDuty = { + serviceKey: string +} + +// HipChat sends alerts to stride.com +type HipChat = { + room: string + token: string +} + +// Sensu sends alerts to sensu or sensuapp.org +type Sensu = { + source: string + handlers: string[] +} + +// Pushover sends alerts to pushover.net +type Pushover = { + // UserKey is the User/Group key of your user (or you), viewable when logged + // into the Pushover dashboard. Often referred to as USER_KEY + // in the Pushover documentation. + userKey: string + + // Device is the users device name to send message directly to that device, + // rather than all of a user's devices (multiple device names may + // be separated by a comma) + device: string + + // Title is your message's title, otherwise your apps name is used + title: string + + // URL is a supplementary URL to show with your message + url: string + + // URLTitle is a title for your supplementary URL, otherwise just URL is shown + urlTitle: string + + // Sound is the name of one of the sounds supported by the device clients to override + // the user's default sound choice + sound: string +} + +// Slack sends alerts to a slack.com channel +type Slack = { + channel: string + username: string + iconEmoji: string +} + +// Telegram sends alerts to telegram.org +type Telegram = { + chatId: string + parseMode: string + disableWebPagePreview: boolean + disableNotification: boolean +} + +// OpsGenie sends alerts to opsgenie.com +type OpsGenie = { + teams: string[] + recipients: string[] +} + +// Talk sends alerts to Jane Talk (https://jianliao.com/site) +type Talk = {} + +// TriggerValues specifies the alerting logic for a specific trigger type +type TriggerValues = { + change?: string + period?: string + shift?: string + operator?: string + value?: string + rangeValue: string +} + +// DBRP represents a database and retention policy for a time series source +type DBRP = { + db: string + rp: string +} diff --git a/ui/src/types/query.tsx b/ui/src/types/query.tsx index 92b8115d45..356d2222a0 100644 --- a/ui/src/types/query.tsx +++ b/ui/src/types/query.tsx @@ -8,7 +8,7 @@ export interface Query { groupBy: GroupBy areTagsAccepted: boolean rawText: string | null - range?: TimeRange | null + range?: DurationRange | null source?: string fill: string status?: Status @@ -53,7 +53,28 @@ export interface Status { success?: string } -export interface TimeRange { +export interface DurationRange { lower: string upper?: string } + +interface TimeShift { + label: string + unit: string + quantity: string +} + +export interface QueryConfig { + id?: string + database: string + measurement: string + retentionPolicy: string + fields: Field[] + tags: Tags + groupBy: GroupBy + areTagsAccepted: boolean + fill?: string + rawText: string + range: DurationRange + shifts: TimeShift[] +} diff --git a/ui/src/types/sources.tsx b/ui/src/types/sources.tsx index d278d08ae5..fbde1da606 100644 --- a/ui/src/types/sources.tsx +++ b/ui/src/types/sources.tsx @@ -1,3 +1,5 @@ +import { Kapacitor } from "./" + export interface Source { id: string name: string @@ -13,7 +15,7 @@ export interface Source { metaUrl?: string } -export interface SourceLinks { +interface SourceLinks { self: string kapacitors: string proxy: string @@ -24,15 +26,3 @@ export interface SourceLinks { databases: string roles?: string } - -export interface Kapacitor { - id?: string - url: string - name: string - username?: string - password?: string - active: boolean - links: { - self: string - } -} From 207a645aa17ee168780d4a26fc119bb8d709c2bf Mon Sep 17 00:00:00 2001 From: Jared Scheib Date: Fri, 16 Mar 2018 19:23:03 -0700 Subject: [PATCH 24/48] Rename KapacitorRulesTable.js to KapacitorRulesTable.tsx --- .../{KapacitorRulesTable.js => KapacitorRulesTable.tsx} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename ui/src/kapacitor/components/{KapacitorRulesTable.js => KapacitorRulesTable.tsx} (100%) diff --git a/ui/src/kapacitor/components/KapacitorRulesTable.js b/ui/src/kapacitor/components/KapacitorRulesTable.tsx similarity index 100% rename from ui/src/kapacitor/components/KapacitorRulesTable.js rename to ui/src/kapacitor/components/KapacitorRulesTable.tsx From 13ee90db99efddf58e57db28d0d5c06082e5eed1 Mon Sep 17 00:00:00 2001 From: Jared Scheib Date: Fri, 16 Mar 2018 19:23:28 -0700 Subject: [PATCH 25/48] Convert KapacitorRulesTable to working TypeScript --- .../components/KapacitorRulesTable.tsx | 122 ++++++++++-------- 1 file changed, 66 insertions(+), 56 deletions(-) diff --git a/ui/src/kapacitor/components/KapacitorRulesTable.tsx b/ui/src/kapacitor/components/KapacitorRulesTable.tsx index 783d66218b..e6998db995 100644 --- a/ui/src/kapacitor/components/KapacitorRulesTable.tsx +++ b/ui/src/kapacitor/components/KapacitorRulesTable.tsx @@ -1,8 +1,9 @@ -import React from 'react' -import PropTypes from 'prop-types' +import React, {PureComponent, SFC, MouseEvent} from 'react' import {Link} from 'react-router' import _ from 'lodash' +import {AlertRule, Source} from 'src/types' + import ConfirmButton from 'src/shared/components/ConfirmButton' import {parseAlertNodeList} from 'src/shared/parsing/parseHandlersFromRule' import {TASKS_TABLE} from 'src/kapacitor/constants/tableSizing' @@ -15,7 +16,26 @@ const { colActions, } = TASKS_TABLE -const KapacitorRulesTable = ({rules, source, onDelete, onChangeRuleStatus}) => +interface KapacitorRulesTableProps { + rules: AlertRule[] + source: Source + onChangeRuleStatus: (rule: AlertRule) => void + onDelete: (rule: AlertRule) => void +} + +interface RuleRowProps { + rule: AlertRule + source: Source + onChangeRuleStatus: (rule: AlertRule) => void + onDelete: (rule: AlertRule) => void +} + +const KapacitorRulesTable: SFC = ({ + rules, + source, + onChangeRuleStatus, + onDelete, +}) => ( @@ -43,64 +63,54 @@ const KapacitorRulesTable = ({rules, source, onDelete, onChangeRuleStatus}) => })}
+) const handleDelete = (rule, onDelete) => onDelete(rule) -const RuleRow = ({rule, source, onDelete, onChangeRuleStatus}) => - - - - {rule.name} - - - - {rule.trigger} - - - {rule.message} - - - {parseAlertNodeList(rule)} - - -
- -
- - - - - +class RuleRow extends PureComponent { + handleClickRuleStatusEnabled(_: MouseEvent) { + return (rule: AlertRule) => this.props.onChangeRuleStatus(rule) + } -const {arrayOf, func, shape, string} = PropTypes + render() { + const {rule, source, onDelete} = this.props -KapacitorRulesTable.propTypes = { - rules: arrayOf(shape()), - onChangeRuleStatus: func, - onDelete: func, - source: shape({ - id: string.isRequired, - }).isRequired, -} - -RuleRow.propTypes = { - rule: shape(), - source: shape(), - onChangeRuleStatus: func, - onDelete: func, + return ( + + + + {rule.name} + + + + {rule.trigger} + + {rule.message} + {parseAlertNodeList(rule)} + +
+ +
+ + + + + + ) + } } export default KapacitorRulesTable From 46edda85b646050cd6da0e6b9c1cf4cf03e5133a Mon Sep 17 00:00:00 2001 From: Jared Scheib Date: Fri, 16 Mar 2018 20:49:46 -0700 Subject: [PATCH 26/48] Rename TasksTable.js to TasksTable.tsx --- ui/src/kapacitor/components/{TasksTable.js => TasksTable.tsx} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename ui/src/kapacitor/components/{TasksTable.js => TasksTable.tsx} (100%) diff --git a/ui/src/kapacitor/components/TasksTable.js b/ui/src/kapacitor/components/TasksTable.tsx similarity index 100% rename from ui/src/kapacitor/components/TasksTable.js rename to ui/src/kapacitor/components/TasksTable.tsx From a70e3edc3ab7f82ef59a606f1d9ff7601ac689b9 Mon Sep 17 00:00:00 2001 From: Jared Scheib Date: Fri, 16 Mar 2018 20:55:02 -0700 Subject: [PATCH 27/48] Convert TasksTable to working TypeScript --- ui/src/kapacitor/components/TasksTable.tsx | 121 ++++++++++++--------- 1 file changed, 67 insertions(+), 54 deletions(-) diff --git a/ui/src/kapacitor/components/TasksTable.tsx b/ui/src/kapacitor/components/TasksTable.tsx index ca9e5b9113..190e688056 100644 --- a/ui/src/kapacitor/components/TasksTable.tsx +++ b/ui/src/kapacitor/components/TasksTable.tsx @@ -1,14 +1,33 @@ -import React from 'react' -import PropTypes from 'prop-types' +import React, {PureComponent, SFC, MouseEvent} from 'react' import {Link} from 'react-router' import _ from 'lodash' +import {AlertRule, Source} from 'src/types' + import ConfirmButton from 'src/shared/components/ConfirmButton' import {TASKS_TABLE} from 'src/kapacitor/constants/tableSizing' - const {colName, colType, colEnabled, colActions} = TASKS_TABLE -const TasksTable = ({tasks, source, onDelete, onChangeRuleStatus}) => +interface TasksTableProps { + tasks: AlertRule[] + source: Source + onChangeRuleStatus: (rule: AlertRule) => void + onDelete: (rule: AlertRule) => void +} + +interface TaskRowProps { + task: AlertRule + source: Source + onChangeRuleStatus: (rule: AlertRule) => void + onDelete: (rule: AlertRule) => void +} + +const TasksTable: SFC = ({ + tasks, + source, + onDelete, + onChangeRuleStatus, +}) => ( @@ -34,61 +53,55 @@ const TasksTable = ({tasks, source, onDelete, onChangeRuleStatus}) => })}
+) const handleDelete = (task, onDelete) => onDelete(task) -const TaskRow = ({task, source, onDelete, onChangeRuleStatus}) => - - - - {task.name} - - - - {task.type} - - -
- -
- - - - - +class TaskRow extends PureComponent { + handleClickRuleStatusEnabled(_: MouseEvent) { + return (rule: AlertRule) => this.props.onChangeRuleStatus(rule) + } -const {arrayOf, func, shape, string} = PropTypes + render() { + const {task, source, onDelete} = this.props -TasksTable.propTypes = { - tasks: arrayOf(shape()), - onChangeRuleStatus: func, - onDelete: func, - source: shape({ - id: string.isRequired, - }).isRequired, -} - -TaskRow.propTypes = { - task: shape(), - source: shape(), - onChangeRuleStatus: func, - onDelete: func, + return ( + + + + {task.name} + + + + {task.type} + + +
+ +
+ + + + + + ) + } } export default TasksTable From 90fe7ecf209812289c07337637ebbc15507ac053 Mon Sep 17 00:00:00 2001 From: Jared Scheib Date: Fri, 16 Mar 2018 20:59:44 -0700 Subject: [PATCH 28/48] Update changelog & prettier --- CHANGELOG.md | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 57319d12f9..74db8e9343 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,21 +5,24 @@ ### UI Improvements ### Bug Fixes + 1. [#2911](https://github.com/influxdata/chronograf/pull/2911): Fix Heroku OAuth 1. [#2953](https://github.com/influxdata/chronograf/pull/2953): Fix error reporting in DataExplorer 1. [#2947](https://github.com/influxdata/chronograf/pull/2947): Fix Okta oauth2 provider support 1. [#2866](https://github.com/influxdata/chronograf/pull/2866): Change hover text on delete mappings confirmation button to 'Delete' 1. [#2919](https://github.com/influxdata/chronograf/pull/2919): Automatically add graph type 'line' to any graph missing a type +1. [#3006](https://github.com/influxdata/chronograf/pull/3006): Fix Kapacitor Rules task enabled checkboxes to only toggle exactly as clicked ## v1.4.2.3 [2018-03-08] ## v1.4.2.2 [2018-03-07] -### Bug Fixes -1. [#2866](https://github.com/influxdata/chronograf/pull/2866): Change hover text on delete mappings confirmation button to 'Delete' -1. [#2911](https://github.com/influxdata/chronograf/pull/2911): Fix Heroku OAuth -1. [#2859](https://github.com/influxdata/chronograf/pull/2859): Enable Mappings save button when valid -1. [#2933](https://github.com/influxdata/chronograf/pull/2933): Include url in Kapacitor connection creation requests +### Bug Fixes + +1. [#2866](https://github.com/influxdata/chronograf/pull/2866): Change hover text on delete mappings confirmation button to 'Delete' +1. [#2911](https://github.com/influxdata/chronograf/pull/2911): Fix Heroku OAuth +1. [#2859](https://github.com/influxdata/chronograf/pull/2859): Enable Mappings save button when valid +1. [#2933](https://github.com/influxdata/chronograf/pull/2933): Include url in Kapacitor connection creation requests ## v1.4.2.1 [2018-02-28] From 0c382010068daa7028e9a4ce5cbc7412615bf2e4 Mon Sep 17 00:00:00 2001 From: Jared Scheib Date: Mon, 19 Mar 2018 16:29:21 -0700 Subject: [PATCH 29/48] Fix ui handlers & state sync for task enabled checkboxes Refactor toggle checkbox & delete handlers to typed class instance methods in KapacitorRulesTable & TasksTable, and to use traditional, testable JavaScript syntax. Remove curry in KapacitorRulesPage component methods to successfully toggle & delete, in accordance with above refactor. --- .../components/KapacitorRulesTable.tsx | 31 +++++++++++++------ ui/src/kapacitor/components/TasksTable.tsx | 25 ++++++++++----- .../containers/KapacitorRulesPage.js | 5 +-- 3 files changed, 42 insertions(+), 19 deletions(-) diff --git a/ui/src/kapacitor/components/KapacitorRulesTable.tsx b/ui/src/kapacitor/components/KapacitorRulesTable.tsx index e6998db995..02ee526eee 100644 --- a/ui/src/kapacitor/components/KapacitorRulesTable.tsx +++ b/ui/src/kapacitor/components/KapacitorRulesTable.tsx @@ -1,4 +1,4 @@ -import React, {PureComponent, SFC, MouseEvent} from 'react' +import React, {PureComponent, SFC, ChangeEvent} from 'react' import {Link} from 'react-router' import _ from 'lodash' @@ -65,15 +65,28 @@ const KapacitorRulesTable: SFC = ({ ) -const handleDelete = (rule, onDelete) => onDelete(rule) - class RuleRow extends PureComponent { - handleClickRuleStatusEnabled(_: MouseEvent) { - return (rule: AlertRule) => this.props.onChangeRuleStatus(rule) + constructor(props) { + super(props) + + this.handleClickRuleStatusEnabled = this.handleClickRuleStatusEnabled.bind(this) + this.handleDelete = this.handleDelete.bind(this) + } + + handleClickRuleStatusEnabled(rule: AlertRule) { + return (_: ChangeEvent) => { + this.props.onChangeRuleStatus(rule) + } + } + + handleDelete(rule: AlertRule) { + return () => { + this.props.onDelete(rule) + } } render() { - const {rule, source, onDelete} = this.props + const {rule, source} = this.props return ( @@ -93,8 +106,8 @@ class RuleRow extends PureComponent { id={`kapacitor-rule-row-task-enabled ${rule.id}`} className="form-control-static" type="checkbox" - defaultChecked={rule.status === 'enabled'} - onClick={this.handleClickRuleStatusEnabled} + checked={rule.status === 'enabled'} + onChange={this.handleClickRuleStatusEnabled(rule)} />