mirror of
https://github.com/fleetdm/fleet
synced 2026-05-24 09:28:54 +00:00
Add targets to packs (#831)
* Allow form field values to be an array * Send the server host and label ids on create * Get and display the targets in a pack * Adds target_type to labels and hosts * Allow updating a pack’s targets as well as name and description * Adds select targets dropdown to edit pack page * Adds targets to dropdown when pack is edited
This commit is contained in:
parent
c2084026d1
commit
d1a18bcb89
14 changed files with 184 additions and 50 deletions
|
|
@ -4,8 +4,9 @@ import Button from 'components/buttons/Button';
|
||||||
import Form from 'components/forms/Form';
|
import Form from 'components/forms/Form';
|
||||||
import formFieldInterface from 'interfaces/form_field';
|
import formFieldInterface from 'interfaces/form_field';
|
||||||
import InputField from 'components/forms/fields/InputField';
|
import InputField from 'components/forms/fields/InputField';
|
||||||
|
import SelectTargetsDropdown from 'components/forms/fields/SelectTargetsDropdown';
|
||||||
|
|
||||||
const fieldNames = ['description', 'name'];
|
const fieldNames = ['description', 'name', 'targets'];
|
||||||
|
|
||||||
class EditPackForm extends Component {
|
class EditPackForm extends Component {
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
|
|
@ -13,13 +14,23 @@ class EditPackForm extends Component {
|
||||||
fields: PropTypes.shape({
|
fields: PropTypes.shape({
|
||||||
description: formFieldInterface.isRequired,
|
description: formFieldInterface.isRequired,
|
||||||
name: formFieldInterface.isRequired,
|
name: formFieldInterface.isRequired,
|
||||||
|
targets: formFieldInterface.isRequired,
|
||||||
}).isRequired,
|
}).isRequired,
|
||||||
handleSubmit: PropTypes.func.isRequired,
|
handleSubmit: PropTypes.func.isRequired,
|
||||||
onCancel: PropTypes.func.isRequired,
|
onCancel: PropTypes.func.isRequired,
|
||||||
|
onFetchTargets: PropTypes.func,
|
||||||
|
targetsCount: PropTypes.number,
|
||||||
};
|
};
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
const { className, fields, handleSubmit, onCancel } = this.props;
|
const {
|
||||||
|
className,
|
||||||
|
fields,
|
||||||
|
handleSubmit,
|
||||||
|
onCancel,
|
||||||
|
onFetchTargets,
|
||||||
|
targetsCount,
|
||||||
|
} = this.props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<form className={className} onSubmit={handleSubmit}>
|
<form className={className} onSubmit={handleSubmit}>
|
||||||
|
|
@ -29,6 +40,15 @@ class EditPackForm extends Component {
|
||||||
<InputField
|
<InputField
|
||||||
{...fields.description}
|
{...fields.description}
|
||||||
/>
|
/>
|
||||||
|
<SelectTargetsDropdown
|
||||||
|
{...fields.targets}
|
||||||
|
label="select pack targets"
|
||||||
|
name="selected-pack-targets"
|
||||||
|
onFetchTargets={onFetchTargets}
|
||||||
|
onSelect={fields.targets.onChange}
|
||||||
|
selectedTargets={fields.targets.value}
|
||||||
|
targetsCount={targetsCount}
|
||||||
|
/>
|
||||||
<Button onClick={onCancel} type="button" variant="inverse">CANCEL</Button>
|
<Button onClick={onCancel} type="button" variant="inverse">CANCEL</Button>
|
||||||
<Button type="submit" variant="brand">SAVE</Button>
|
<Button type="submit" variant="brand">SAVE</Button>
|
||||||
</form>
|
</form>
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ import EditPackForm from 'components/forms/packs/EditPackForm';
|
||||||
import Icon from 'components/icons/Icon';
|
import Icon from 'components/icons/Icon';
|
||||||
import packInterface from 'interfaces/pack';
|
import packInterface from 'interfaces/pack';
|
||||||
import SelectTargetsDropdown from 'components/forms/fields/SelectTargetsDropdown';
|
import SelectTargetsDropdown from 'components/forms/fields/SelectTargetsDropdown';
|
||||||
|
import targetInterface from 'interfaces/target';
|
||||||
|
|
||||||
const baseClass = 'edit-pack-form';
|
const baseClass = 'edit-pack-form';
|
||||||
|
|
||||||
|
|
@ -18,6 +19,7 @@ class EditPackFormWrapper extends Component {
|
||||||
onEditPack: PropTypes.func.isRequired,
|
onEditPack: PropTypes.func.isRequired,
|
||||||
onFetchTargets: PropTypes.func,
|
onFetchTargets: PropTypes.func,
|
||||||
pack: packInterface.isRequired,
|
pack: packInterface.isRequired,
|
||||||
|
packTargets: PropTypes.arrayOf(targetInterface),
|
||||||
targetsCount: PropTypes.number,
|
targetsCount: PropTypes.number,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -30,6 +32,7 @@ class EditPackFormWrapper extends Component {
|
||||||
onEditPack,
|
onEditPack,
|
||||||
onFetchTargets,
|
onFetchTargets,
|
||||||
pack,
|
pack,
|
||||||
|
packTargets,
|
||||||
targetsCount,
|
targetsCount,
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
|
|
@ -37,9 +40,11 @@ class EditPackFormWrapper extends Component {
|
||||||
return (
|
return (
|
||||||
<EditPackForm
|
<EditPackForm
|
||||||
className={className}
|
className={className}
|
||||||
formData={pack}
|
formData={{ ...pack, targets: packTargets }}
|
||||||
handleSubmit={handleSubmit}
|
handleSubmit={handleSubmit}
|
||||||
onCancel={onCancelEditPack}
|
onCancel={onCancelEditPack}
|
||||||
|
onFetchTargets={onFetchTargets}
|
||||||
|
targetsCount={targetsCount}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -63,6 +68,7 @@ class EditPackFormWrapper extends Component {
|
||||||
name="selected-pack-targets"
|
name="selected-pack-targets"
|
||||||
onFetchTargets={onFetchTargets}
|
onFetchTargets={onFetchTargets}
|
||||||
onSelect={noop}
|
onSelect={noop}
|
||||||
|
selectedTargets={packTargets}
|
||||||
targetsCount={targetsCount}
|
targetsCount={targetsCount}
|
||||||
disabled
|
disabled
|
||||||
className={`${baseClass}__select-targets`}
|
className={`${baseClass}__select-targets`}
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,8 @@ export default PropTypes.shape({
|
||||||
error: PropTypes.string,
|
error: PropTypes.string,
|
||||||
name: PropTypes.string,
|
name: PropTypes.string,
|
||||||
onChange: PropTypes.func,
|
onChange: PropTypes.func,
|
||||||
value: PropTypes.oneOfType([PropTypes.bool, PropTypes.number, PropTypes.string]),
|
value: PropTypes.oneOfType(
|
||||||
|
[PropTypes.array, PropTypes.bool, PropTypes.number, PropTypes.string]
|
||||||
|
),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,5 @@
|
||||||
import { PropTypes } from 'react';
|
import { PropTypes } from 'react';
|
||||||
|
import hostInterface from 'interfaces/host';
|
||||||
|
import labelInterface from 'interfaces/label';
|
||||||
|
|
||||||
export default PropTypes.shape({
|
export default PropTypes.oneOfType([hostInterface, labelInterface]);
|
||||||
id: PropTypes.number,
|
|
||||||
label: PropTypes.string,
|
|
||||||
name: PropTypes.string,
|
|
||||||
target_type: PropTypes.string,
|
|
||||||
});
|
|
||||||
|
|
|
||||||
|
|
@ -47,11 +47,15 @@ export const formatConfigDataForServer = (config) => {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export const formatSelectedTargetsForApi = (selectedTargets) => {
|
export const formatSelectedTargetsForApi = (selectedTargets, appendID = false) => {
|
||||||
const targets = selectedTargets || [];
|
const targets = selectedTargets || [];
|
||||||
const hosts = flatMap(targets, filterTarget('hosts'));
|
const hosts = flatMap(targets, filterTarget('hosts'));
|
||||||
const labels = flatMap(targets, filterTarget('labels'));
|
const labels = flatMap(targets, filterTarget('labels'));
|
||||||
|
|
||||||
|
if (appendID) {
|
||||||
|
return { host_ids: hosts, label_ids: labels };
|
||||||
|
}
|
||||||
|
|
||||||
return { hosts, labels };
|
return { hosts, labels };
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -53,6 +53,15 @@ describe('Kolide API - helpers', () => {
|
||||||
labels: [1, 2],
|
labels: [1, 2],
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('appends `_id` when appendID is specified', () => {
|
||||||
|
const targets = [host1, host2, label1, label2];
|
||||||
|
|
||||||
|
expect(formatSelectedTargetsForApi(targets, true)).toEqual({
|
||||||
|
host_ids: [6, 5],
|
||||||
|
label_ids: [1, 2],
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('#setupData', () => {
|
describe('#setupData', () => {
|
||||||
|
|
|
||||||
|
|
@ -32,10 +32,11 @@ class Kolide extends Base {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
createPack = ({ name, description }) => {
|
createPack = ({ name, description, targets }) => {
|
||||||
const { PACKS } = endpoints;
|
const { PACKS } = endpoints;
|
||||||
|
const packTargets = helpers.formatSelectedTargetsForApi(targets, true);
|
||||||
|
|
||||||
return this.authenticatedPost(this.endpoint(PACKS), JSON.stringify({ description, name }))
|
return this.authenticatedPost(this.endpoint(PACKS), JSON.stringify({ description, name, ...packTargets }))
|
||||||
.then((response) => { return response.pack; });
|
.then((response) => { return response.pack; });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -121,7 +122,7 @@ class Kolide extends Base {
|
||||||
const { HOSTS } = endpoints;
|
const { HOSTS } = endpoints;
|
||||||
|
|
||||||
return this.authenticatedGet(this.endpoint(HOSTS))
|
return this.authenticatedGet(this.endpoint(HOSTS))
|
||||||
.then((response) => { return response.hosts; });
|
.then(response => response.hosts);
|
||||||
}
|
}
|
||||||
|
|
||||||
getLabelHosts = (labelID) => {
|
getLabelHosts = (labelID) => {
|
||||||
|
|
@ -358,11 +359,12 @@ class Kolide extends Base {
|
||||||
return this.authenticatedPatch(this.endpoint(CONFIG), JSON.stringify(configData));
|
return this.authenticatedPatch(this.endpoint(CONFIG), JSON.stringify(configData));
|
||||||
}
|
}
|
||||||
|
|
||||||
updatePack = ({ id: packID }, updateParams) => {
|
updatePack = (pack, { description, name, targets }) => {
|
||||||
const { PACKS } = endpoints;
|
const { PACKS } = endpoints;
|
||||||
const updatePackEndpoint = `${this.baseURL}${PACKS}/${packID}`;
|
const updatePackEndpoint = `${this.baseURL}${PACKS}/${pack.id}`;
|
||||||
|
const packTargets = helpers.formatSelectedTargetsForApi(targets, true);
|
||||||
|
|
||||||
return this.authenticatedPatch(updatePackEndpoint, JSON.stringify(updateParams))
|
return this.authenticatedPatch(updatePackEndpoint, JSON.stringify({ description, name, ...packTargets }))
|
||||||
.then((response) => { return response.pack; });
|
.then((response) => { return response.pack; });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ import nock from 'nock';
|
||||||
import Kolide from 'kolide';
|
import Kolide from 'kolide';
|
||||||
import helpers from 'kolide/helpers';
|
import helpers from 'kolide/helpers';
|
||||||
import mocks from 'test/mocks';
|
import mocks from 'test/mocks';
|
||||||
import { queryStub, userStub } from 'test/stubs';
|
import { hostStub, queryStub, userStub } from 'test/stubs';
|
||||||
|
|
||||||
const {
|
const {
|
||||||
invalidForgotPasswordRequest,
|
invalidForgotPasswordRequest,
|
||||||
|
|
@ -80,7 +80,7 @@ describe('Kolide - API client', () => {
|
||||||
|
|
||||||
it('#createPack', (done) => {
|
it('#createPack', (done) => {
|
||||||
const { description, name } = pack;
|
const { description, name } = pack;
|
||||||
const params = { description, name };
|
const params = { description, name, host_ids: [], label_ids: [] };
|
||||||
const request = validCreatePackRequest(bearerToken, params);
|
const request = validCreatePackRequest(bearerToken, params);
|
||||||
|
|
||||||
Kolide.setBearerToken(bearerToken);
|
Kolide.setBearerToken(bearerToken);
|
||||||
|
|
@ -105,7 +105,9 @@ describe('Kolide - API client', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('#updatePack', (done) => {
|
it('#updatePack', (done) => {
|
||||||
const updatePackParams = { name: 'New Pack Name' };
|
const targets = [hostStub];
|
||||||
|
const packTargets = helpers.formatSelectedTargetsForApi(targets, true);
|
||||||
|
const updatePackParams = { name: 'New Pack Name', ...packTargets };
|
||||||
const request = validUpdatePackRequest(bearerToken, pack, updatePackParams);
|
const request = validUpdatePackRequest(bearerToken, pack, updatePackParams);
|
||||||
|
|
||||||
Kolide.setBearerToken(bearerToken);
|
Kolide.setBearerToken(bearerToken);
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,13 @@
|
||||||
import React, { Component, PropTypes } from 'react';
|
import React, { Component, PropTypes } from 'react';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { noop, size, find } from 'lodash';
|
import { filter, includes, isEqual, noop, size, find } from 'lodash';
|
||||||
import { push } from 'react-router-redux';
|
import { push } from 'react-router-redux';
|
||||||
|
|
||||||
import EditPackFormWrapper from 'components/packs/EditPackFormWrapper';
|
import EditPackFormWrapper from 'components/packs/EditPackFormWrapper';
|
||||||
|
import hostActions from 'redux/nodes/entities/hosts/actions';
|
||||||
|
import hostInterface from 'interfaces/host';
|
||||||
|
import labelActions from 'redux/nodes/entities/labels/actions';
|
||||||
|
import labelInterface from 'interfaces/label';
|
||||||
import packActions from 'redux/nodes/entities/packs/actions';
|
import packActions from 'redux/nodes/entities/packs/actions';
|
||||||
import ScheduleQuerySidePanel from 'components/side_panels/ScheduleQuerySidePanel';
|
import ScheduleQuerySidePanel from 'components/side_panels/ScheduleQuerySidePanel';
|
||||||
import packInterface from 'interfaces/pack';
|
import packInterface from 'interfaces/pack';
|
||||||
|
|
@ -24,7 +28,9 @@ export class EditPackPage extends Component {
|
||||||
isLoadingPack: PropTypes.bool,
|
isLoadingPack: PropTypes.bool,
|
||||||
isLoadingScheduledQueries: PropTypes.bool,
|
isLoadingScheduledQueries: PropTypes.bool,
|
||||||
pack: packInterface,
|
pack: packInterface,
|
||||||
|
packHosts: PropTypes.arrayOf(hostInterface),
|
||||||
packID: PropTypes.string,
|
packID: PropTypes.string,
|
||||||
|
packLabels: PropTypes.arrayOf(labelInterface),
|
||||||
scheduledQueries: PropTypes.arrayOf(queryInterface),
|
scheduledQueries: PropTypes.arrayOf(queryInterface),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -41,7 +47,16 @@ export class EditPackPage extends Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount () {
|
componentDidMount () {
|
||||||
const { allQueries, dispatch, isLoadingPack, pack, packID, scheduledQueries } = this.props;
|
const {
|
||||||
|
allQueries,
|
||||||
|
dispatch,
|
||||||
|
isLoadingPack,
|
||||||
|
pack,
|
||||||
|
packHosts,
|
||||||
|
packID,
|
||||||
|
packLabels,
|
||||||
|
scheduledQueries,
|
||||||
|
} = this.props;
|
||||||
const { load } = packActions;
|
const { load } = packActions;
|
||||||
const { loadAll } = queryActions;
|
const { loadAll } = queryActions;
|
||||||
|
|
||||||
|
|
@ -49,6 +64,16 @@ export class EditPackPage extends Component {
|
||||||
dispatch(load(packID));
|
dispatch(load(packID));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (pack) {
|
||||||
|
if (!packHosts || packHosts.length !== pack.host_ids.length) {
|
||||||
|
dispatch(hostActions.loadAll());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!packLabels || packLabels.length !== pack.label_ids.length) {
|
||||||
|
dispatch(labelActions.loadAll());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!size(scheduledQueries)) {
|
if (!size(scheduledQueries)) {
|
||||||
dispatch(scheduledQueryActions.loadAll({ id: packID }));
|
dispatch(scheduledQueryActions.loadAll({ id: packID }));
|
||||||
}
|
}
|
||||||
|
|
@ -60,6 +85,20 @@ export class EditPackPage extends Component {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
componentWillReceiveProps ({ dispatch, pack, packHosts, packLabels }) {
|
||||||
|
if (!isEqual(pack, this.props.pack)) {
|
||||||
|
if (!packHosts || packHosts.length !== pack.host_ids.length) {
|
||||||
|
dispatch(hostActions.loadAll());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!packLabels || packLabels.length !== pack.label_ids.length) {
|
||||||
|
dispatch(labelActions.loadAll());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
onCancelEditPack = () => {
|
onCancelEditPack = () => {
|
||||||
const { dispatch, isEdit, packID } = this.props;
|
const { dispatch, isEdit, packID } = this.props;
|
||||||
|
|
||||||
|
|
@ -97,10 +136,10 @@ export class EditPackPage extends Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
handlePackFormSubmit = (formData) => {
|
handlePackFormSubmit = (formData) => {
|
||||||
const { dispatch } = this.props;
|
const { dispatch, pack } = this.props;
|
||||||
const { update } = packActions;
|
const { update } = packActions;
|
||||||
|
|
||||||
return dispatch(update(formData));
|
return dispatch(update(pack, formData));
|
||||||
}
|
}
|
||||||
|
|
||||||
handleRemoveScheduledQueries = (scheduledQueryIDs) => {
|
handleRemoveScheduledQueries = (scheduledQueryIDs) => {
|
||||||
|
|
@ -149,7 +188,9 @@ export class EditPackPage extends Component {
|
||||||
onToggleEdit,
|
onToggleEdit,
|
||||||
} = this;
|
} = this;
|
||||||
const { targetsCount, selectedQuery } = this.state;
|
const { targetsCount, selectedQuery } = this.state;
|
||||||
const { allQueries, isEdit, isLoadingScheduledQueries, pack, scheduledQueries } = this.props;
|
const { allQueries, isEdit, isLoadingScheduledQueries, pack, packHosts, packLabels, scheduledQueries } = this.props;
|
||||||
|
|
||||||
|
const packTargets = [...packHosts, ...packLabels];
|
||||||
|
|
||||||
if (!pack || isLoadingScheduledQueries) {
|
if (!pack || isLoadingScheduledQueries) {
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -166,6 +207,7 @@ export class EditPackPage extends Component {
|
||||||
onEditPack={onToggleEdit}
|
onEditPack={onToggleEdit}
|
||||||
onFetchTargets={onFetchTargets}
|
onFetchTargets={onFetchTargets}
|
||||||
pack={pack}
|
pack={pack}
|
||||||
|
packTargets={packTargets}
|
||||||
targetsCount={targetsCount}
|
targetsCount={targetsCount}
|
||||||
/>
|
/>
|
||||||
<ScheduledQueriesListWrapper
|
<ScheduledQueriesListWrapper
|
||||||
|
|
@ -194,6 +236,12 @@ const mapStateToProps = (state, { params, route }) => {
|
||||||
const scheduledQueries = entityGetter.get('scheduled_queries').where({ pack_id: packID });
|
const scheduledQueries = entityGetter.get('scheduled_queries').where({ pack_id: packID });
|
||||||
const isLoadingScheduledQueries = state.entities.scheduled_queries.loading;
|
const isLoadingScheduledQueries = state.entities.scheduled_queries.loading;
|
||||||
const isEdit = route.path === 'edit';
|
const isEdit = route.path === 'edit';
|
||||||
|
const packHosts = pack ? filter(state.entities.hosts.data, (host) => {
|
||||||
|
return includes(pack.host_ids, host.id);
|
||||||
|
}) : [];
|
||||||
|
const packLabels = pack ? filter(state.entities.labels.data, (label) => {
|
||||||
|
return includes(pack.label_ids, label.id);
|
||||||
|
}) : [];
|
||||||
|
|
||||||
return {
|
return {
|
||||||
allQueries,
|
allQueries,
|
||||||
|
|
@ -201,7 +249,9 @@ const mapStateToProps = (state, { params, route }) => {
|
||||||
isLoadingPack,
|
isLoadingPack,
|
||||||
isLoadingScheduledQueries,
|
isLoadingScheduledQueries,
|
||||||
pack,
|
pack,
|
||||||
|
packHosts,
|
||||||
packID,
|
packID,
|
||||||
|
packLabels,
|
||||||
scheduledQueries,
|
scheduledQueries,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,8 @@ import EditPackPage from './EditPackPage';
|
||||||
describe('EditPackPage - component', () => {
|
describe('EditPackPage - component', () => {
|
||||||
const store = {
|
const store = {
|
||||||
entities: {
|
entities: {
|
||||||
|
hosts: { data: {} },
|
||||||
|
labels: { data: {} },
|
||||||
packs: {
|
packs: {
|
||||||
data: {
|
data: {
|
||||||
[packStub.id]: packStub,
|
[packStub.id]: packStub,
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,6 @@ import { connect } from 'react-redux';
|
||||||
import { noop } from 'lodash';
|
import { noop } from 'lodash';
|
||||||
import { push } from 'react-router-redux';
|
import { push } from 'react-router-redux';
|
||||||
|
|
||||||
import Kolide from 'kolide';
|
|
||||||
import packActions from 'redux/nodes/entities/packs/actions';
|
import packActions from 'redux/nodes/entities/packs/actions';
|
||||||
import PackForm from 'components/forms/packs/PackForm';
|
import PackForm from 'components/forms/packs/PackForm';
|
||||||
import PackInfoSidePanel from 'components/side_panels/PackInfoSidePanel';
|
import PackInfoSidePanel from 'components/side_panels/PackInfoSidePanel';
|
||||||
|
|
@ -47,37 +46,15 @@ export class PackComposerPage extends Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
handleSubmit = (formData) => {
|
handleSubmit = (formData) => {
|
||||||
const { create, load } = packActions;
|
const { create } = packActions;
|
||||||
const { dispatch } = this.props;
|
const { dispatch } = this.props;
|
||||||
const { visitPackPage } = this;
|
const { visitPackPage } = this;
|
||||||
|
|
||||||
return dispatch(create(formData))
|
return dispatch(create(formData))
|
||||||
.then((pack) => {
|
.then((pack) => {
|
||||||
const { id: packID } = pack;
|
const { id: packID } = pack;
|
||||||
const { targets } = formData;
|
|
||||||
|
|
||||||
if (!targets) {
|
return visitPackPage(packID);
|
||||||
return visitPackPage(packID);
|
|
||||||
}
|
|
||||||
|
|
||||||
const promises = targets.map((target) => {
|
|
||||||
const { id: targetID } = target;
|
|
||||||
|
|
||||||
if (target.target_type === 'labels') {
|
|
||||||
Kolide.addLabelToPack(packID, targetID);
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Add host to pack when API is available
|
|
||||||
return Promise.resolve();
|
|
||||||
});
|
|
||||||
|
|
||||||
return Promise.all(promises)
|
|
||||||
.then(() => {
|
|
||||||
dispatch(load(packID))
|
|
||||||
.then(() => {
|
|
||||||
return visitPackPage(packID);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,5 +7,8 @@ const { HOSTS: schema } = schemas;
|
||||||
export default reduxConfig({
|
export default reduxConfig({
|
||||||
entityName: 'hosts',
|
entityName: 'hosts',
|
||||||
loadAllFunc: Kolide.getHosts,
|
loadAllFunc: Kolide.getHosts,
|
||||||
|
parseEntityFunc: (host) => {
|
||||||
|
return { ...host, target_type: 'hosts' };
|
||||||
|
},
|
||||||
schema,
|
schema,
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -8,5 +8,8 @@ export default reduxConfig({
|
||||||
createFunc: Kolide.createLabel,
|
createFunc: Kolide.createLabel,
|
||||||
entityName: 'labels',
|
entityName: 'labels',
|
||||||
loadAllFunc: Kolide.getLabels,
|
loadAllFunc: Kolide.getLabels,
|
||||||
|
parseEntityFunc: (label) => {
|
||||||
|
return { ...label, target_type: 'labels' };
|
||||||
|
},
|
||||||
schema,
|
schema,
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,60 @@ export const configStub = {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const hostStub = {
|
||||||
|
created_at: '2017-01-10T19:18:55Z',
|
||||||
|
updated_at: '2017-01-10T20:13:52Z',
|
||||||
|
deleted_at: null,
|
||||||
|
deleted: false,
|
||||||
|
id: 1,
|
||||||
|
detail_updated_at: '2017-01-10T20:01:48Z',
|
||||||
|
seen_time: '2017-01-10T20:13:54Z',
|
||||||
|
hostname: '52883a0ba916',
|
||||||
|
uuid: 'FD87130B-09A9-683D-9095-D92CD20728CA',
|
||||||
|
platform: 'ubuntu',
|
||||||
|
osquery_version: '2.1.2',
|
||||||
|
os_version: 'Ubuntu 14.4.',
|
||||||
|
build: '',
|
||||||
|
platform_like: 'debian',
|
||||||
|
code_name: '',
|
||||||
|
uptime: 45469000000000,
|
||||||
|
memory: 2094940160,
|
||||||
|
cpu_type: '6',
|
||||||
|
cpu_subtype: '78',
|
||||||
|
cpu_brand: 'Intel(R) Core(TM) i5-6267U CPU @ 2.90GHz',
|
||||||
|
cpu_physical_cores: 2,
|
||||||
|
cpu_logical_cores: 2,
|
||||||
|
hardware_vendor: ' ',
|
||||||
|
hardware_model: 'BHYVE',
|
||||||
|
hardware_version: '1.0',
|
||||||
|
hardware_serial: 'None',
|
||||||
|
computer_name: '52883a0ba916',
|
||||||
|
primary_ip_id: 1,
|
||||||
|
network_interfaces: [
|
||||||
|
{
|
||||||
|
id: 1,
|
||||||
|
interface: 'eth0',
|
||||||
|
address: '172.19.0.8',
|
||||||
|
mask: '255.255.0.0',
|
||||||
|
broadcast: '172.19.0.8',
|
||||||
|
point_to_point: '',
|
||||||
|
mac: '02:42:ac:13:00:08',
|
||||||
|
type: 1,
|
||||||
|
mtu: 1500,
|
||||||
|
metric: 0,
|
||||||
|
ipackets: 512,
|
||||||
|
opackets: 317,
|
||||||
|
ibytes: 97231,
|
||||||
|
obytes: 43502,
|
||||||
|
ierrors: 0,
|
||||||
|
oerrors: 0,
|
||||||
|
last_change: -1,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
status: 'online',
|
||||||
|
display_text: '52883a0ba916',
|
||||||
|
};
|
||||||
|
|
||||||
export const packStub = {
|
export const packStub = {
|
||||||
created_at: '0001-01-01T00:00:00Z',
|
created_at: '0001-01-01T00:00:00Z',
|
||||||
updated_at: '0001-01-01T00:00:00Z',
|
updated_at: '0001-01-01T00:00:00Z',
|
||||||
|
|
@ -41,6 +95,8 @@ export const packStub = {
|
||||||
platform: '',
|
platform: '',
|
||||||
created_by: 1,
|
created_by: 1,
|
||||||
disabled: false,
|
disabled: false,
|
||||||
|
host_ids: [],
|
||||||
|
label_ids: [],
|
||||||
};
|
};
|
||||||
|
|
||||||
export const queryStub = {
|
export const queryStub = {
|
||||||
|
|
@ -82,6 +138,7 @@ export const userStub = {
|
||||||
export default {
|
export default {
|
||||||
adminUserStub,
|
adminUserStub,
|
||||||
configStub,
|
configStub,
|
||||||
|
hostStub,
|
||||||
packStub,
|
packStub,
|
||||||
queryStub,
|
queryStub,
|
||||||
scheduledQueryStub,
|
scheduledQueryStub,
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue