Merge pull request #15829 from overleaf/ii-ide-page-prototype-permissions

[web] React ide page permissions

GitOrigin-RevId: 727d33e0654d4bfefe5e710e553895f793cacb82
This commit is contained in:
ilkin-overleaf
2023-11-24 09:04:27 +00:00
committed by Copybot
parent 1f39b6d72a
commit e4f5afc0c0
14 changed files with 168 additions and 48 deletions
@@ -1,5 +1,5 @@
import { Project } from '../../../../../types/project'
import { PermissionsLevel } from '../types/permissions-level'
import { PermissionsLevel } from '@/features/ide-react/types/permissions'
export type JoinProjectPayloadProject = Pick<
Project,
@@ -21,6 +21,7 @@ import useEventListener from '@/shared/hooks/use-event-listener'
import { FileTreeFindResult } from '@/features/ide-react/types/file-tree'
import { Project } from '../../../../../types/project'
import { useModalsContext } from '@/features/ide-react/context/modals-context'
import { usePermissionsContext } from '@/features/ide-react/context/permissions-context'
import { useTranslation } from 'react-i18next'
type DocumentMetadata = {
@@ -53,6 +54,7 @@ export const MetadataProvider: FC = ({ children }) => {
const { socket } = useConnectionContext()
const { onlineUsersCount } = useOnlineUsersContext()
const { permissionsLevel } = useEditorContext()
const { permissions } = usePermissionsContext()
const { currentDocument } = useEditorManagerContext()
const { showGenericMessageModal } = useModalsContext()
@@ -190,7 +192,7 @@ export const MetadataProvider: FC = ({ children }) => {
)
}
window.setTimeout(() => {
if (permissionsLevel !== 'readOnly') {
if (permissions.write) {
loadProjectMetaFromServer()
}
}, 200)
@@ -204,7 +206,7 @@ export const MetadataProvider: FC = ({ children }) => {
}, [
eventEmitter,
loadProjectMetaFromServer,
permissionsLevel,
permissions,
showGenericMessageModal,
t,
])
@@ -0,0 +1,117 @@
import { createContext, useContext, useState, useEffect, useMemo } from 'react'
import { useConnectionContext } from '@/features/ide-react/context/connection-context'
import { useEditorContext } from '@/shared/context/editor-context'
import getMeta from '@/utils/meta'
import { Permissions } from '@/features/ide-react/types/permissions'
type PermissionsContextValue = {
permissions: Permissions
}
const PermissionsContext = createContext<PermissionsContextValue | undefined>(
undefined
)
const readOnlyPermissions: Readonly<Permissions> = {
read: true,
write: false,
admin: false,
comment: true,
}
const readAndWritePermissions: Readonly<Permissions> = {
read: true,
write: true,
admin: false,
comment: true,
}
const ownerPermissions: Readonly<Permissions> = {
read: true,
write: true,
admin: true,
comment: true,
}
const permissionsMap = {
readOnly: readOnlyPermissions,
readAndWrite: readAndWritePermissions,
owner: ownerPermissions,
anonymous: {
readOnly: { ...readOnlyPermissions, comment: false },
readAndWrite: { ...readAndWritePermissions, comment: false },
owner: { ...ownerPermissions, comment: false },
},
} as const
export const PermissionsProvider: React.FC = ({ children }) => {
const [permissions, setPermissions] = useState<Permissions>({
read: false,
write: false,
admin: false,
comment: false,
})
const { connectionState } = useConnectionContext()
const { permissionsLevel } = useEditorContext()
const anonymous = getMeta('ol-anonymous') as boolean | undefined
useEffect(() => {
if (permissionsLevel === 'readOnly') {
if (anonymous) {
setPermissions(permissionsMap.anonymous.readOnly)
} else {
setPermissions(permissionsMap.readOnly)
}
}
if (permissionsLevel === 'readAndWrite') {
if (permissions.admin) {
if (anonymous) {
setPermissions(permissionsMap.anonymous.owner)
} else {
setPermissions(permissionsMap.owner)
}
} else {
if (anonymous) {
setPermissions(permissionsMap.anonymous.readAndWrite)
} else {
setPermissions(permissionsMap.readAndWrite)
}
}
}
if (permissionsLevel === 'owner') {
if (anonymous) {
setPermissions(permissionsMap.anonymous.owner)
} else {
setPermissions(permissionsMap.owner)
}
}
}, [anonymous, permissions, permissionsLevel])
useEffect(() => {
if (connectionState.forceDisconnected) {
setPermissions(prevState => ({ ...prevState, write: false }))
}
}, [connectionState.forceDisconnected])
const value = useMemo<PermissionsContextValue>(
() => ({
permissions,
}),
[permissions]
)
return (
<PermissionsContext.Provider value={value}>
{children}
</PermissionsContext.Provider>
)
}
export function usePermissionsContext(): PermissionsContextValue {
const context = useContext(PermissionsContext)
if (!context) {
throw new Error(
'usePermissionsContext is only available inside PermissionsProvider'
)
}
return context
}
@@ -19,6 +19,7 @@ import { SplitTestProvider } from '@/shared/context/split-test-context'
import { ModalsContextProvider } from '@/features/ide-react/context/modals-context'
import { FileTreePathProvider } from '@/features/file-tree/contexts/file-tree-path'
import { UserSettingsProvider } from '@/shared/context/user-settings-context'
import { PermissionsProvider } from '@/features/ide-react/context/permissions-context'
export const ReactContextRoot: FC = ({ children }) => {
return (
@@ -33,25 +34,27 @@ export const ReactContextRoot: FC = ({ children }) => {
<ReferencesProvider>
<DetachProvider>
<EditorProvider>
<ProjectSettingsProvider>
<LayoutProvider>
<LocalCompileProvider>
<DetachCompileProvider>
<ChatProvider>
<ModalsContextProvider>
<EditorManagerProvider>
<OnlineUsersProvider>
<MetadataProvider>
{children}
</MetadataProvider>
</OnlineUsersProvider>
</EditorManagerProvider>
</ModalsContextProvider>
</ChatProvider>
</DetachCompileProvider>
</LocalCompileProvider>
</LayoutProvider>
</ProjectSettingsProvider>
<PermissionsProvider>
<ProjectSettingsProvider>
<LayoutProvider>
<LocalCompileProvider>
<DetachCompileProvider>
<ChatProvider>
<ModalsContextProvider>
<EditorManagerProvider>
<OnlineUsersProvider>
<MetadataProvider>
{children}
</MetadataProvider>
</OnlineUsersProvider>
</EditorManagerProvider>
</ModalsContextProvider>
</ChatProvider>
</DetachCompileProvider>
</LocalCompileProvider>
</LayoutProvider>
</ProjectSettingsProvider>
</PermissionsProvider>
</EditorProvider>
</DetachProvider>
</ReferencesProvider>
@@ -11,13 +11,13 @@ import { useLayoutContext } from '@/shared/context/layout-context'
import { useUserContext } from '@/shared/context/user-context'
import { useIdeReactContext } from '@/features/ide-react/context/ide-react-context'
import { useConnectionContext } from '@/features/ide-react/context/connection-context'
import { usePermissionsContext } from '@/features/ide-react/context/permissions-context'
import { debugConsole } from '@/utils/debugging'
import { useEditorContext } from '@/shared/context/editor-context'
import { getJSON, postJSON } from '@/infrastructure/fetch-json'
import ColorManager from '@/ide/colors/ColorManager'
// @ts-ignore
import RangesTracker from '@overleaf/ranges-tracker'
import { ReviewPanelStateReactIde } from '../types/review-panel-state'
import * as ReviewPanel from '../types/review-panel-state'
import {
ReviewPanelCommentThreadMessage,
@@ -28,6 +28,7 @@ import {
} from '../../../../../../../types/review-panel/review-panel'
import { UserId } from '../../../../../../../types/user'
import { PublicAccessLevel } from '../../../../../../../types/public-access-level'
import { ReviewPanelStateReactIde } from '../types/review-panel-state'
import {
DeepReadonly,
MergeAndOverride,
@@ -114,6 +115,8 @@ function useReviewPanelState(): ReviewPanelStateReactIde {
features: { trackChangesVisible, trackChanges },
} = project
const { isRestrictedTokenMember } = useEditorContext()
// TODO permissions to be removed from the review panel context. It currently acts just as a proxy.
const { permissions } = usePermissionsContext()
// TODO `currentDocument` and `currentDocumentId` should be get from `useEditorManagerContext()` but that makes tests fail
const [currentDocument] = useScopeValue<Document>('editor.sharejs_doc')
@@ -134,9 +137,6 @@ function useReviewPanelState(): ReviewPanelStateReactIde {
ReviewPanel.Value<'commentThreads'>
>({})
const [entries, setEntries] = useState<ReviewPanel.Value<'entries'>>({})
const [permissions] =
useScopeValue<ReviewPanel.Value<'permissions'>>('permissions')
const [users, setUsers] = useScopeValue<ReviewPanel.Value<'users'>>(
'users',
true
@@ -1,6 +1,6 @@
import { Emitter } from 'strict-event-emitter'
import { Project } from '../../../../types/project'
import { PermissionsLevel } from '@/features/ide-react/types/permissions-level'
import { PermissionsLevel } from '@/features/ide-react/types/permissions'
import { ShareJsDoc } from '@/features/ide-react/editor/share-js-doc'
import { GotoLineOptions } from '@/features/ide-react/types/goto-line-options'
import { CursorPosition } from '@/features/ide-react/types/cursor-position'
@@ -1 +0,0 @@
export type PermissionsLevel = 'owner' | 'readAndWrite' | 'readOnly'
@@ -0,0 +1,8 @@
export type Permissions = {
read: boolean
write: boolean
admin: boolean
comment: boolean
}
export type PermissionsLevel = 'owner' | 'readAndWrite' | 'readOnly'