Skip to content

Commit dfd01e0

Browse files
committed
Add editor view to show content element comments
REDMINE-21261
1 parent bae44d8 commit dfd01e0

File tree

5 files changed

+135
-0
lines changed

5 files changed

+135
-0
lines changed
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
import '@testing-library/jest-dom/extend-expect';
2+
import BackboneEvents from 'backbone-events-standalone';
3+
4+
import {ContentElementCommentsView} from 'editor/views/ContentElementCommentsView';
5+
6+
import {useFakeTranslations, renderBackboneView} from 'pageflow/testHelpers';
7+
import {useEditorGlobals} from 'support';
8+
import {act, waitFor} from '@testing-library/react';
9+
10+
describe('ContentElementCommentsView', () => {
11+
const {createEntry} = useEditorGlobals();
12+
13+
useFakeTranslations({
14+
'pageflow_scrolled.review.add_comment_placeholder': 'Add a comment...',
15+
'pageflow_scrolled.review.new_topic': 'New topic',
16+
'pageflow_scrolled.review.send': 'Send'
17+
});
18+
19+
it('displays threads from session state', () => {
20+
const entry = createEntry({
21+
contentElements: [{id: 1, permaId: 10, typeName: 'textBlock'}]
22+
});
23+
entry.reviewSession = fakeReviewSession({
24+
currentUser: {id: 1},
25+
commentThreads: [{
26+
id: 1,
27+
subjectType: 'ContentElement',
28+
subjectId: 10,
29+
comments: [{id: 100, body: 'Looks good', creatorName: 'Alice'}]
30+
}]
31+
});
32+
33+
const view = new ContentElementCommentsView({
34+
entry,
35+
model: entry.contentElements.get(1),
36+
editor: {}
37+
});
38+
39+
const {getByText} = renderBackboneView(view);
40+
view.onShow();
41+
42+
expect(getByText('Looks good')).toBeInTheDocument();
43+
});
44+
45+
it('updates when session emits change:thread', async () => {
46+
const entry = createEntry({
47+
contentElements: [{id: 1, permaId: 10, typeName: 'textBlock'}]
48+
});
49+
entry.reviewSession = fakeReviewSession({
50+
currentUser: {id: 1},
51+
commentThreads: []
52+
});
53+
54+
const view = new ContentElementCommentsView({
55+
entry,
56+
model: entry.contentElements.get(1),
57+
editor: {}
58+
});
59+
60+
const {getByText} = renderBackboneView(view);
61+
act(() => view.onShow());
62+
63+
act(() => {
64+
entry.reviewSession.trigger('change:thread', {
65+
id: 1,
66+
subjectType: 'ContentElement',
67+
subjectId: 10,
68+
comments: [{id: 100, body: 'New comment', creatorName: 'Bob'}]
69+
});
70+
});
71+
72+
await waitFor(() => {
73+
expect(getByText('New comment')).toBeInTheDocument();
74+
});
75+
});
76+
});
77+
78+
function fakeReviewSession(state = null) {
79+
const session = {
80+
state,
81+
createThread: jest.fn().mockResolvedValue(),
82+
createComment: jest.fn().mockResolvedValue()
83+
};
84+
85+
Object.assign(session, BackboneEvents);
86+
return session;
87+
}

entry_types/scrolled/package/src/editor/controllers/SideBarController.js

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
import Marionette from 'backbone.marionette';
22

33
import {editor} from 'pageflow-scrolled/editor';
4+
import {BackButtonDecoratorView} from 'pageflow/editor';
45

56
import {EditChapterView} from '../views/EditChapterView';
67
import {EditSectionView} from '../views/EditSectionView';
78
import {EditSectionTransitionView} from '../views/EditSectionTransitionView';
89
import {EditSectionPaddingsView} from '../views/EditSectionPaddingsView';
910
import {EditContentElementView} from '../views/EditContentElementView';
11+
import {ContentElementCommentsView} from '../views/ContentElementCommentsView';
1012

1113
export const SideBarController = Marionette.Controller.extend({
1214
initialize: function(options) {
@@ -47,6 +49,16 @@ export const SideBarController = Marionette.Controller.extend({
4749
}));
4850
},
4951

52+
contentElementComments: function(id) {
53+
this.region.show(new BackButtonDecoratorView({
54+
view: new ContentElementCommentsView({
55+
entry: this.entry,
56+
model: this.entry.contentElements.get(id),
57+
editor
58+
})
59+
}));
60+
},
61+
5062
contentElement: function(id, tab) {
5163
this.region.show(new EditContentElementView({
5264
entry: this.entry,

entry_types/scrolled/package/src/editor/routers/SideBarRouter.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ export const SideBarRouter = Marionette.AppRouter.extend({
77
'scrolled/sections/:id/paddings?position=:position': 'sectionPaddings',
88
'scrolled/sections/:id/paddings': 'sectionPaddings',
99
'scrolled/sections/:id': 'section',
10+
'scrolled/content_elements/:id/comments': 'contentElementComments',
1011
'scrolled/content_elements/:id': 'contentElement'
1112
}
1213
});
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import React from 'react';
2+
import ReactDOM from 'react-dom';
3+
import Marionette from 'backbone.marionette';
4+
5+
import {ReviewStateProvider, ReviewMessageHandler, ThreadList} from 'pageflow-scrolled/review';
6+
7+
import styles from './ContentElementCommentsView.module.css';
8+
9+
export const ContentElementCommentsView = Marionette.ItemView.extend({
10+
template: () => `<div class="${styles.container}"></div>`,
11+
12+
onShow() {
13+
const session = this.options.entry.reviewSession;
14+
15+
this.reviewMessageHandler = ReviewMessageHandler.create({
16+
session,
17+
targetWindow: window
18+
});
19+
20+
ReactDOM.render(
21+
<ReviewStateProvider initialState={session.state}>
22+
<ThreadList subjectType="ContentElement"
23+
subjectId={this.model.get('permaId')} />
24+
</ReviewStateProvider>,
25+
this.$el.find(`.${styles.container}`)[0]
26+
);
27+
},
28+
29+
onClose() {
30+
this.reviewMessageHandler.dispose();
31+
ReactDOM.unmountComponentAtNode(this.$el.find(`.${styles.container}`)[0]);
32+
}
33+
});
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
.container {
2+
}

0 commit comments

Comments
 (0)