diff --git a/src/sentry/static/sentry/app/components/activity/noteContainer.jsx b/src/sentry/static/sentry/app/components/activity/noteContainer.jsx index 303767479362da..dd60efa4a164aa 100644 --- a/src/sentry/static/sentry/app/components/activity/noteContainer.jsx +++ b/src/sentry/static/sentry/app/components/activity/noteContainer.jsx @@ -1,17 +1,9 @@ import React from 'react'; -import ApiMixin from '../../mixins/apiMixin'; -import IndicatorStore from '../../stores/indicatorStore'; -import GroupStore from '../../stores/groupStore'; import Note from './note'; import NoteInput from './noteInput'; -import {t} from '../../locale'; const NoteContainer = React.createClass({ - mixins: [ - ApiMixin - ], - getInitialState() { return { editing: false @@ -27,27 +19,7 @@ const NoteContainer = React.createClass({ }, onDelete() { - let {group, item} = this.props; - // Optimistically remove from UI - let index = GroupStore.removeActivity(group.id, item.id); - if (index === -1) { - // I dunno, the id wasn't found in the GroupStore - return; - } - - let loadingIndicator = IndicatorStore.add(t('Removing comment..')); - - this.api.request('/issues/' + group.id + '/comments/' + item.id + '/' , { - method: 'DELETE', - error: (error) => { - // TODO(mattrobenolt): Show an actual error that this failed, - // but just bring it back in place for now - GroupStore.addActivity(group.id, item, index); - }, - complete: () => { - IndicatorStore.remove(loadingIndicator); - } - }); + this.props.onDelete(this.props.item); }, render() { diff --git a/src/sentry/static/sentry/app/views/groupActivity/index.jsx b/src/sentry/static/sentry/app/views/groupActivity/index.jsx index 9a3b708c43cf51..0bc4e05245d89e 100644 --- a/src/sentry/static/sentry/app/views/groupActivity/index.jsx +++ b/src/sentry/static/sentry/app/views/groupActivity/index.jsx @@ -1,22 +1,29 @@ import React from 'react'; +import ApiMixin from '../../mixins/apiMixin'; +import GroupState from '../../mixins/groupState'; + import Duration from '../../components/duration'; import Gravatar from '../../components/gravatar'; -import GroupState from '../../mixins/groupState'; -import MemberListStore from '../../stores/memberListStore'; import TimeSince from '../../components/timeSince'; -import ConfigStore from '../../stores/configStore'; import Version from '../../components/version'; - import NoteContainer from '../../components/activity/noteContainer'; import NoteInput from '../../components/activity/noteInput'; -import {t, tn} from '../../locale'; +import ConfigStore from '../../stores/configStore'; +import GroupStore from '../../stores/groupStore'; +import IndicatorStore from '../../stores/indicatorStore'; +import MemberListStore from '../../stores/memberListStore'; + +import {t, tn} from '../../locale'; const GroupActivity = React.createClass({ // TODO(dcramer): only re-render on group/activity change - mixins: [GroupState], + mixins: [ + GroupState, + ApiMixin + ], formatActivity(author, item, params) { let data = item.data; @@ -98,6 +105,31 @@ const GroupActivity = React.createClass({ } }, + onNoteDelete(item) { + let {group} = this.props; + + // Optimistically remove from UI + let index = GroupStore.removeActivity(group.id, item.id); + if (index === -1) { + // I dunno, the id wasn't found in the GroupStore + return; + } + + let loadingIndicator = IndicatorStore.add(t('Removing comment..')); + + this.api.request('/issues/' + group.id + '/comments/' + item.id + '/' , { + method: 'DELETE', + error: (error) => { + // TODO(mattrobenolt): Show an actual error that this failed, + // but just bring it back in place for now + GroupStore.addActivity(group.id, item, index); + }, + complete: () => { + IndicatorStore.remove(loadingIndicator); + } + }); + }, + render() { let group = this.props.group; let me = ConfigStore.get('user'); @@ -114,7 +146,7 @@ const GroupActivity = React.createClass({ if (item.type === 'note') { return ( - + ); } else { return ( diff --git a/tests/js/spec/views/groupActivity/index.spec.jsx b/tests/js/spec/views/groupActivity/index.spec.jsx new file mode 100644 index 00000000000000..fcb1e1a3fdd081 --- /dev/null +++ b/tests/js/spec/views/groupActivity/index.spec.jsx @@ -0,0 +1,66 @@ +import React from 'react'; +import {shallow} from 'enzyme'; + +import GroupActivity from 'app/views/groupActivity'; +import NoteInput from 'app/components/activity/noteInput'; +import ConfigStore from 'app/stores/configStore'; +import GroupStore from 'app/stores/groupStore'; + +describe('GroupActivity', function() { + beforeEach(function() { + this.sandbox = sinon.sandbox.create(); + + this.sandbox.stub(ConfigStore, 'get').withArgs('user').returns({}); + }); + + afterEach(function () { + this.sandbox.restore(); + }); + + it('renders a NoteInput', function () { + let wrapper = shallow(, { + context: { + group: {id: '1337'}, + project: {id: 'foo'}, + team: {id: '1'}, + organization: {id:'bar'} + } + }); + expect(wrapper.find(NoteInput)).to.have.length(1); + }); + + describe('onNoteDelete()', function () { + beforeEach(function () { + this.instance = shallow(, { + context: { + group: {id: '1337'}, + project: {id: 'foo'}, + team: {id: '1'}, + organization: {id:'bar'} + } + }).instance(); + }); + + it('should do nothing if not present in GroupStore', function () { + let instance = this.instance; + + this.sandbox.stub(GroupStore, 'removeActivity').returns(-1); // not found + let request = this.sandbox.stub(instance.api, 'request'); + + instance.onNoteDelete({id: 1}); + expect(request.calledOnce).to.not.be.ok; + }); + + it('should remove remove the item from the GroupStore make a DELETE API request', function () { + let instance = this.instance; + + this.sandbox.stub(GroupStore, 'removeActivity').returns(1); + + let request = this.sandbox.stub(instance.api, 'request'); + instance.onNoteDelete({id: 1}); + expect(request.calledOnce).to.be.ok; + expect(request.getCall(0).args[0]).to.equal('/issues/1337/comments/1/'); + expect(request.getCall(0).args[1]).to.have.property('method', 'DELETE'); + }); + }); +});