mirror of
https://github.com/overleaf/overleaf.git
synced 2025-04-05 05:18:21 +00:00
Merge pull request #16493 from overleaf/ii-rp-mini-page-load
[web] Prevent opening and closing of the mini review panel GitOrigin-RevId: 25297a24ddfb2654b00efa8d33b825620f859147
This commit is contained in:
parent
6703ed7e27
commit
fc3fb7318a
3 changed files with 91 additions and 90 deletions
|
@ -4,11 +4,10 @@ import { isEqual, cloneDeep } from 'lodash'
|
|||
import usePersistedState from '@/shared/hooks/use-persisted-state'
|
||||
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 useLayoutToLeft from '@/features/ide-react/context/review-panel/hooks/useLayoutToLeft'
|
||||
import { sendMB } from '../../../../../infrastructure/event-tracking'
|
||||
import { sendMB } from '@/infrastructure/event-tracking'
|
||||
import {
|
||||
dispatchReviewPanelLayout as handleLayoutChange,
|
||||
UpdateType,
|
||||
|
@ -197,26 +196,25 @@ function useReviewPanelState(): ReviewPanelStateReactIde {
|
|||
Record<ThreadId, boolean>
|
||||
>({})
|
||||
|
||||
const {
|
||||
isLoading: loadingThreads,
|
||||
reset,
|
||||
runAsync: runAsyncThreads,
|
||||
} = useAsync<ReviewPanelCommentThreadsApi>()
|
||||
const [loadingThreads, setLoadingThreads] =
|
||||
useScopeValue<boolean>('loadingThreads')
|
||||
|
||||
const loadThreadsController = useAbortController()
|
||||
const loadThreadsExecuted = useRef(false)
|
||||
const threadsLoadedOnceRef = useRef(false)
|
||||
const loadingThreadsInProgressRef = useRef(false)
|
||||
const ensureThreadsAreLoaded = useCallback(() => {
|
||||
if (loadThreadsExecuted.current) {
|
||||
if (threadsLoadedOnceRef.current) {
|
||||
// We get any updates in real time so only need to load them once.
|
||||
return
|
||||
}
|
||||
loadThreadsExecuted.current = true
|
||||
threadsLoadedOnceRef.current = true
|
||||
loadingThreadsInProgressRef.current = true
|
||||
|
||||
return runAsyncThreads(
|
||||
getJSON(`/project/${projectId}/threads`, {
|
||||
signal: loadThreadsController.signal,
|
||||
})
|
||||
)
|
||||
return getJSON(`/project/${projectId}/threads`, {
|
||||
signal: loadThreadsController.signal,
|
||||
})
|
||||
.then(threads => {
|
||||
setLoadingThreads(false)
|
||||
const tempResolvedThreadIds: typeof resolvedThreadIds = {}
|
||||
const threadsEntries = Object.entries(threads) as [
|
||||
[
|
||||
|
@ -248,7 +246,10 @@ function useReviewPanelState(): ReviewPanelStateReactIde {
|
|||
}
|
||||
})
|
||||
.catch(debugConsole.error)
|
||||
}, [loadThreadsController.signal, projectId, runAsyncThreads])
|
||||
.finally(() => {
|
||||
loadingThreadsInProgressRef.current = false
|
||||
})
|
||||
}, [loadThreadsController.signal, projectId, setLoadingThreads])
|
||||
|
||||
const rangesTrackers = useRef<Record<DocId, RangesTracker>>({})
|
||||
const refreshingRangeUsers = useRef(false)
|
||||
|
@ -335,21 +336,6 @@ function useReviewPanelState(): ReviewPanelStateReactIde {
|
|||
const updateEntries = useCallback(
|
||||
async (docId: DocId) => {
|
||||
const rangesTracker = getChangeTracker(docId)
|
||||
let localResolvedThreadIds = resolvedThreadIds
|
||||
|
||||
if (!isRestrictedTokenMember) {
|
||||
if (rangesTracker.comments.length > 0) {
|
||||
const threadsLoadResult = await ensureThreadsAreLoaded()
|
||||
if (typeof threadsLoadResult === 'object') {
|
||||
localResolvedThreadIds = threadsLoadResult.resolvedThreadIds
|
||||
}
|
||||
} else if (loadingThreads) {
|
||||
// ensure that tracked changes are highlighted even if no comments are loaded
|
||||
reset()
|
||||
dispatchReviewPanelEvent('loaded_threads')
|
||||
}
|
||||
}
|
||||
|
||||
const docEntries = cloneDeep(getDocEntries(docId))
|
||||
const docResolvedComments = cloneDeep(getDocResolvedComments(docId))
|
||||
// Assume we'll delete everything until we see it, then we'll remove it from this object
|
||||
|
@ -432,32 +418,41 @@ function useReviewPanelState(): ReviewPanelStateReactIde {
|
|||
}
|
||||
}
|
||||
|
||||
for (const comment of rangesTracker.comments) {
|
||||
deleteChanges.delete(comment.id)
|
||||
let localResolvedThreadIds = resolvedThreadIds
|
||||
|
||||
const newEntry: Partial<ReviewPanelCommentEntry> = {
|
||||
type: 'comment',
|
||||
thread_id: comment.op.t,
|
||||
entry_ids: [comment.id],
|
||||
content: comment.op.c,
|
||||
offset: comment.op.p,
|
||||
if (!isRestrictedTokenMember) {
|
||||
if (rangesTracker.comments.length > 0) {
|
||||
const threadsLoadResult = await ensureThreadsAreLoaded()
|
||||
if (threadsLoadResult?.resolvedThreadIds) {
|
||||
localResolvedThreadIds = threadsLoadResult.resolvedThreadIds
|
||||
}
|
||||
} else if (loadingThreads) {
|
||||
// ensure that tracked changes are highlighted even if no comments are loaded
|
||||
setLoadingThreads(false)
|
||||
dispatchReviewPanelEvent('loaded_threads')
|
||||
}
|
||||
}
|
||||
|
||||
let newComment: any
|
||||
if (localResolvedThreadIds[comment.op.t]) {
|
||||
docResolvedComments[comment.id] ??= {} as ReviewPanelCommentEntry
|
||||
newComment = docResolvedComments[comment.id]
|
||||
delete docEntries[comment.id]
|
||||
} else {
|
||||
docEntries[comment.id] ??= {} as ReviewPanelEntry
|
||||
newComment = docEntries[comment.id]
|
||||
delete docResolvedComments[comment.id]
|
||||
}
|
||||
if (!loadingThreadsInProgressRef.current) {
|
||||
for (const comment of rangesTracker.comments) {
|
||||
deleteChanges.delete(comment.id)
|
||||
|
||||
for (const [key, value] of Object.entries(newEntry) as Entries<
|
||||
typeof newEntry
|
||||
>) {
|
||||
newComment[key] = value
|
||||
let newComment: any
|
||||
if (localResolvedThreadIds[comment.op.t]) {
|
||||
docResolvedComments[comment.id] ??= {} as ReviewPanelCommentEntry
|
||||
newComment = docResolvedComments[comment.id]
|
||||
delete docEntries[comment.id]
|
||||
} else {
|
||||
docEntries[comment.id] ??= {} as ReviewPanelEntry
|
||||
newComment = docEntries[comment.id]
|
||||
delete docResolvedComments[comment.id]
|
||||
}
|
||||
|
||||
newComment.type = 'comment'
|
||||
newComment.thread_id = comment.op.t
|
||||
newComment.entry_ids = [comment.id]
|
||||
newComment.content = comment.op.c
|
||||
newComment.offset = comment.op.p
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -489,7 +484,7 @@ function useReviewPanelState(): ReviewPanelStateReactIde {
|
|||
users,
|
||||
ensureThreadsAreLoaded,
|
||||
loadingThreads,
|
||||
reset,
|
||||
setLoadingThreads,
|
||||
]
|
||||
)
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import { ReactScopeValueStore } from '@/features/ide-react/scope-value-store/react-scope-value-store'
|
||||
|
||||
export default function populateReviewPanelScope(store: ReactScopeValueStore) {
|
||||
store.set('loadingThreads', true)
|
||||
store.set('users', {})
|
||||
store.set('addNewComment', () => {})
|
||||
}
|
||||
|
|
|
@ -404,7 +404,7 @@ export default App.controller('ReviewPanelController', [
|
|||
return q
|
||||
}
|
||||
|
||||
function updateEntries(doc_id) {
|
||||
async function updateEntries(doc_id) {
|
||||
const rangesTracker = getChangeTracker(doc_id)
|
||||
const entries = getDocEntries(doc_id)
|
||||
const resolvedComments = getDocResolvedComments(doc_id)
|
||||
|
@ -478,7 +478,7 @@ export default App.controller('ReviewPanelController', [
|
|||
|
||||
if (!window.isRestrictedTokenMember) {
|
||||
if (rangesTracker.comments.length > 0) {
|
||||
ensureThreadsAreLoaded()
|
||||
await ensureThreadsAreLoaded()
|
||||
} else if (ide.$scope.loadingThreads === true) {
|
||||
// ensure that tracked changes are highlighted even if no comments are loaded
|
||||
ide.$scope.loadingThreads = false
|
||||
|
@ -486,32 +486,34 @@ export default App.controller('ReviewPanelController', [
|
|||
}
|
||||
}
|
||||
|
||||
for (const comment of Array.from(rangesTracker.comments)) {
|
||||
let new_comment
|
||||
changed = true
|
||||
delete delete_changes[comment.id]
|
||||
if (ide.$scope.reviewPanel.resolvedThreadIds[comment.op.t]) {
|
||||
new_comment =
|
||||
resolvedComments[comment.id] != null
|
||||
? resolvedComments[comment.id]
|
||||
: (resolvedComments[comment.id] = {})
|
||||
delete entries[comment.id]
|
||||
} else {
|
||||
new_comment =
|
||||
entries[comment.id] != null
|
||||
? entries[comment.id]
|
||||
: (entries[comment.id] = {})
|
||||
delete resolvedComments[comment.id]
|
||||
}
|
||||
const new_entry = {
|
||||
type: 'comment',
|
||||
thread_id: comment.op.t,
|
||||
entry_ids: [comment.id],
|
||||
content: comment.op.c,
|
||||
offset: comment.op.p,
|
||||
}
|
||||
for (const key in new_entry) {
|
||||
new_comment[key] = new_entry[key]
|
||||
if (!_loadingThreadsInProgress) {
|
||||
for (const comment of Array.from(rangesTracker.comments)) {
|
||||
let new_comment
|
||||
changed = true
|
||||
delete delete_changes[comment.id]
|
||||
if (ide.$scope.reviewPanel.resolvedThreadIds[comment.op.t]) {
|
||||
new_comment =
|
||||
resolvedComments[comment.id] != null
|
||||
? resolvedComments[comment.id]
|
||||
: (resolvedComments[comment.id] = {})
|
||||
delete entries[comment.id]
|
||||
} else {
|
||||
new_comment =
|
||||
entries[comment.id] != null
|
||||
? entries[comment.id]
|
||||
: (entries[comment.id] = {})
|
||||
delete resolvedComments[comment.id]
|
||||
}
|
||||
const new_entry = {
|
||||
type: 'comment',
|
||||
thread_id: comment.op.t,
|
||||
entry_ids: [comment.id],
|
||||
content: comment.op.c,
|
||||
offset: comment.op.p,
|
||||
}
|
||||
for (const key in new_entry) {
|
||||
new_comment[key] = new_entry[key]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -530,9 +532,9 @@ export default App.controller('ReviewPanelController', [
|
|||
return entries
|
||||
}
|
||||
|
||||
$scope.$on('editor:track-changes:changed', function () {
|
||||
$scope.$on('editor:track-changes:changed', async function () {
|
||||
const doc_id = $scope.editor.open_doc_id
|
||||
const entries = updateEntries(doc_id)
|
||||
const entries = await updateEntries(doc_id)
|
||||
|
||||
$scope.$broadcast('review-panel:recalculate-screen-positions')
|
||||
dispatchReviewPanelEvent('recalculate-screen-positions', {
|
||||
|
@ -1191,19 +1193,22 @@ export default App.controller('ReviewPanelController', [
|
|||
.catch(() => (_refreshingRangeUsers = false))
|
||||
}
|
||||
|
||||
let _threadsLoaded = false
|
||||
function ensureThreadsAreLoaded() {
|
||||
if (_threadsLoaded) {
|
||||
let _threadsLoadedOnce = false
|
||||
let _loadingThreadsInProgress = false
|
||||
async function ensureThreadsAreLoaded() {
|
||||
if (_threadsLoadedOnce) {
|
||||
// We get any updates in real time so only need to load them once.
|
||||
return
|
||||
}
|
||||
_threadsLoaded = true
|
||||
_threadsLoadedOnce = true
|
||||
_loadingThreadsInProgress = true
|
||||
ide.$scope.loadingThreads = true
|
||||
return $http
|
||||
.get(`/project/${$scope.project_id}/threads`)
|
||||
.then(function (response) {
|
||||
.then(async function (response) {
|
||||
const threads = response.data
|
||||
ide.$scope.loadingThreads = false
|
||||
_loadingThreadsInProgress = false
|
||||
for (const thread_id in ide.$scope.reviewPanel.resolvedThreadIds) {
|
||||
delete ide.$scope.reviewPanel.resolvedThreadIds[thread_id]
|
||||
}
|
||||
|
@ -1222,7 +1227,7 @@ export default App.controller('ReviewPanelController', [
|
|||
// Update entries so that the view has up-to-date information about
|
||||
// the entries when handling the loaded_threads events, which avoids
|
||||
// thrashing
|
||||
updateEntries($scope.editor.open_doc_id)
|
||||
await updateEntries($scope.editor.open_doc_id)
|
||||
|
||||
dispatchReviewPanelEvent('loaded_threads')
|
||||
return $timeout(() => ide.$scope.$broadcast('review-panel:layout'))
|
||||
|
|
Loading…
Reference in a new issue