Browse Source

Merge pull request #28274 from overleaf/dp-review-panel-events

Add review panel tracking events back to editor

GitOrigin-RevId: 3e9b1dafd5e90909b75d7b082f0e407724dfc61a
David 11 months ago
parent
commit
b925953a70

+ 21 - 1
services/web/frontend/js/features/review-panel/context/ranges-context.tsx

@@ -32,6 +32,8 @@ import {
   TransactionSpec,
 } from '@codemirror/state'
 import { buildRangesFromSnapshot } from '@/features/review-panel/utils/snapshot-ranges'
+import { useEditorAnalytics } from '@/shared/hooks/use-editor-analytics'
+import { useReviewPanelViewContext } from './review-panel-view-context'
 
 export type Ranges = {
   docId: string
@@ -106,9 +108,11 @@ export const RangesProvider: FC<React.PropsWithChildren> = ({ children }) => {
   const { projectId } = useIdeReactContext()
   const { currentDocument } = useEditorOpenDocContext()
   const { socket } = useConnectionContext()
+  const { sendEvent } = useEditorAnalytics()
   const [ranges, setRanges] = useState<Ranges | undefined>(() =>
     buildRanges(currentDocument)
   )
+  const reviewPanelView = useReviewPanelViewContext()
 
   // rebuild the ranges when the current doc changes
   useEffect(() => {
@@ -247,6 +251,10 @@ export const RangesProvider: FC<React.PropsWithChildren> = ({ children }) => {
           }
 
           shareDoc.submitOp([op])
+          sendEvent('rp-changes-accepted', {
+            count: changes.length,
+            view: reviewPanelView,
+          })
 
           // dispatch an effect as the editor's doc doesn't change when tracked changes are accepted
           view.dispatch({
@@ -317,6 +325,10 @@ export const RangesProvider: FC<React.PropsWithChildren> = ({ children }) => {
           }
 
           shareDoc.submitOp([op])
+          sendEvent('rp-changes-rejected', {
+            count: changes.length,
+            view: reviewPanelView,
+          })
 
           // in case the doc didn't change
           view.dispatch(...specs, {
@@ -333,6 +345,10 @@ export const RangesProvider: FC<React.PropsWithChildren> = ({ children }) => {
             await postJSON(url, { body: { change_ids: ids } })
             currentDocument.ranges.removeChangeIds(ids)
             setRanges(buildRanges(currentDocument))
+            sendEvent('rp-changes-accepted', {
+              count: ids.length,
+              view: reviewPanelView,
+            })
           }
         },
         async rejectChanges(...changes) {
@@ -341,11 +357,15 @@ export const RangesProvider: FC<React.PropsWithChildren> = ({ children }) => {
             view.dispatch(
               rejectChanges(view.state, currentDocument.ranges, ids)
             )
+            sendEvent('rp-changes-rejected', {
+              count: ids.length,
+              view: reviewPanelView,
+            })
           }
         },
       } satisfies RangesActions
     }
-  }, [currentDocument, projectId, view])
+  }, [currentDocument, projectId, view, sendEvent, reviewPanelView])
 
   if (!actions) {
     return null

+ 14 - 5
services/web/frontend/js/features/review-panel/context/review-panel-view-context.tsx

@@ -1,8 +1,8 @@
+import { useEditorAnalytics } from '@/shared/hooks/use-editor-analytics'
 import {
   createContext,
-  Dispatch,
   FC,
-  SetStateAction,
+  useCallback,
   useContext,
   useMemo,
   useState,
@@ -13,7 +13,7 @@ export type View = 'cur_file' | 'overview'
 export const ReviewPanelViewContext = createContext<View>('cur_file')
 
 type ViewActions = {
-  setView: Dispatch<SetStateAction<View>>
+  setView: (newView: View) => void
 }
 
 const ReviewPanelViewActionsContext = createContext<ViewActions | undefined>(
@@ -24,12 +24,21 @@ export const ReviewPanelViewProvider: FC<React.PropsWithChildren> = ({
   children,
 }) => {
   const [view, setView] = useState<View>('cur_file')
+  const { sendEvent } = useEditorAnalytics()
+
+  const handleSetView = useCallback(
+    (newView: View) => {
+      sendEvent('rp-subview-change', { subView: newView })
+      setView(newView)
+    },
+    [sendEvent]
+  )
 
   const actions = useMemo(
     () => ({
-      setView,
+      setView: handleSetView,
     }),
-    [setView]
+    [handleSetView]
   )
 
   return (

+ 28 - 1
services/web/frontend/js/features/review-panel/context/threads-context.tsx

@@ -33,6 +33,8 @@ import Range from 'overleaf-editor-core/lib/range'
 import { trackedDeletesFromState } from '@/features/source-editor/utils/tracked-deletes'
 import { useCodeMirrorViewContext } from '@/features/source-editor/components/codemirror-context'
 import { rangesUpdatedEffect } from '@/features/source-editor/extensions/history-ot'
+import { useEditorAnalytics } from '@/shared/hooks/use-editor-analytics'
+import { useReviewPanelViewContext } from './review-panel-view-context'
 
 export type Threads = Record<ThreadId, ReviewPanelCommentThread>
 
@@ -62,6 +64,8 @@ export const ThreadsProvider: FC<React.PropsWithChildren> = ({ children }) => {
   const { currentDocument } = useEditorOpenDocContext()
   const { isRestrictedTokenMember } = useEditorContext()
   const view = useCodeMirrorViewContext()
+  const { sendEvent } = useEditorAnalytics()
+  const reviewPanelView = useReviewPanelViewContext()
 
   // const [error, setError] = useState<Error>()
   const [data, setData] = useState<Threads>()
@@ -275,6 +279,8 @@ export const ThreadsProvider: FC<React.PropsWithChildren> = ({ children }) => {
           body: { content },
         })
 
+        sendEvent('rp-new-comment', { size: content.length })
+
         const op: CommentOperation = {
           c: text,
           p: pos,
@@ -287,22 +293,31 @@ export const ThreadsProvider: FC<React.PropsWithChildren> = ({ children }) => {
         await postJSON(
           `/project/${projectId}/doc/${currentDocument.doc_id}/thread/${threadId}/resolve`
         )
+        sendEvent('rp-comment-resolve', { view: reviewPanelView })
       },
       async reopenThread(threadId: string) {
         await postJSON(
           `/project/${projectId}/doc/${currentDocument.doc_id}/thread/${threadId}/reopen`
         )
+        sendEvent('rp-comment-reopen')
       },
       async deleteThread(threadId: string) {
         await deleteJSON(
           `/project/${projectId}/doc/${currentDocument.doc_id}/thread/${threadId}`
         )
         currentDocument.ranges?.removeCommentId(threadId)
+        sendEvent('rp-comment-delete')
       },
       async addMessage(threadId: ThreadId, content: string) {
         await postJSON(`/project/${projectId}/thread/${threadId}/messages`, {
           body: { content },
         })
+
+        sendEvent('rp-comment-reply', {
+          view,
+          size: content.length,
+          thread: threadId,
+        })
       },
       async editMessage(
         threadId: ThreadId,
@@ -336,6 +351,8 @@ export const ThreadsProvider: FC<React.PropsWithChildren> = ({ children }) => {
             body: { content },
           })
 
+          sendEvent('rp-new-comment', { size: content.length })
+
           const trackedDeletes = trackedDeletesFromState(view.state)
           pos = trackedDeletes.toSnapshot(pos)
           const ranges = [new Range(pos, text.length)]
@@ -348,6 +365,7 @@ export const ThreadsProvider: FC<React.PropsWithChildren> = ({ children }) => {
         async resolveThread(threadId: string) {
           const op = new SetCommentStateOperation(threadId, true)
           currentDocument.historyOTShareDoc.submitOp([op])
+          sendEvent('rp-comment-resolve', { view: reviewPanelView })
           view.dispatch({
             effects: rangesUpdatedEffect.of(null),
           })
@@ -355,6 +373,7 @@ export const ThreadsProvider: FC<React.PropsWithChildren> = ({ children }) => {
         async reopenThread(threadId: string) {
           const op = new SetCommentStateOperation(threadId, false)
           currentDocument.historyOTShareDoc.submitOp([op])
+          sendEvent('rp-comment-reopen')
           view.dispatch({
             effects: rangesUpdatedEffect.of(null),
           })
@@ -362,6 +381,7 @@ export const ThreadsProvider: FC<React.PropsWithChildren> = ({ children }) => {
         async deleteThread(threadId: string) {
           const op = new DeleteCommentOperation(threadId)
           currentDocument.historyOTShareDoc.submitOp([op])
+          sendEvent('rp-comment-delete')
           view.dispatch({
             effects: rangesUpdatedEffect.of(null),
           })
@@ -370,7 +390,14 @@ export const ThreadsProvider: FC<React.PropsWithChildren> = ({ children }) => {
     }
 
     return actions
-  }, [view, currentDocument, projectId, isHistoryOT])
+  }, [
+    view,
+    reviewPanelView,
+    currentDocument,
+    projectId,
+    isHistoryOT,
+    sendEvent,
+  ])
 
   if (!actions) {
     return null