diff --git a/frontend/pages/queries/QueryPage/QueryPage.jsx b/frontend/pages/queries/QueryPage/QueryPage.jsx index 586e7f5521..0a1d594315 100644 --- a/frontend/pages/queries/QueryPage/QueryPage.jsx +++ b/frontend/pages/queries/QueryPage/QueryPage.jsx @@ -36,6 +36,9 @@ export class QueryPage extends Component { }), hostIDs: PropTypes.oneOfType([PropTypes.array, PropTypes.string]), loadingQueries: PropTypes.bool.isRequired, + location: PropTypes.shape({ + pathname: PropTypes.string, + }), query: queryInterface, selectedOsqueryTable: osqueryTableInterface, selectedTargets: PropTypes.arrayOf(targetInterface), @@ -64,11 +67,19 @@ export class QueryPage extends Component { return false; } - componentWillUnmount () { - const { destroyCampaign, removeSocket } = this; + componentWillReceiveProps (nextProps) { + const nextPathname = nextProps.location.pathname; + const { pathname } = this.props.location; - removeSocket(); - destroyCampaign(); + if (nextPathname !== pathname) { + this.resetCampaignAndTargets(); + } + + return false; + } + + componentWillUnmount () { + this.resetCampaignAndTargets(); return false; } @@ -270,6 +281,17 @@ export class QueryPage extends Component { return false; } + resetCampaignAndTargets = () => { + const { destroyCampaign, removeSocket } = this; + const { dispatch } = this.props; + + destroyCampaign(); + dispatch(setSelectedTargets([])); + removeSocket(); + + return false; + } + renderResultsTable = () => { const { campaign } = this.state; const { onExportQueryResults } = this; diff --git a/frontend/pages/queries/QueryPage/QueryPage.tests.jsx b/frontend/pages/queries/QueryPage/QueryPage.tests.jsx index 5ac5b52d7d..eee13d33c3 100644 --- a/frontend/pages/queries/QueryPage/QueryPage.tests.jsx +++ b/frontend/pages/queries/QueryPage/QueryPage.tests.jsx @@ -5,7 +5,7 @@ import { mount } from 'enzyme'; import { noop } from 'lodash'; import convertToCSV from 'utilities/convert_to_csv'; -import { defaultSelectedOsqueryTable } from 'redux/nodes/components/QueryPages/actions'; +import * as queryPageActions from 'redux/nodes/components/QueryPages/actions'; import helpers from 'test/helpers'; import kolide from 'kolide'; import queryActions from 'redux/nodes/entities/queries/actions'; @@ -14,6 +14,7 @@ import { validUpdateQueryRequest } from 'test/mocks'; import { hostStub } from 'test/stubs'; const { connectedComponent, createAceSpy, fillInFormInput, reduxMockStore } = helpers; +const { defaultSelectedOsqueryTable } = queryPageActions; const locationProp = { params: {}, location: { query: {} } }; describe('QueryPage - component', () => { @@ -139,6 +140,33 @@ describe('QueryPage - component', () => { }); }); + describe('#componentWillReceiveProps', () => { + it('resets selected targets and removed the campaign when the hostname changes', () => { + const queryResult = { org_name: 'Kolide', org_url: 'https://kolide.co' }; + const campaign = { id: 1, query_results: [queryResult] }; + const props = { + dispatch: noop, + loadingQueries: false, + location: { pathname: '/queries/11' }, + selectedOsqueryTable: defaultSelectedOsqueryTable, + selectedTargets: [hostStub], + }; + const Page = mount(); + const PageNode = Page.node; + + spyOn(PageNode, 'destroyCampaign'); + spyOn(PageNode, 'removeSocket'); + spyOn(queryPageActions, 'setSelectedTargets'); + + Page.setState({ campaign }); + Page.setProps({ location: { pathname: '/queries/new' } }); + + expect(queryPageActions.setSelectedTargets).toHaveBeenCalledWith([]); + expect(PageNode.destroyCampaign).toHaveBeenCalled(); + expect(PageNode.removeSocket).toHaveBeenCalled(); + }); + }); + describe('export as csv', () => { it('exports the campaign query results in csv format', () => { const queryResult = { org_name: 'Kolide', org_url: 'https://kolide.co' };