mirror of
https://github.com/overleaf/overleaf.git
synced 2024-11-21 20:47:08 -05:00
Use permissions.write for editor editable state (#16011)
GitOrigin-RevId: b38ce53fa90a739d9e38ddcc57b01dfa0d9a104c
This commit is contained in:
parent
e46decbbcf
commit
18ad44c278
7 changed files with 62 additions and 92 deletions
|
@ -49,6 +49,12 @@ function populateIdeReactScope(store: ReactScopeValueStore) {
|
|||
function populateProjectScope(store: ReactScopeValueStore) {
|
||||
store.allowNonExistentPath('project', true)
|
||||
store.set('permissionsLevel', 'readOnly')
|
||||
store.set('permissions', {
|
||||
read: true,
|
||||
write: false,
|
||||
admin: false,
|
||||
comment: true,
|
||||
})
|
||||
}
|
||||
|
||||
function populatePdfScope(store: ReactScopeValueStore) {
|
||||
|
|
|
@ -54,7 +54,7 @@ export const MetadataProvider: FC = ({ children }) => {
|
|||
const { socket } = useConnectionContext()
|
||||
const { onlineUsersCount } = useOnlineUsersContext()
|
||||
const { permissionsLevel } = useEditorContext()
|
||||
const { permissions } = usePermissionsContext()
|
||||
const permissions = usePermissionsContext()
|
||||
const { currentDocument } = useEditorManagerContext()
|
||||
const { showGenericMessageModal } = useModalsContext()
|
||||
|
||||
|
|
|
@ -1,110 +1,73 @@
|
|||
import { createContext, useContext, useState, useEffect, useMemo } from 'react'
|
||||
import { createContext, useContext, useEffect } 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'
|
||||
import {
|
||||
Permissions,
|
||||
PermissionsLevel,
|
||||
} from '@/features/ide-react/types/permissions'
|
||||
import useScopeValue from '@/shared/hooks/use-scope-value'
|
||||
import { DeepReadonly } from '../../../../../types/utils'
|
||||
|
||||
type PermissionsContextValue = {
|
||||
permissions: Permissions
|
||||
}
|
||||
const PermissionsContext = createContext<Permissions | undefined>(undefined)
|
||||
|
||||
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,
|
||||
const permissionsMap: DeepReadonly<Record<PermissionsLevel, Permissions>> = {
|
||||
readOnly: {
|
||||
read: true,
|
||||
write: false,
|
||||
admin: false,
|
||||
comment: false,
|
||||
})
|
||||
comment: true,
|
||||
},
|
||||
readAndWrite: {
|
||||
read: true,
|
||||
write: true,
|
||||
admin: false,
|
||||
comment: true,
|
||||
},
|
||||
owner: {
|
||||
read: true,
|
||||
write: true,
|
||||
admin: true,
|
||||
comment: true,
|
||||
},
|
||||
}
|
||||
|
||||
const anonymousPermissionsMap: typeof permissionsMap = {
|
||||
readOnly: { ...permissionsMap.readOnly, comment: false },
|
||||
readAndWrite: { ...permissionsMap.readAndWrite, comment: false },
|
||||
owner: { ...permissionsMap.owner, comment: false },
|
||||
}
|
||||
|
||||
export const PermissionsProvider: React.FC = ({ children }) => {
|
||||
const [permissions, setPermissions] =
|
||||
useScopeValue<Readonly<Permissions>>('permissions')
|
||||
const { connectionState } = useConnectionContext()
|
||||
const { permissionsLevel } = useEditorContext()
|
||||
const { permissionsLevel } = useEditorContext() as {
|
||||
permissionsLevel: PermissionsLevel
|
||||
}
|
||||
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])
|
||||
const activePermissionsMap = anonymous
|
||||
? anonymousPermissionsMap
|
||||
: permissionsMap
|
||||
setPermissions(activePermissionsMap[permissionsLevel])
|
||||
}, [anonymous, permissionsLevel, setPermissions])
|
||||
|
||||
useEffect(() => {
|
||||
if (connectionState.forceDisconnected) {
|
||||
setPermissions(prevState => ({ ...prevState, write: false }))
|
||||
}
|
||||
}, [connectionState.forceDisconnected])
|
||||
|
||||
const value = useMemo<PermissionsContextValue>(
|
||||
() => ({
|
||||
permissions,
|
||||
}),
|
||||
[permissions]
|
||||
)
|
||||
}, [connectionState.forceDisconnected, setPermissions])
|
||||
|
||||
return (
|
||||
<PermissionsContext.Provider value={value}>
|
||||
<PermissionsContext.Provider value={permissions}>
|
||||
{children}
|
||||
</PermissionsContext.Provider>
|
||||
)
|
||||
}
|
||||
|
||||
export function usePermissionsContext(): PermissionsContextValue {
|
||||
export function usePermissionsContext() {
|
||||
const context = useContext(PermissionsContext)
|
||||
|
||||
if (!context) {
|
||||
|
|
|
@ -129,7 +129,7 @@ function useReviewPanelState(): ReviewPanelStateReactIde {
|
|||
} = project
|
||||
const { isRestrictedTokenMember } = useEditorContext()
|
||||
// TODO permissions to be removed from the review panel context. It currently acts just as a proxy.
|
||||
const { permissions } = usePermissionsContext()
|
||||
const permissions = usePermissionsContext()
|
||||
const { showGenericMessageModal } = useModalsContext()
|
||||
const addCommentEmitter = useScopeEventEmitter('comment:start_adding')
|
||||
|
||||
|
|
|
@ -26,7 +26,6 @@ import { useIdeContext } from '../../../shared/context/ide-context'
|
|||
import { restoreScrollPosition } from '../extensions/scroll-position'
|
||||
import { setEditable } from '../extensions/editable'
|
||||
import { useFileTreeData } from '../../../shared/context/file-tree-data-context'
|
||||
import { useEditorContext } from '../../../shared/context/editor-context'
|
||||
import { setAutoPair } from '../extensions/auto-pair'
|
||||
import { setAutoComplete } from '../extensions/auto-complete'
|
||||
import { usePhrases } from './use-phrases'
|
||||
|
@ -51,7 +50,8 @@ function useCodeMirrorScope(view: EditorView) {
|
|||
const ide = useIdeContext()
|
||||
|
||||
const { fileTreeData } = useFileTreeData()
|
||||
const { permissionsLevel } = useEditorContext()
|
||||
|
||||
const [permissions] = useScopeValue<{ write: boolean }>('permissions')
|
||||
|
||||
// set up scope listeners
|
||||
|
||||
|
@ -240,7 +240,7 @@ function useCodeMirrorScope(view: EditorView) {
|
|||
}
|
||||
}, [view, fileTreeData])
|
||||
|
||||
const editableRef = useRef(permissionsLevel !== 'readOnly')
|
||||
const editableRef = useRef(permissions.write)
|
||||
|
||||
const { previewByPath } = useFileTreePathContext()
|
||||
|
||||
|
@ -317,9 +317,9 @@ function useCodeMirrorScope(view: EditorView) {
|
|||
}, [view, previewByPath])
|
||||
|
||||
useEffect(() => {
|
||||
editableRef.current = permissionsLevel !== 'readOnly'
|
||||
editableRef.current = permissions.write
|
||||
view.dispatch(setEditable(editableRef.current)) // the editor needs to be locked when there's a problem saving data
|
||||
}, [view, permissionsLevel])
|
||||
}, [view, permissions.write])
|
||||
|
||||
useEffect(() => {
|
||||
phrasesRef.current = phrases
|
||||
|
|
|
@ -13,7 +13,7 @@ const mountEditor = (
|
|||
props?: Omit<ComponentProps<typeof EditorProviders>, 'children' | 'scope'>
|
||||
) => {
|
||||
const scope = mockScope(content)
|
||||
scope.permissionsLevel = 'readOnly'
|
||||
scope.permissions.write = false
|
||||
scope.editor.showVisual = true
|
||||
|
||||
cy.mount(
|
||||
|
|
|
@ -227,6 +227,7 @@ describe('<CodeMirrorEditor/>', { scrollBehavior: false }, function () {
|
|||
it('does not allow typing to the document in read-only mode', function () {
|
||||
const scope = mockScope()
|
||||
scope.permissionsLevel = 'readOnly'
|
||||
scope.permissions.write = false
|
||||
|
||||
cy.mount(
|
||||
<Container>
|
||||
|
|
Loading…
Reference in a new issue