From 365940716022c52324bf24f7a8a439d9a5d30e5d Mon Sep 17 00:00:00 2001 From: Mike Stone Date: Tue, 17 Jan 2017 16:44:00 -0500 Subject: [PATCH] Filters hosts by custom label (#978) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Filters hosts by custom label * display singular “Host” when host count is 1 --- .../packs/PacksList/PacksList.tests.jsx | 13 +++++-- .../hosts/ManageHostsPage/ManageHostsPage.jsx | 24 +++++------- .../ManageHostsPage/ManageHostsPage.tests.jsx | 17 +++++++++ .../pages/hosts/ManageHostsPage/helpers.js | 24 ++++++++++++ .../hosts/ManageHostsPage/helpers.tests.js | 37 +++++++++++++++++++ frontend/test/stubs.js | 21 +++++++++++ 6 files changed, 119 insertions(+), 17 deletions(-) create mode 100644 frontend/pages/hosts/ManageHostsPage/helpers.js create mode 100644 frontend/pages/hosts/ManageHostsPage/helpers.tests.js diff --git a/frontend/components/packs/PacksList/PacksList.tests.jsx b/frontend/components/packs/PacksList/PacksList.tests.jsx index 6db57a5b49..d59b6960b0 100644 --- a/frontend/components/packs/PacksList/PacksList.tests.jsx +++ b/frontend/components/packs/PacksList/PacksList.tests.jsx @@ -1,6 +1,7 @@ import React from 'react'; import expect, { createSpy, restoreSpies } from 'expect'; import { mount } from 'enzyme'; +import { noop } from 'lodash'; import PacksList from 'components/packs/PacksList'; import { packStub } from 'test/stubs'; @@ -8,13 +9,19 @@ import { packStub } from 'test/stubs'; describe('PacksList - component', () => { afterEach(restoreSpies); + const props = { + onCheckAllPacks: noop, + onCheckPack: noop, + onSelectPack: noop, + }; + it('renders', () => { - expect(mount().length).toEqual(1); + expect(mount().length).toEqual(1); }); it('calls the onCheckAllPacks prop when select all packs checkbox is checked', () => { const spy = createSpy(); - const component = mount(); + const component = mount(); component.find({ name: 'select-all-packs' }).simulate('change'); @@ -23,7 +30,7 @@ describe('PacksList - component', () => { it('calls the onCheckPack prop when a pack checkbox is checked', () => { const spy = createSpy(); - const component = mount(); + const component = mount(); const packCheckbox = component.find({ name: `select-pack-${packStub.id}` }); packCheckbox.simulate('change'); diff --git a/frontend/pages/hosts/ManageHostsPage/ManageHostsPage.jsx b/frontend/pages/hosts/ManageHostsPage/ManageHostsPage.jsx index ada828861a..b3a37c4776 100644 --- a/frontend/pages/hosts/ManageHostsPage/ManageHostsPage.jsx +++ b/frontend/pages/hosts/ManageHostsPage/ManageHostsPage.jsx @@ -2,10 +2,11 @@ import React, { Component, PropTypes } from 'react'; import AceEditor from 'react-ace'; import { connect } from 'react-redux'; import { push } from 'react-router-redux'; -import { filter, orderBy, sortBy } from 'lodash'; +import { orderBy, sortBy } from 'lodash'; import entityGetter from 'redux/utilities/entityGetter'; import { getStatusLabelCounts, setDisplay } from 'redux/nodes/components/ManageHostsPage/actions'; +import helpers from 'pages/hosts/ManageHostsPage/helpers'; import hostActions from 'redux/nodes/entities/hosts/actions'; import labelActions from 'redux/nodes/entities/labels/actions'; import labelInterface from 'interfaces/label'; @@ -137,17 +138,9 @@ export class ManageHostsPage extends Component { } filterHosts = () => { - const { hosts: allHosts, selectedLabel } = this.props; + const { hosts, selectedLabel } = this.props; - // TODO: Filter custom labels by their host_ids attribute - if (!selectedLabel || selectedLabel.type === 'custom' || selectedLabel.type === 'all') { - return allHosts; - } - - const { type } = selectedLabel; - const filterObject = type === 'status' ? { status: selectedLabel.slug } : { [type]: selectedLabel[type] }; - - return filter(allHosts, filterObject); + return helpers.filterHosts(hosts, selectedLabel); } sortHosts = (hosts) => { @@ -196,13 +189,13 @@ export class ManageHostsPage extends Component { renderHeader = () => { const { renderIcon, renderQuery } = this; - const { display, isAddLabel, selectedLabel } = this.props; + const { display, isAddLabel, selectedLabel, statusLabels } = this.props; if (!selectedLabel || isAddLabel) { return false; } - const { count, description, display_text: displayText } = selectedLabel; + const { count, description, display_text: displayText, slug, type } = selectedLabel; const { onToggleDisplay } = this; const buttonOptions = { rightIcon: 'grid-select', @@ -211,6 +204,9 @@ export class ManageHostsPage extends Component { leftText: 'List', }; + const hostCount = type === 'status' ? statusLabels[`${slug}_count`] : count; + const hostsTotalDisplay = hostCount === 1 ? '1 Host Total' : `${hostCount} Hosts Total`; + return (

@@ -228,7 +224,7 @@ export class ManageHostsPage extends Component { }
-

{count} Hosts Total

+

{hostsTotalDisplay}

{ hosts: [], labels: [], selectedOsqueryTable: stubbedOsqueryTable, + statusLabels: {}, }; beforeEach(() => { @@ -70,6 +71,22 @@ describe('ManageHostsPage - component', () => { }); }); + describe('header', () => { + it('displays "1 Host Total" when there is 1 host', () => { + const oneHostLabel = { ...allHostsLabel, count: 1 }; + const page = mount(); + + expect(page.text()).toInclude('1 Host Total'); + }); + + it('displays "#{count} Hosts Total" when there are more than 1 host', () => { + const oneHostLabel = { ...allHostsLabel, count: 2 }; + const page = mount(); + + expect(page.text()).toInclude('2 Hosts Total'); + }); + }); + describe('host rendering', () => { it('renders hosts as HostDetails by default', () => { const page = mount(); diff --git a/frontend/pages/hosts/ManageHostsPage/helpers.js b/frontend/pages/hosts/ManageHostsPage/helpers.js new file mode 100644 index 0000000000..c8c7ba27b4 --- /dev/null +++ b/frontend/pages/hosts/ManageHostsPage/helpers.js @@ -0,0 +1,24 @@ +import { filter, includes } from 'lodash'; + +const filterHosts = (hosts, label) => { + if (!label) { + return hosts; + } + + const { host_ids: hostIDs, platform, slug, type } = label; + + switch (type) { + case 'all': + return hosts; + case 'status': + return filter(hosts, { status: slug }); + case 'platform': + return filter(hosts, { platform }); + case 'custom': + return filter(hosts, h => includes(hostIDs, h.id)); + default: + return hosts; + } +}; + +export default { filterHosts }; diff --git a/frontend/pages/hosts/ManageHostsPage/helpers.tests.js b/frontend/pages/hosts/ManageHostsPage/helpers.tests.js new file mode 100644 index 0000000000..b218e190d3 --- /dev/null +++ b/frontend/pages/hosts/ManageHostsPage/helpers.tests.js @@ -0,0 +1,37 @@ +import expect from 'expect'; + +import helpers from 'pages/hosts/ManageHostsPage/helpers'; +import { hostStub, labelStub } from 'test/stubs'; + +const macHost = { ...hostStub, id: 1, platform: 'darwin', status: 'mia' }; +const ubuntuHost = { ...hostStub, id: 2, platform: 'ubuntu', status: 'offline' }; +const windowsHost = { ...hostStub, id: 3, platform: 'windows', status: 'online' }; +const allHosts = [macHost, ubuntuHost, windowsHost]; + +describe('ManageHostsPage - helpers', () => { + describe('#filterHosts', () => { + it('filters the all hosts label', () => { + const allHostsLabel = { ...labelStub, type: 'all' }; + + expect(helpers.filterHosts(allHosts, allHostsLabel)).toEqual(allHosts); + }); + + it('filters the platform label', () => { + const platformLabel = { ...labelStub, type: 'platform', platform: 'ubuntu' }; + + expect(helpers.filterHosts(allHosts, platformLabel)).toEqual([ubuntuHost]); + }); + + it('filters the status label', () => { + const statusLabel = { ...labelStub, type: 'status', slug: 'online' }; + + expect(helpers.filterHosts(allHosts, statusLabel)).toEqual([windowsHost]); + }); + + it('filters the custom label', () => { + const customLabel = { ...labelStub, type: 'custom', host_ids: [1, 3] }; + + expect(helpers.filterHosts(allHosts, customLabel)).toEqual([macHost, windowsHost]); + }); + }); +}); diff --git a/frontend/test/stubs.js b/frontend/test/stubs.js index 4b4ecae1bc..ccb1f68010 100644 --- a/frontend/test/stubs.js +++ b/frontend/test/stubs.js @@ -91,6 +91,26 @@ export const hostStub = { display_text: '52883a0ba916', }; +export const labelStub = { + created_at: '2017-01-16T23:11:01Z', + updated_at: '2017-01-16T23:11:01Z', + deleted_at: null, + deleted: false, + id: 1, + name: 'All Hosts', + description: '', + query: 'select 1;', + platform: '', + label_type: 1, + display_text: 'All Hosts', + count: 20, + online: 20, + offline: 0, + missing_in_action: 0, + host_ids: [], + type: 'all', +}; + export const packStub = { created_at: '0001-01-01T00:00:00Z', updated_at: '0001-01-01T00:00:00Z', @@ -146,6 +166,7 @@ export default { adminUserStub, configStub, hostStub, + labelStub, packStub, queryStub, scheduledQueryStub,