Skip to content
11 changes: 11 additions & 0 deletions entry_types/scrolled/config/locales/de.yml
Original file line number Diff line number Diff line change
Expand Up @@ -1926,6 +1926,17 @@ de:
review:
add_comment: Kommentar hinzufügen
cancel_add_comment: Abbrechen
comment_toolbar: Kommentare
filter:
label: Kommentare filtern
unresolved: Ungelöst
all: Alle
previous_comment: Vorheriger Kommentar
next_comment: Nächster Kommentar
comment_count:
zero: Keine Kommentare
one: 1 Kommentar
other: '%{count} Kommentare'
select_content_element: Zum Kommentieren auswählen
select_section: Abschnitt zum Kommentieren auswählen
select_text_to_comment: Text zum Kommentieren auswählen
Expand Down
11 changes: 11 additions & 0 deletions entry_types/scrolled/config/locales/en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -1755,6 +1755,17 @@ en:
review:
add_comment: Add comment
cancel_add_comment: Cancel
comment_toolbar: Comments
filter:
label: Filter comments
unresolved: Unresolved
all: All
previous_comment: Previous comment
next_comment: Next comment
comment_count:
zero: No comments
one: 1 comment
other: '%{count} comments'
select_content_element: Select to comment
select_section: Select section to comment
select_text_to_comment: Select text to comment
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -129,48 +129,4 @@ describe('contentElements/textBlock/editor', () => {
});
});

describe('#compareRanges', () => {
function range(anchor, focus) {
return {
anchor: {path: [anchor[0], anchor[1]], offset: anchor[2]},
focus: {path: [focus[0], focus[1]], offset: focus[2]}
};
}

it('orders ranges by start block', () => {
const earlier = range([0, 0, 0], [0, 0, 5]);
const later = range([1, 0, 0], [1, 0, 5]);

expect(type.compareRanges(earlier, later)).toBeLessThan(0);
expect(type.compareRanges(later, earlier)).toBeGreaterThan(0);
});

it('orders ranges within the same block by offset', () => {
const earlier = range([0, 0, 2], [0, 0, 4]);
const later = range([0, 0, 6], [0, 0, 8]);

expect(type.compareRanges(earlier, later)).toBeLessThan(0);
});

it('uses the smaller of anchor and focus as the start point', () => {
const reversed = range([0, 0, 8], [0, 0, 2]);
const forward = range([0, 0, 5], [0, 0, 6]);

expect(type.compareRanges(reversed, forward)).toBeLessThan(0);
});

it('returns 0 for equal ranges', () => {
const r = range([0, 0, 0], [0, 0, 5]);

expect(type.compareRanges(r, r)).toBe(0);
});

it('sorts range-less subjects last', () => {
const r = range([0, 0, 0], [0, 0, 5]);

expect(type.compareRanges(undefined, r)).toBeGreaterThan(0);
expect(type.compareRanges(r, undefined)).toBeLessThan(0);
expect(type.compareRanges(undefined, undefined)).toBe(0);
});
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import 'contentElements/textBlock/review';
import {review} from 'review';

describe('contentElements/textBlock/review', () => {
const compareRanges = review.contentElementTypes.findCompareRanges('textBlock');

function range(anchor, focus) {
return {
anchor: {path: [anchor[0], anchor[1]], offset: anchor[2]},
focus: {path: [focus[0], focus[1]], offset: focus[2]}
};
}

it('orders ranges by start block', () => {
const earlier = range([0, 0, 0], [0, 0, 5]);
const later = range([1, 0, 0], [1, 0, 5]);

expect(compareRanges(earlier, later)).toBeLessThan(0);
expect(compareRanges(later, earlier)).toBeGreaterThan(0);
});

it('orders ranges within the same block by offset', () => {
const earlier = range([0, 0, 2], [0, 0, 4]);
const later = range([0, 0, 6], [0, 0, 8]);

expect(compareRanges(earlier, later)).toBeLessThan(0);
});

it('uses the smaller of anchor and focus as the start point', () => {
const reversed = range([0, 0, 8], [0, 0, 2]);
const forward = range([0, 0, 5], [0, 0, 6]);

expect(compareRanges(reversed, forward)).toBeLessThan(0);
});

it('returns 0 for equal ranges', () => {
const r = range([0, 0, 0], [0, 0, 5]);

expect(compareRanges(r, r)).toBe(0);
});

it('sorts range-less subjects last', () => {
const r = range([0, 0, 0], [0, 0, 5]);

expect(compareRanges(undefined, r)).toBeGreaterThan(0);
expect(compareRanges(r, undefined)).toBeLessThan(0);
expect(compareRanges(undefined, undefined)).toBe(0);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import userEvent from '@testing-library/user-event';
import {act} from '@testing-library/react';

import {editor} from 'pageflow-scrolled/editor';
import {review} from 'pageflow-scrolled/review';

import {EntryCommentsView} from 'editor/views/EntryCommentsView';
import styles from 'editor/views/EntryCommentsView.module.css';
Expand All @@ -14,7 +15,7 @@ describe('EntryCommentsView', () => {
const {createEntry} = useEditorGlobals();

beforeAll(() => {
editor.contentElementTypes.register('fixture', {
review.contentElementTypes.register('fixture', {
compareRanges: (a, b) => (a?.start ?? 0) - (b?.start ?? 0)
});
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import '@testing-library/jest-dom/extend-expect';
import userEvent from '@testing-library/user-event';

import {editor} from 'pageflow-scrolled/editor';
import {review} from 'pageflow-scrolled/review';
import {SelectionCommentsView} from 'editor/views/SelectionCommentsView';

import {factories, useFakeTranslations, renderBackboneView} from 'pageflow/testHelpers';
Expand All @@ -12,7 +13,7 @@ describe('SelectionCommentsView', () => {
const {createEntry} = useEditorGlobals();

beforeAll(() => {
editor.contentElementTypes.register('fixture', {
review.contentElementTypes.register('fixture', {
compareRanges: (a, b) => (a?.start ?? 0) - (b?.start ?? 0)
});
});
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
import '@testing-library/jest-dom/extend-expect';
import {fireEvent, within} from '@testing-library/react';

import {renderEntry, useCommentingPageObjects} from 'support/pageObjects/commenting';

describe('comment display filter', () => {
useCommentingPageObjects();

beforeEach(() => {
window.HTMLElement.prototype.scrollIntoView = jest.fn();
});

it('expands resolved comments in the popover when showing all', () => {
const entry = renderEntry({
seed: {contentElements: [{typeName: 'withTestId', configuration: {testId: 5}}]},
commenting: {
currentUser: {id: 42, name: 'Alice'},
commentThreads: [
{id: 1, subjectType: 'ContentElement', subjectId: 1, resolvedAt: '2026-01-01',
comments: [{id: 10, body: 'Resolved comment', creatorName: 'Bob', creatorId: 2}]}
]
}
});

fireEvent.click(entry.getCommentFilterButton('all'));
fireEvent.click(entry.getAllCommentBadges()[0]);

expect(entry.getByText('Resolved comment')).toBeInTheDocument();
expect(entry.queryByPlaceholderText('Add a comment...')).not.toBeInTheDocument();
});

it('shows the unresolved and total comment counts in the segments', () => {
const entry = renderEntry({
seed: {
contentElements: [
{typeName: 'withTestId', configuration: {testId: 5}},
{typeName: 'withTestId', configuration: {testId: 6}},
{typeName: 'withTestId', configuration: {testId: 7}}
]
},
commenting: {
currentUser: {id: 42, name: 'Alice'},
commentThreads: [
{id: 1, subjectType: 'ContentElement', subjectId: 1, resolvedAt: null,
comments: [{id: 10, body: 'a', creatorName: 'Bob', creatorId: 2}]},
{id: 2, subjectType: 'ContentElement', subjectId: 2, resolvedAt: null,
comments: [{id: 11, body: 'b', creatorName: 'Bob', creatorId: 2}]},
{id: 3, subjectType: 'ContentElement', subjectId: 3, resolvedAt: '2026-01-01',
comments: [{id: 12, body: 'c', creatorName: 'Bob', creatorId: 2}]}
]
}
});

expect(within(entry.getCommentFilterButton('unresolved')).getByText('2'))
.toBeInTheDocument();
expect(within(entry.getCommentFilterButton('all')).getByText('3'))
.toBeInTheDocument();
});

it('shows unresolved comments with the unresolved segment active by default', () => {
const entry = renderEntryWithResolvedThread();

expect(entry.queryAllCommentBadges()).toHaveLength(0);
expect(entry.getCommentFilterButton('unresolved'))
.toHaveAttribute('aria-pressed', 'true');
expect(entry.getCommentFilterButton('all'))
.toHaveAttribute('aria-pressed', 'false');
});

it('shows resolved comments when selecting all', () => {
const entry = renderEntryWithResolvedThread();

fireEvent.click(entry.getCommentFilterButton('all'));

expect(entry.queryAllCommentBadges()).toHaveLength(1);
expect(entry.getCommentFilterButton('all'))
.toHaveAttribute('aria-pressed', 'true');
});

it('shows both resolved and unresolved comments when showing all', () => {
const entry = renderEntry({
seed: {
contentElements: [
{typeName: 'withTestId', configuration: {testId: 5}},
{typeName: 'withTestId', configuration: {testId: 6}}
]
},
commenting: {
currentUser: {id: 42, name: 'Alice'},
commentThreads: [
{id: 1, subjectType: 'ContentElement', subjectId: 1, resolvedAt: null,
comments: [{id: 10, body: 'Open', creatorName: 'Bob', creatorId: 2}]},
{id: 2, subjectType: 'ContentElement', subjectId: 2, resolvedAt: '2026-01-01',
comments: [{id: 11, body: 'Done', creatorName: 'Bob', creatorId: 2}]}
]
}
});

expect(entry.queryAllCommentBadges()).toHaveLength(1);

fireEvent.click(entry.getCommentFilterButton('all'));

expect(entry.queryAllCommentBadges()).toHaveLength(2);
});

it('hides resolved comments again when selecting unresolved', () => {
const entry = renderEntryWithResolvedThread();

fireEvent.click(entry.getCommentFilterButton('all'));
expect(entry.queryAllCommentBadges()).toHaveLength(1);

fireEvent.click(entry.getCommentFilterButton('unresolved'));

expect(entry.queryAllCommentBadges()).toHaveLength(0);
});

function renderEntryWithResolvedThread() {
return renderEntry({
seed: {
contentElements: [{typeName: 'withTestId', configuration: {testId: 5}}]
},
commenting: {
currentUser: {id: 42, name: 'Alice'},
commentThreads: [
{id: 1, subjectType: 'ContentElement', subjectId: 1, resolvedAt: '2026-01-01',
comments: [{id: 10, body: 'Done', creatorName: 'Bob', creatorId: 2}]}
]
}
});
}
});
Loading
Loading