Filters hosts by custom label (#978)

* Filters hosts by custom label

* display singular “Host” when host count is 1
This commit is contained in:
Mike Stone 2017-01-17 16:44:00 -05:00 committed by GitHub
parent 0c93c4db67
commit 3659407160
6 changed files with 119 additions and 17 deletions

View File

@ -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(<PacksList packs={[packStub]} />).length).toEqual(1);
expect(mount(<PacksList {...props} packs={[packStub]} />).length).toEqual(1);
});
it('calls the onCheckAllPacks prop when select all packs checkbox is checked', () => {
const spy = createSpy();
const component = mount(<PacksList onCheckAllPacks={spy} packs={[packStub]} />);
const component = mount(<PacksList {...props} onCheckAllPacks={spy} packs={[packStub]} />);
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(<PacksList onCheckPack={spy} packs={[packStub]} />);
const component = mount(<PacksList {...props} onCheckPack={spy} packs={[packStub]} />);
const packCheckbox = component.find({ name: `select-pack-${packStub.id}` });
packCheckbox.simulate('change');

View File

@ -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 (
<div className={`${baseClass}__header`}>
<h1 className={`${baseClass}__title`}>
@ -228,7 +224,7 @@ export class ManageHostsPage extends Component {
}
<div className={`${baseClass}__topper`}>
<p className={`${baseClass}__host-count`}>{count} Hosts Total</p>
<p className={`${baseClass}__host-count`}>{hostsTotalDisplay}</p>
<Rocker
onChange={onToggleDisplay}
options={buttonOptions}

View File

@ -47,6 +47,7 @@ describe('ManageHostsPage - component', () => {
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(<ManageHostsPage {...props} selectedLabel={oneHostLabel} />);
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(<ManageHostsPage {...props} selectedLabel={oneHostLabel} />);
expect(page.text()).toInclude('2 Hosts Total');
});
});
describe('host rendering', () => {
it('renders hosts as HostDetails by default', () => {
const page = mount(<ManageHostsPage {...props} hosts={[hostStub]} />);

View File

@ -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 };

View File

@ -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]);
});
});
});

View File

@ -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,