Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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() {
Expand Down
46 changes: 39 additions & 7 deletions src/sentry/static/sentry/app/views/groupActivity/index.jsx
Original file line number Diff line number Diff line change
@@ -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;
Expand Down Expand Up @@ -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');
Expand All @@ -114,7 +146,7 @@ const GroupActivity = React.createClass({

if (item.type === 'note') {
return (
<NoteContainer group={group} item={item} key={itemIdx} author={author} />
<NoteContainer group={group} item={item} key={itemIdx} author={author} onDelete={this.onNoteDelete} />
);
} else {
return (
Expand Down
66 changes: 66 additions & 0 deletions tests/js/spec/views/groupActivity/index.spec.jsx
Original file line number Diff line number Diff line change
@@ -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(<GroupActivity group={{id: '1337', activity: []}}/>, {
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(<GroupActivity group={{id: '1337', activity: []}}/>, {
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');
});
});
});