Merge pull request #16065 from overleaf/ii-ide-page-prototype-review-panel-add-comment

[web] React ide page add comment

GitOrigin-RevId: 4c2442ccc77760d4a27268551c9dd2d73fcdba84
This commit is contained in:
ilkin-overleaf 2023-12-04 15:10:35 +02:00 committed by Copybot
parent db5500cbe8
commit 8035241cc0
6 changed files with 84 additions and 7 deletions

View file

@ -6,6 +6,7 @@ import useScopeValue from '../../../../../shared/hooks/use-scope-value'
import useSocketListener from '@/features/ide-react/hooks/use-socket-listener'
import useAsync from '@/shared/hooks/use-async'
import useAbortController from '@/shared/hooks/use-abort-controller'
import useScopeEventEmitter from '@/shared/hooks/use-scope-event-emitter'
import { sendMB } from '../../../../../infrastructure/event-tracking'
import {
dispatchReviewPanelLayout as handleLayoutChange,
@ -130,6 +131,7 @@ function useReviewPanelState(): ReviewPanelStateReactIde {
// TODO permissions to be removed from the review panel context. It currently acts just as a proxy.
const { permissions } = usePermissionsContext()
const { showGenericMessageModal } = useModalsContext()
const addCommentEmitter = useScopeEventEmitter('comment:start_adding')
// TODO `currentDocument` and `currentDocumentId` should be get from `useEditorManagerContext()` but that makes tests fail
const [currentDocument] = useScopeValue<Document>('editor.sharejs_doc')
@ -834,8 +836,6 @@ function useReviewPanelState(): ReviewPanelStateReactIde {
applyTrackChangesStateToClient
)
const [submitNewComment] =
useScopeValue<ReviewPanel.UpdaterFn<'submitNewComment'>>('submitNewComment')
const [gotoEntry] =
useScopeValue<ReviewPanel.UpdaterFn<'gotoEntry'>>('gotoEntry')
@ -1097,6 +1097,53 @@ function useReviewPanelState(): ReviewPanelStateReactIde {
[getThread, projectId, showGenericMessageModal, t, view]
)
// TODO `submitNewComment` is partially localized in the `add-comment-entry` component.
const submitNewComment = useCallback(
(content: string) => {
if (!content) {
return
}
const entries = getDocEntries(currentDocumentId)
const addCommentEntry = entries['add-comment'] as
| ReviewPanelAddCommentEntry
| undefined
if (!addCommentEntry) {
return
}
const { offset, length } = addCommentEntry
const threadId = RangesTracker.generateId()
setCommentThreads(prevState => ({
...prevState,
[threadId]: { ...getThread(threadId), submitting: true },
}))
const url = `/project/${projectId}/thread/${threadId}/messages`
postJSON(url, { body: { content } })
.then(() => {
dispatchReviewPanelEvent('comment:add', { threadId, offset, length })
handleLayoutChange({ async: true })
sendMB('rp-new-comment', { size: content.length })
})
.catch(() => {
showGenericMessageModal(
t('error_submitting_comment'),
t('comment_submit_error')
)
})
},
[
currentDocumentId,
getDocEntries,
getThread,
projectId,
showGenericMessageModal,
t,
]
)
const [entryHover, setEntryHover] = useState(false)
const [isAddingComment, setIsAddingComment] = useState(false)
const [navHeight, setNavHeight] = useState(0)
@ -1250,6 +1297,19 @@ function useReviewPanelState(): ReviewPanelStateReactIde {
handleLayoutChange()
}
const addNewCommentFromKbdShortcut = () => {
if (!trackChangesVisible) {
return
}
dispatchReviewPanelEvent('comment:select_line')
if (!reviewPanelOpen) {
toggleReviewPanel()
}
handleLayoutChange({ async: true })
addCommentEmitter()
}
const handleEditorEvents = (e: Event) => {
const event = e as CustomEvent
const { type, payload } = event.detail
@ -1266,6 +1326,11 @@ function useReviewPanelState(): ReviewPanelStateReactIde {
break
}
case 'add-new-comment': {
addNewCommentFromKbdShortcut()
break
}
case 'toggle-track-changes': {
toggleTrackChangesFromKbdShortcut()
break
@ -1279,9 +1344,12 @@ function useReviewPanelState(): ReviewPanelStateReactIde {
window.removeEventListener('editor:event', handleEditorEvents)
}
}, [
addCommentEmitter,
currentDocumentId,
getDocEntries,
resolvedThreadIds,
reviewPanelOpen,
toggleReviewPanel,
toggleTrackChangesForUser,
trackChanges,
trackChangesState,

View file

@ -6,8 +6,6 @@ export default function populateReviewPanelScope(store: ReactScopeValueStore) {
store.set('users', {})
store.set('reviewPanel.layoutToLeft', false)
store.set('reviewPanel.rendererData.lineHeight', 0)
store.set('submitNewComment', async () => {})
store.set('gotoEntry', () => {})
store.set('saveEdit', () => {})
store.set('addNewComment', () => {})
}

View file

@ -8,6 +8,7 @@ import {
useReviewPanelUpdaterFnsContext,
useReviewPanelValueContext,
} from '../../../context/review-panel/review-panel-context'
import { useIdeContext } from '@/shared/context/ide-context'
import { useCodeMirrorViewContext } from '../../codemirror-editor'
import Modal, { useBulkActionsModal } from '../entries/bulk-actions-entry/modal'
import getMeta from '../../../../../utils/meta'
@ -27,6 +28,8 @@ function EditorWidgets() {
} = useBulkActionsModal()
const { setIsAddingComment, handleSetSubview } =
useReviewPanelUpdaterFnsContext()
const { isReactIde } = useIdeContext()
const { toggleReviewPanel } = useReviewPanelUpdaterFnsContext()
const [addNewComment] =
useScopeValue<(e: React.MouseEvent<HTMLButtonElement>) => void>(
'addNewComment'
@ -47,6 +50,13 @@ function EditorWidgets() {
openDocId && openDocId in entries ? entries[openDocId] : undefined
const handleAddNewCommentClick = (e: React.MouseEvent<HTMLButtonElement>) => {
if (isReactIde) {
e.preventDefault()
setIsAddingComment(true)
toggleReviewPanel()
return
}
addNewComment(e)
setTimeout(() => {
// Re-render the comment box in order to add autofocus every time

View file

@ -30,10 +30,10 @@ function AddCommentEntry() {
handleLayoutChange({ async: true })
}
const handleSubmitNewComment = async () => {
const handleSubmitNewComment = () => {
setIsSubmitting(true)
try {
await submitNewComment(content)
submitNewComment(content)
setIsSubmitting(false)
setIsAddingComment(false)
setContent('')

View file

@ -33,6 +33,7 @@ function ReviewPanelView({ parentDomNode }: ReviewPanelViewProps) {
</>
)
// TODO fix DOM structure
return ReactDOM.createPortal(
isReactIde ? (
<div

View file

@ -76,7 +76,7 @@ export interface ReviewPanelState {
refreshResolvedCommentsDropdown: () => Promise<
void | ReviewPanelDocEntries[]
>
submitNewComment: (content: string) => Promise<void>
submitNewComment: (content: string) => void
setEntryHover: React.Dispatch<React.SetStateAction<Value<'entryHover'>>>
setIsAddingComment: React.Dispatch<
React.SetStateAction<Value<'isAddingComment'>>