mirror of
https://github.com/overleaf/overleaf.git
synced 2024-11-07 20:31:06 -05:00
Merge pull request #15909 from overleaf/ii-ide-page-prototype-review-panel-refresh-ranges
[web] React ide page refresh ranges GitOrigin-RevId: 7f79b8f63869ee39fef9a101e6dcc56c39af8df7
This commit is contained in:
parent
a75b44a6fc
commit
81f5a1308e
4 changed files with 94 additions and 17 deletions
|
@ -1,5 +1,6 @@
|
|||
import { useState, useEffect, useMemo, useCallback, useRef } from 'react'
|
||||
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'
|
||||
|
@ -130,9 +131,9 @@ function useReviewPanelState(): ReviewPanelStateReactIde {
|
|||
const [nVisibleSelectedChanges] = useScopeValue<
|
||||
ReviewPanel.Value<'nVisibleSelectedChanges'>
|
||||
>('reviewPanel.nVisibleSelectedChanges')
|
||||
const [collapsed, setCollapsed] = useScopeValue<
|
||||
const [collapsed, setCollapsed] = usePersistedState<
|
||||
ReviewPanel.Value<'collapsed'>
|
||||
>('reviewPanel.overview.docsCollapsedState')
|
||||
>(`docs_collapsed_state:${projectId}`, {}, false, true)
|
||||
const [commentThreads, setCommentThreads] = useState<
|
||||
ReviewPanel.Value<'commentThreads'>
|
||||
>({})
|
||||
|
@ -273,7 +274,7 @@ function useReviewPanelState(): ReviewPanelStateReactIde {
|
|||
const getChangeTracker = useCallback(
|
||||
(docId: DocId) => {
|
||||
if (!rangesTrackers.current[docId]) {
|
||||
rangesTrackers.current[docId] = new RangesTracker() as RangesTracker
|
||||
rangesTrackers.current[docId] = new RangesTracker()
|
||||
rangesTrackers.current[docId].resolvedThreadIds = {
|
||||
...resolvedThreadIds,
|
||||
}
|
||||
|
@ -890,9 +891,47 @@ function useReviewPanelState(): ReviewPanelStateReactIde {
|
|||
[onThreadDeleted, projectId]
|
||||
)
|
||||
|
||||
const [refreshResolvedCommentsDropdown] = useScopeValue<
|
||||
ReviewPanel.UpdaterFn<'refreshResolvedCommentsDropdown'>
|
||||
>('refreshResolvedCommentsDropdown')
|
||||
const refreshRanges = useCallback(() => {
|
||||
type Doc = {
|
||||
id: DocId
|
||||
ranges: {
|
||||
comments?: unknown[]
|
||||
changes?: unknown[]
|
||||
}
|
||||
}
|
||||
|
||||
return getJSON<Doc[]>(`/project/${projectId}/ranges`)
|
||||
.then(docs => {
|
||||
setCollapsed(prevState => {
|
||||
const collapsed = { ...prevState }
|
||||
docs.forEach(doc => {
|
||||
if (collapsed[doc.id] == null) {
|
||||
collapsed[doc.id] = false
|
||||
}
|
||||
})
|
||||
return collapsed
|
||||
})
|
||||
|
||||
docs.forEach(async doc => {
|
||||
if (doc.id !== currentDocumentId) {
|
||||
// this is kept up to date in real-time, don't overwrite
|
||||
const rangesTracker = getChangeTracker(doc.id)
|
||||
rangesTracker.comments = doc.ranges?.comments ?? []
|
||||
rangesTracker.changes = doc.ranges?.changes ?? []
|
||||
}
|
||||
})
|
||||
|
||||
return Promise.all(docs.map(doc => updateEntries(doc.id)))
|
||||
})
|
||||
.catch(debugConsole.error)
|
||||
}, [
|
||||
currentDocumentId,
|
||||
getChangeTracker,
|
||||
projectId,
|
||||
setCollapsed,
|
||||
updateEntries,
|
||||
])
|
||||
|
||||
const [acceptChanges] =
|
||||
useScopeValue<ReviewPanel.UpdaterFn<'acceptChanges'>>('acceptChanges')
|
||||
const [rejectChanges] =
|
||||
|
@ -1056,7 +1095,7 @@ function useReviewPanelState(): ReviewPanelStateReactIde {
|
|||
submitNewComment,
|
||||
deleteComment,
|
||||
unresolveComment,
|
||||
refreshResolvedCommentsDropdown,
|
||||
refreshResolvedCommentsDropdown: refreshRanges,
|
||||
deleteThread,
|
||||
toggleTrackChangesForEveryone,
|
||||
toggleTrackChangesForUser,
|
||||
|
@ -1084,7 +1123,7 @@ function useReviewPanelState(): ReviewPanelStateReactIde {
|
|||
submitNewComment,
|
||||
deleteComment,
|
||||
unresolveComment,
|
||||
refreshResolvedCommentsDropdown,
|
||||
refreshRanges,
|
||||
deleteThread,
|
||||
toggleTrackChangesForEveryone,
|
||||
toggleTrackChangesForUser,
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import { ReactScopeValueStore } from '@/features/ide-react/scope-value-store/react-scope-value-store'
|
||||
|
||||
export default function populateReviewPanelScope(store: ReactScopeValueStore) {
|
||||
store.set('reviewPanel.overview.docsCollapsedState', {})
|
||||
store.set('reviewPanel.overview.loading', false)
|
||||
store.set('reviewPanel.nVisibleSelectedChanges', 0)
|
||||
store.set('permissions', {
|
||||
|
@ -18,7 +17,6 @@ export default function populateReviewPanelScope(store: ReactScopeValueStore) {
|
|||
store.set('deleteComment', () => {})
|
||||
store.set('gotoEntry', () => {})
|
||||
store.set('saveEdit', () => {})
|
||||
store.set('refreshResolvedCommentsDropdown', async () => {})
|
||||
store.set('acceptChanges', () => {})
|
||||
store.set('rejectChanges', () => {})
|
||||
store.set('bulkAcceptActions', () => {})
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import {
|
||||
CommentId,
|
||||
ReviewPanelCommentThreads,
|
||||
ReviewPanelDocEntries,
|
||||
ReviewPanelEntries,
|
||||
ReviewPanelUsers,
|
||||
SubView,
|
||||
|
@ -72,7 +73,9 @@ export interface ReviewPanelState {
|
|||
) => void
|
||||
unresolveComment: (threadId: ThreadId) => void
|
||||
deleteThread: (docId: DocId, threadId: ThreadId) => void
|
||||
refreshResolvedCommentsDropdown: () => Promise<void>
|
||||
refreshResolvedCommentsDropdown: () => Promise<
|
||||
void | ReviewPanelDocEntries[]
|
||||
>
|
||||
submitNewComment: (content: string) => Promise<void>
|
||||
setEntryHover: React.Dispatch<React.SetStateAction<Value<'entryHover'>>>
|
||||
setIsAddingComment: React.Dispatch<
|
||||
|
|
|
@ -7,14 +7,51 @@ import {
|
|||
} from 'react'
|
||||
import _ from 'lodash'
|
||||
import localStorage from '../../infrastructure/local-storage'
|
||||
import { debugConsole } from '@/utils/debugging'
|
||||
|
||||
const safeStringify = (value: unknown) => {
|
||||
try {
|
||||
return JSON.stringify(value)
|
||||
} catch (e) {
|
||||
debugConsole.error('double stringify exception', e)
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
const safeParse = (value: string) => {
|
||||
try {
|
||||
return JSON.parse(value)
|
||||
} catch (e) {
|
||||
debugConsole.error('double parse exception', e)
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
function usePersistedState<T = any>(
|
||||
key: string,
|
||||
defaultValue?: T,
|
||||
listen = false
|
||||
listen = false,
|
||||
// The option below is for backward compatibility with Angular
|
||||
// which sometimes stringifies the values twice
|
||||
doubleStringifyAndParse = false
|
||||
): [T, Dispatch<SetStateAction<T>>] {
|
||||
const getItem = useCallback(
|
||||
(key: string) => {
|
||||
const item = localStorage.getItem(key)
|
||||
return doubleStringifyAndParse ? safeParse(item) : item
|
||||
},
|
||||
[doubleStringifyAndParse]
|
||||
)
|
||||
const setItem = useCallback(
|
||||
(key: string, value: unknown) => {
|
||||
const val = doubleStringifyAndParse ? safeStringify(value) : value
|
||||
localStorage.setItem(key, val)
|
||||
},
|
||||
[doubleStringifyAndParse]
|
||||
)
|
||||
|
||||
const [value, setValue] = useState<T>(() => {
|
||||
return localStorage.getItem(key) ?? defaultValue
|
||||
return getItem(key) ?? defaultValue
|
||||
})
|
||||
|
||||
const updateFunction = useCallback(
|
||||
|
@ -27,13 +64,13 @@ function usePersistedState<T = any>(
|
|||
if (actualNewValue === defaultValue) {
|
||||
localStorage.removeItem(key)
|
||||
} else {
|
||||
localStorage.setItem(key, actualNewValue)
|
||||
setItem(key, actualNewValue)
|
||||
}
|
||||
|
||||
return actualNewValue
|
||||
})
|
||||
},
|
||||
[key, defaultValue]
|
||||
[key, defaultValue, setItem]
|
||||
)
|
||||
|
||||
useEffect(() => {
|
||||
|
@ -42,7 +79,7 @@ function usePersistedState<T = any>(
|
|||
if (event.key === key) {
|
||||
// note: this value is read via getItem rather than from event.newValue
|
||||
// because getItem handles deserializing the JSON that's stored in localStorage.
|
||||
setValue(localStorage.getItem(key) ?? defaultValue)
|
||||
setValue(getItem(key) ?? defaultValue)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -52,7 +89,7 @@ function usePersistedState<T = any>(
|
|||
window.removeEventListener('storage', listener)
|
||||
}
|
||||
}
|
||||
}, [key, listen, defaultValue])
|
||||
}, [defaultValue, key, listen, getItem])
|
||||
|
||||
return [value, updateFunction]
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue