Merge pull request #19914 from overleaf/rh-viewer-comments

[web] Allow Viewers to access chat and view comments/tracked changes

GitOrigin-RevId: 72be0444afdf5e0ad5937bf25718a7566bad001a
This commit is contained in:
roo hutton 2024-08-28 11:09:32 +01:00 committed by Copybot
parent 446e19424d
commit 837b5a4b9b
5 changed files with 10 additions and 28 deletions

View file

@ -11,14 +11,13 @@ import withErrorBoundary from '../../../infrastructure/error-boundary'
import { FetchError } from '../../../infrastructure/fetch-json' import { FetchError } from '../../../infrastructure/fetch-json'
import { useChatContext } from '../context/chat-context' import { useChatContext } from '../context/chat-context'
import LoadingSpinner from '../../../shared/components/loading-spinner' import LoadingSpinner from '../../../shared/components/loading-spinner'
import useViewerPermissions from '@/shared/hooks/use-viewer-permissions'
const MessageList = lazy(() => import('./message-list')) const MessageList = lazy(() => import('./message-list'))
const ChatPane = React.memo(function ChatPane() { const ChatPane = React.memo(function ChatPane() {
const { t } = useTranslation() const { t } = useTranslation()
const { setChatIsOpen, chatIsOpen } = useLayoutContext() const { chatIsOpen } = useLayoutContext()
const user = useUserContext() const user = useUserContext()
const { const {
@ -47,17 +46,13 @@ const ChatPane = React.memo(function ChatPane() {
0 0
) )
const shouldShowChat = !useViewerPermissions()
// Keep the chat pane in the DOM to avoid resetting the form input and re-rendering MathJax content. // Keep the chat pane in the DOM to avoid resetting the form input and re-rendering MathJax content.
const [chatOpenedOnce, setChatOpenedOnce] = useState(chatIsOpen) const [chatOpenedOnce, setChatOpenedOnce] = useState(chatIsOpen)
useEffect(() => { useEffect(() => {
if (chatIsOpen && shouldShowChat) { if (chatIsOpen) {
setChatOpenedOnce(true) setChatOpenedOnce(true)
} else if (chatIsOpen && !shouldShowChat) {
setChatIsOpen(false)
} }
}, [chatIsOpen, setChatIsOpen, shouldShowChat]) }, [chatIsOpen])
if (error) { if (error) {
// let user try recover from fetch errors // let user try recover from fetch errors

View file

@ -17,7 +17,6 @@ import { appendMessage, prependMessages } from '../utils/message-list-appender'
import useBrowserWindow from '../../../shared/hooks/use-browser-window' import useBrowserWindow from '../../../shared/hooks/use-browser-window'
import { useLayoutContext } from '../../../shared/context/layout-context' import { useLayoutContext } from '../../../shared/context/layout-context'
import { useIdeContext } from '@/shared/context/ide-context' import { useIdeContext } from '@/shared/context/ide-context'
import useViewerPermissions from '@/shared/hooks/use-viewer-permissions'
const PAGE_SIZE = 50 const PAGE_SIZE = 50
@ -287,10 +286,9 @@ export const ChatProvider: FC = ({ children }) => {
}, []) }, [])
// Handling receiving messages over the socket // Handling receiving messages over the socket
const hasViewerPermissions = useViewerPermissions()
const { socket } = useIdeContext() const { socket } = useIdeContext()
useEffect(() => { useEffect(() => {
if (!socket || hasViewerPermissions) return if (!socket) return
function receivedMessage(message: any) { function receivedMessage(message: any) {
// If the message is from the current client id, then we are receiving the sent message back from the socket. // If the message is from the current client id, then we are receiving the sent message back from the socket.
@ -306,7 +304,7 @@ export const ChatProvider: FC = ({ children }) => {
socket.removeListener('new-chat-message', receivedMessage) socket.removeListener('new-chat-message', receivedMessage)
} }
}, [socket, hasViewerPermissions]) }, [socket])
// Handle unread messages // Handle unread messages
useEffect(() => { useEffect(() => {

View file

@ -6,7 +6,6 @@ import { useLayoutContext } from '../../../shared/context/layout-context'
import { useProjectContext } from '../../../shared/context/project-context' import { useProjectContext } from '../../../shared/context/project-context'
import * as eventTracking from '../../../infrastructure/event-tracking' import * as eventTracking from '../../../infrastructure/event-tracking'
import { Doc } from '../../../../../types/doc' import { Doc } from '../../../../../types/doc'
import useViewerPermissions from '@/shared/hooks/use-viewer-permissions'
function isOpentoString(open: boolean) { function isOpentoString(open: boolean) {
return open ? 'open' : 'close' return open ? 'open' : 'close'
@ -45,7 +44,6 @@ const EditorNavigationToolbarRoot = React.memo(
} = useLayoutContext() } = useLayoutContext()
const { markMessagesAsRead, unreadMessageCount } = useChatContext() const { markMessagesAsRead, unreadMessageCount } = useChatContext()
const canViewChatAndTrackChanges = !useViewerPermissions()
const toggleChatOpen = useCallback(() => { const toggleChatOpen = useCallback(() => {
if (!chatIsOpen) { if (!chatIsOpen) {
@ -121,12 +119,12 @@ const EditorNavigationToolbarRoot = React.memo(
hasPublishPermissions={ hasPublishPermissions={
permissionsLevel === 'owner' || permissionsLevel === 'readAndWrite' permissionsLevel === 'owner' || permissionsLevel === 'readAndWrite'
} }
chatVisible={!(isRestrictedTokenMember || !canViewChatAndTrackChanges)} chatVisible={!isRestrictedTokenMember}
projectName={projectName} projectName={projectName}
renameProject={renameProject} renameProject={renameProject}
hasRenamePermissions={permissionsLevel === 'owner'} hasRenamePermissions={permissionsLevel === 'owner'}
openShareModal={openShareModal} openShareModal={openShareModal}
trackChangesVisible={canViewChatAndTrackChanges && trackChangesVisible} trackChangesVisible={trackChangesVisible}
/> />
) )
} }

View file

@ -64,7 +64,6 @@ import {
EditOperation, EditOperation,
} from '../../../../../../../types/change' } from '../../../../../../../types/change'
import { RangesTrackerWithResolvedThreadIds } from '@/features/ide-react/editor/document-container' import { RangesTrackerWithResolvedThreadIds } from '@/features/ide-react/editor/document-container'
import useViewerPermissions from '@/shared/hooks/use-viewer-permissions'
import getMeta from '@/utils/meta' import getMeta from '@/utils/meta'
import { useEditorContext } from '@/shared/context/editor-context' import { useEditorContext } from '@/shared/context/editor-context'
@ -152,7 +151,6 @@ function useReviewPanelState(): ReviewPanel.ReviewPanelState {
const permissions = usePermissionsContext() const permissions = usePermissionsContext()
const { showGenericMessageModal } = useModalsContext() const { showGenericMessageModal } = useModalsContext()
const addCommentEmitter = useScopeEventEmitter('comment:start_adding') const addCommentEmitter = useScopeEventEmitter('comment:start_adding')
const hasViewerPermissions = useViewerPermissions()
const layoutToLeft = useLayoutToLeft('.ide-react-editor-panel') const layoutToLeft = useLayoutToLeft('.ide-react-editor-panel')
const [subView, setSubView] = const [subView, setSubView] =
@ -420,7 +418,7 @@ function useReviewPanelState(): ReviewPanel.ReviewPanelState {
} }
if (!users[change.metadata.user_id]) { if (!users[change.metadata.user_id]) {
if (!(isRestrictedTokenMember || hasViewerPermissions)) { if (!isRestrictedTokenMember) {
refreshChangeUsers(change.metadata.user_id) refreshChangeUsers(change.metadata.user_id)
} }
} }
@ -428,10 +426,7 @@ function useReviewPanelState(): ReviewPanel.ReviewPanelState {
let localResolvedThreadIds = resolvedThreadIds let localResolvedThreadIds = resolvedThreadIds
if ( if (!isRestrictedTokenMember && rangesTracker.comments.length > 0) {
!(isRestrictedTokenMember || hasViewerPermissions) &&
rangesTracker.comments.length > 0
) {
const threadsLoadResult = await ensureThreadsAreLoaded() const threadsLoadResult = await ensureThreadsAreLoaded()
if (threadsLoadResult?.resolvedThreadIds) { if (threadsLoadResult?.resolvedThreadIds) {
localResolvedThreadIds = threadsLoadResult.resolvedThreadIds localResolvedThreadIds = threadsLoadResult.resolvedThreadIds
@ -494,7 +489,6 @@ function useReviewPanelState(): ReviewPanel.ReviewPanelState {
ensureThreadsAreLoaded, ensureThreadsAreLoaded,
loadingThreads, loadingThreads,
setLoadingThreads, setLoadingThreads,
hasViewerPermissions,
isRestrictedTokenMember, isRestrictedTokenMember,
] ]
) )

View file

@ -18,7 +18,6 @@ import { dispatchTimer } from '../../../infrastructure/cm6-performance'
import importOverleafModules from '../../../../macros/import-overleaf-module.macro' import importOverleafModules from '../../../../macros/import-overleaf-module.macro'
import { FigureModal } from './figure-modal/figure-modal' import { FigureModal } from './figure-modal/figure-modal'
import useViewerPermissions from '@/shared/hooks/use-viewer-permissions'
import { ReviewPanelProviders } from '@/features/review-panel-new/context/review-panel-providers' import { ReviewPanelProviders } from '@/features/review-panel-new/context/review-panel-providers'
import { ReviewPanelMigration } from '@/features/source-editor/components/review-panel/review-panel-migration' import { ReviewPanelMigration } from '@/features/source-editor/components/review-panel/review-panel-migration'
@ -38,8 +37,6 @@ function CodeMirrorEditor() {
const isMounted = useIsMounted() const isMounted = useIsMounted()
const shouldShowReviewPanel = !useViewerPermissions()
// create the view using the initial state and intercept transactions // create the view using the initial state and intercept transactions
const viewRef = useRef<EditorView | null>(null) const viewRef = useRef<EditorView | null>(null)
if (viewRef.current === null) { if (viewRef.current === null) {
@ -75,7 +72,7 @@ function CodeMirrorEditor() {
)} )}
<CodeMirrorCommandTooltip /> <CodeMirrorCommandTooltip />
{shouldShowReviewPanel && <ReviewPanelMigration />} <ReviewPanelMigration />
{sourceEditorComponents.map( {sourceEditorComponents.map(
({ import: { default: Component }, path }) => ( ({ import: { default: Component }, path }) => (
<Component key={path} /> <Component key={path} />