Skip to content

Commit 141079b

Browse files
committed
PT-3548: Create new comment threads
Added UsjReaderWriter.findNextMatchingNode Tested findNextMatchingNode
1 parent 9c2ebd8 commit 141079b

34 files changed

+6186
-4245
lines changed

assets/localization/en.json

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,13 @@
55
"%about_licenseLabel_format%": "License: {license}",
66
"%about_versionLabel_format%": "Version: {version}",
77
"%ariaLabel_opensInBrowser%": "Opens externally in a browser window",
8+
"%menuItemName_wordList%": "Word List",
9+
"%commentEditor_assignTo_label%": "Assign to",
10+
"%commentEditor_cancelButton_tooltip%": "Cancel",
11+
"%commentEditor_placeholder%": "Type your comment here...",
12+
"%commentEditor_saveButton_tooltip%": "Save comment",
13+
"%commentEditor_team%": "Team",
14+
"%commentEditor_unassigned%": "Unassigned",
815
"%data_loading_error_paratextData_auth_failure%": "Paratext Registration is not valid. Please update your registration information and try again.",
916
"%data_loading_error_paratextData_internet_disabled%": "Internet access is disabled in “Paratext Registration Information”. Please enable it and try again.",
1017
"%data_loading_error_internetAccess_disabled%": "Internet access is disabled in “Internet Settings”. Please enable it and try again.",
@@ -32,7 +39,7 @@
3239
"%history_recent%": "Recent",
3340
"%history_recentSearches_ariaLabel%": "Show Recent Searches",
3441
"%home_dialog_title%": "Home",
35-
"%insertNote%": "Insert Note",
42+
"%insertComment%": "Insert Comment",
3643
"%mainMenu_about%": "About Platform.Bible",
3744
"%mainMenu_downloadInstallResources%": "Download/Install Resources",
3845
"%mainMenu_edit%": "Edit",
@@ -60,7 +67,6 @@
6067
"%mainMenu_view%": "View",
6168
"%mainMenu_visitSupportBible%": "Visit Support.Bible",
6269
"%mainMenu_window%": "Window",
63-
"%menuItemName_wordList%": "Word List",
6470
"%product_name%": "Platform.Bible",
6571
"%product_shortName%": "Platform",
6672
"%project_full_name_missing%": "*Name Missing*",

assets/localization/es.json

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,12 @@
127127
"%about_licenseLabel_format%": "Licencia: {license}",
128128
"%about_versionLabel_format%": "Versión: {version}",
129129
"%ariaLabel_opensInBrowser%": "Se abre externamente en el navegador.",
130+
"%commentEditor_assignTo_label%": "Asignar a",
131+
"%commentEditor_cancelButton_tooltip%": "Cancelar",
132+
"%commentEditor_placeholder%": "Escribe tu comentario aquí...",
133+
"%commentEditor_saveButton_tooltip%": "Guardar comentario",
134+
"%commentEditor_team%": "Equipo",
135+
"%commentEditor_unassigned%": "Sin asignar",
130136
"%data_loading_error_paratextData_auth_failure%": "La registración de Paratext no es válida. Actualice su información de registración y vuelva a intentarlo.",
131137
"%data_loading_error_paratextData_internet_disabled%": "El acceso a Internet está deshabilitado en “Información de Registro de Paratext”. Por favor, actívelo e intente nuevamente.",
132138
"%downloadUpdateProjectTab_aria_downloadable%": "proyectos descargables",
@@ -153,7 +159,7 @@
153159
"%history_recent%": "Recientes",
154160
"%history_recentSearches_ariaLabel%": "Mostrar búsquedas recientes",
155161
"%home_dialog_title%": "Inicio",
156-
"%insertNote%": "Insertar Nota",
162+
"%insertComment%": "Insertar comentario",
157163
"%mainMenu_about%": "Acerca de Platform.Bible",
158164
"%mainMenu_downloadInstallResources%": "Descargar/instalar recursos",
159165
"%mainMenu_downloadSlashUpdateProject%": "Descargar/actualizar proyecto",

c-sharp/Projects/ParatextProjectDataProvider.cs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -323,6 +323,13 @@ public bool DeleteComment(string commentId)
323323
/// <returns>The auto-generated comment ID (format: "threadId/userName/date")</returns>
324324
public string CreateComment(Comment comment)
325325
{
326+
if (comment.SelectedText.Contains('\\'))
327+
{
328+
throw new InvalidOperationException(
329+
"Invalid selection. Selected text must be a simple word or phrase with no markers."
330+
);
331+
}
332+
326333
var scrText = LocalParatextProjects.GetParatextProject(ProjectDetails.Metadata.Id);
327334

328335
if (comment.AssignedUser != null)
@@ -661,7 +668,8 @@ public bool CanUserEditOrDeleteComment(string commentId)
661668
return false;
662669

663670
// Must be the last comment in the thread
664-
if (comment != thread.LastComment)
671+
var lastComment = thread.LastComment;
672+
if (lastComment == null || comment.Id != lastComment.Id)
665673
return false;
666674

667675
// Must be the author of the comment
@@ -673,7 +681,7 @@ public bool CanUserEditOrDeleteComment(string commentId)
673681
return false;
674682

675683
// Cannot edit/delete the first comment of a conflict note
676-
if (thread.Type == NoteType.Conflict && thread.Comments[0] == comment)
684+
if (thread.Type == NoteType.Conflict && thread.Comments[0].Id == comment.Id)
677685
return false;
678686

679687
return true;

extensions/src/legacy-comment-manager/src/comment-list.web-view.tsx

Lines changed: 43 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -10,20 +10,51 @@ import {
1010
} from 'platform-bible-react';
1111
import { useCallback, useEffect, useMemo, useState } from 'react';
1212
import { useLocalizedStrings, useProjectData, useProjectDataProvider } from '@papi/frontend/react';
13-
import { isPlatformError, LegacyCommentThread } from 'platform-bible-utils';
13+
import { isPlatformError, LegacyCommentThread, serialize } from 'platform-bible-utils';
1414

1515
const DEFAULT_LEGACY_COMMENT_THREADS: LegacyCommentThread[] = [];
1616

17+
/** Message types that can be received from the Comment List web view controller */
18+
type CommentListWebViewMessage = {
19+
method: 'scrollToThread';
20+
threadId: string;
21+
};
22+
1723
global.webViewComponent = function CommentListWebView({
1824
useWebViewScrollGroupScrRef,
1925
projectId,
2026
}: WebViewProps) {
2127
const [localizedStrings] = useLocalizedStrings(COMMENT_LIST_STRING_KEYS);
2228
const [scrRef] = useWebViewScrollGroupScrRef();
2329
const [currentUserName, setCurrentUserName] = useState<string>('');
30+
const [selectedThreadId, setSelectedThreadId] = useState<string | undefined>(undefined);
2431

2532
const commentsPdp = useProjectDataProvider('legacyCommentManager.comments', projectId);
2633

34+
// Listen for messages from the web view controller
35+
useEffect(() => {
36+
const messageListener = ({ data }: MessageEvent<CommentListWebViewMessage>) => {
37+
if (data.method === 'scrollToThread') {
38+
logger.debug(`Comment list received scrollToThread message: ${serialize(data)}`);
39+
const { threadId } = data;
40+
41+
// Find the thread element and scroll to it
42+
const threadElement = document.getElementById(threadId);
43+
if (threadElement) {
44+
setSelectedThreadId(threadId);
45+
threadElement.scrollIntoView({ behavior: 'smooth', block: 'center' });
46+
} else {
47+
logger.warn(`Could not find thread element with id: ${threadId}`);
48+
}
49+
}
50+
};
51+
52+
window.addEventListener('message', messageListener);
53+
return () => {
54+
window.removeEventListener('message', messageListener);
55+
};
56+
}, []);
57+
2758
// Fetch current user's registration data on mount
2859
useEffect(() => {
2960
let isMounted = true;
@@ -59,13 +90,13 @@ global.webViewComponent = function CommentListWebView({
5990
},
6091
],
6192
};
62-
}, [scrRef.book, scrRef.chapterNum, scrRef.verseNum]),
93+
}, [scrRef.book, scrRef.chapterNum]),
6394
DEFAULT_LEGACY_COMMENT_THREADS,
6495
);
6596

6697
const fetchAssignableUsers = useCallback(async () => {
6798
if (!commentsPdp) {
68-
logger.error('Comments PDP is not available');
99+
logger.debug('Comments PDP is not yet available for fetchAssignableUsers');
69100
return [];
70101
}
71102
return commentsPdp.findAssignableUsers();
@@ -74,7 +105,7 @@ global.webViewComponent = function CommentListWebView({
74105

75106
const fetchCanUserAddCommentToThread = useCallback(async () => {
76107
if (!commentsPdp) {
77-
logger.error('Comments PDP is not available');
108+
logger.debug('Comments PDP is not yet available for fetchCanUserAddCommentToThread');
78109
return false;
79110
}
80111
return commentsPdp.canUserAddCommentToThread();
@@ -84,7 +115,7 @@ global.webViewComponent = function CommentListWebView({
84115
const canUserAssignThreadCallback = useCallback(
85116
async (threadId: string): Promise<boolean> => {
86117
if (!commentsPdp) {
87-
logger.error('Comments PDP is not available');
118+
logger.debug('Comments PDP is not yet available for canUserAssignThreadCallback');
88119
return false;
89120
}
90121
return commentsPdp.canUserAssignThread(threadId);
@@ -95,7 +126,7 @@ global.webViewComponent = function CommentListWebView({
95126
const canUserResolveThreadCallback = useCallback(
96127
async (threadId: string): Promise<boolean> => {
97128
if (!commentsPdp) {
98-
logger.error('Comments PDP is not available');
129+
logger.debug('Comments PDP is not yet available for canUserResolveThreadCallback');
99130
return false;
100131
}
101132
return commentsPdp.canUserResolveThread(threadId);
@@ -106,7 +137,7 @@ global.webViewComponent = function CommentListWebView({
106137
const canUserEditOrDeleteCommentCallback = useCallback(
107138
async (commentId: string): Promise<boolean> => {
108139
if (!commentsPdp) {
109-
logger.error('Comments PDP is not available');
140+
logger.debug('Comments PDP is not yet available for canUserEditOrDeleteCommentCallback');
110141
return false;
111142
}
112143
return commentsPdp.canUserEditOrDeleteComment(commentId);
@@ -117,7 +148,7 @@ global.webViewComponent = function CommentListWebView({
117148
const handleAddCommentToThread = useCallback(
118149
async (options: AddCommentToThreadOptions): Promise<string | undefined> => {
119150
if (!commentsPdp) {
120-
logger.error('Comments PDP is not available');
151+
logger.debug('Comments PDP is not yet available for handleAddCommentToThread');
121152
return undefined;
122153
}
123154
try {
@@ -139,7 +170,7 @@ global.webViewComponent = function CommentListWebView({
139170
const handleUpdateComment = useCallback(
140171
async (commentId: string, contents: string): Promise<boolean> => {
141172
if (!commentsPdp) {
142-
logger.error('Comments PDP is not available');
173+
logger.debug('Comments PDP is not yet available for handleUpdateComment');
143174
return false;
144175
}
145176
try {
@@ -156,7 +187,7 @@ global.webViewComponent = function CommentListWebView({
156187
const handleDeleteComment = useCallback(
157188
async (commentId: string): Promise<boolean> => {
158189
if (!commentsPdp) {
159-
logger.error('Comments PDP is not available');
190+
logger.debug('Comments PDP is not yet available for handleDeleteComment');
160191
return false;
161192
}
162193
try {
@@ -204,6 +235,8 @@ global.webViewComponent = function CommentListWebView({
204235
canUserAssignThreadCallback={canUserAssignThreadCallback}
205236
canUserResolveThreadCallback={canUserResolveThreadCallback}
206237
canUserEditOrDeleteCommentCallback={canUserEditOrDeleteCommentCallback}
238+
selectedThreadId={selectedThreadId}
239+
onSelectedThreadChange={setSelectedThreadId}
207240
/>
208241
)}
209242
</div>

0 commit comments

Comments
 (0)