From 826192f4fb7b0efeb30f5fe1f87438a7745fba62 Mon Sep 17 00:00:00 2001 From: Domagoj Kriskovic Date: Mon, 28 Jul 2025 11:50:27 +0200 Subject: [PATCH] Ensure add comment tooltip doesnt show up without comment permissions (#27273) * Ensure add comment tooltip doesnt show up without comment permissions * disable comment option when no permissions in new editor * add e2e tests * use server pro for project sharing * use findByRole for add comment * remove .only GitOrigin-RevId: fbef78e0db7678a00d6c602069e16ddeaf23b2f3 --- server-ce/test/project-sharing.spec.ts | 51 ++++++++++++++++--- .../use-toolbar-menu-editor-commands.tsx | 5 +- .../components/review-tooltip-menu.tsx | 10 ++-- .../components/toolbar/toolbar-items.tsx | 4 +- 4 files changed, 56 insertions(+), 14 deletions(-) diff --git a/server-ce/test/project-sharing.spec.ts b/server-ce/test/project-sharing.spec.ts index 4da2209332..3971a4f481 100644 --- a/server-ce/test/project-sharing.spec.ts +++ b/server-ce/test/project-sharing.spec.ts @@ -14,9 +14,9 @@ import { throttledRecompile } from './helpers/compile' import { beforeWithReRunOnTestRetry } from './helpers/beforeWithReRunOnTestRetry' describe('Project Sharing', function () { - if (isExcludedBySharding('CE_CUSTOM_2')) return + if (isExcludedBySharding('PRO_CUSTOM_2')) return ensureUserExists({ email: 'user@example.com' }) - startWith({ withDataDir: true }) + startWith({ withDataDir: true, pro: true }) let projectName: string beforeWithReRunOnTestRetry(function () { @@ -135,22 +135,57 @@ describe('Project Sharing', function () { cy.findByText('History').should('not.exist') } + function expectCommentAccess() { + cy.findByRole('textbox', { name: /Source Editor editing/i }).should( + 'contain.text', + '\\maketitle' + ) + + cy.findByText('\\maketitle').parent().dblclick() + + cy.findByRole('button', { name: 'Add comment' }).should('be.visible') + + cy.findByRole('textbox', { name: /Source Editor editing/i }).click() + } + + function expectNoCommentAccess() { + cy.findByRole('textbox', { name: /Source Editor editing/i }).should( + 'contain.text', + '\\maketitle' + ) + + cy.findByText('\\maketitle').parent().dblclick() + + cy.findByRole('button', { name: 'Add comment' }).should('not.exist') + cy.findByRole('textbox', { name: /Source Editor editing/i }).click() + } + function expectFullReadOnlyAccess() { expectContentReadOnlyAccess() expectChatAccess() expectHistoryAccess() + expectNoCommentAccess() } function expectRestrictedReadOnlyAccess() { expectContentReadOnlyAccess() expectNoChatAccess() expectNoHistoryAccess() + expectNoCommentAccess() } - function expectReadAndWriteAccess() { + function expectFullReadAndWriteAccess() { expectContentWriteAccess() expectChatAccess() expectHistoryAccess() + expectCommentAccess() + } + + function expectAnonymousReadAndWriteAccess() { + expectContentWriteAccess() + expectChatAccess() + expectHistoryAccess() + expectNoCommentAccess() } function expectProjectDashboardEntry() { @@ -209,7 +244,7 @@ describe('Project Sharing', function () { it('should grant the collaborator write access', () => { login(email) openProjectByName(projectName) - expectReadAndWriteAccess() + expectFullReadAndWriteAccess() expectEditAuthoredAs('You') expectProjectDashboardEntry() }) @@ -244,7 +279,7 @@ describe('Project Sharing', function () { projectName, email ) - expectReadAndWriteAccess() + expectFullReadAndWriteAccess() expectEditAuthoredAs('You') expectProjectDashboardEntry() }) @@ -254,6 +289,7 @@ describe('Project Sharing', function () { describe('with OVERLEAF_ALLOW_PUBLIC_ACCESS=false', () => { describe('wrap startup', () => { startWith({ + pro: true, vars: { OVERLEAF_ALLOW_PUBLIC_ACCESS: 'false', }, @@ -266,6 +302,7 @@ describe('Project Sharing', function () { describe('with OVERLEAF_ALLOW_ANONYMOUS_READ_AND_WRITE_SHARING=true', () => { startWith({ + pro: true, vars: { OVERLEAF_ALLOW_PUBLIC_ACCESS: 'false', OVERLEAF_ALLOW_ANONYMOUS_READ_AND_WRITE_SHARING: 'true', @@ -281,6 +318,7 @@ describe('Project Sharing', function () { describe('with OVERLEAF_ALLOW_PUBLIC_ACCESS=true', () => { describe('wrap startup', () => { startWith({ + pro: true, vars: { OVERLEAF_ALLOW_PUBLIC_ACCESS: 'true', }, @@ -299,6 +337,7 @@ describe('Project Sharing', function () { describe('with OVERLEAF_ALLOW_ANONYMOUS_READ_AND_WRITE_SHARING=true', () => { startWith({ + pro: true, vars: { OVERLEAF_ALLOW_PUBLIC_ACCESS: 'true', OVERLEAF_ALLOW_ANONYMOUS_READ_AND_WRITE_SHARING: 'true', @@ -313,7 +352,7 @@ describe('Project Sharing', function () { it('should grant write access with write link', () => { openProjectViaLinkSharingAsAnon(linkSharingReadAndWrite) - expectReadAndWriteAccess() + expectAnonymousReadAndWriteAccess() expectEditAuthoredAs('Anonymous') }) }) diff --git a/services/web/frontend/js/features/ide-redesign/hooks/use-toolbar-menu-editor-commands.tsx b/services/web/frontend/js/features/ide-redesign/hooks/use-toolbar-menu-editor-commands.tsx index ba96d049f8..a7211d06ca 100644 --- a/services/web/frontend/js/features/ide-redesign/hooks/use-toolbar-menu-editor-commands.tsx +++ b/services/web/frontend/js/features/ide-redesign/hooks/use-toolbar-menu-editor-commands.tsx @@ -23,7 +23,7 @@ export const useToolbarMenuBarEditorCommands = () => { const { t } = useTranslation() const { view: layoutView } = useLayoutContext() const editorIsVisible = layoutView === 'editor' - const { trackedWrite } = usePermissionsContext() + const { trackedWrite, comment } = usePermissionsContext() const languageName = state.facet(language)?.name const isTeXFile = languageName === 'latex' @@ -177,7 +177,7 @@ export const useToolbarMenuBarEditorCommands = () => { handler: () => { commands.addComment() }, - disabled: state.selection.main.empty, + disabled: !comment || state.selection.main.empty, }, /************************************ * Format menu @@ -288,6 +288,7 @@ export const useToolbarMenuBarEditorCommands = () => { trackedWrite, isTeXFile, state.selection.main.empty, + comment, ]) const { toggleSymbolPalette } = useEditorPropertiesContext() diff --git a/services/web/frontend/js/features/review-panel-new/components/review-tooltip-menu.tsx b/services/web/frontend/js/features/review-panel-new/components/review-tooltip-menu.tsx index f26542ebe9..fb6b68460b 100644 --- a/services/web/frontend/js/features/review-panel-new/components/review-tooltip-menu.tsx +++ b/services/web/frontend/js/features/review-panel-new/components/review-tooltip-menu.tsx @@ -18,7 +18,6 @@ import { reviewTooltipStateField, } from '@/features/source-editor/extensions/review-tooltip' import { EditorView, getTooltip } from '@codemirror/view' -import useViewerPermissions from '@/shared/hooks/use-viewer-permissions' import usePreviousValue from '@/shared/hooks/use-previous-value' import { useLayoutContext } from '@/shared/context/layout-context' import { useReviewPanelViewActionsContext } from '../context/review-panel-view-context' @@ -35,6 +34,7 @@ import { useEditorPropertiesContext } from '@/features/ide-react/context/editor- import classNames from 'classnames' import useEventListener from '@/shared/hooks/use-event-listener' import useReviewPanelLayout from '../hooks/use-review-panel-layout' +import { usePermissionsContext } from '@/features/ide-react/context/permissions-context' const EDIT_MODE_SWITCH_WIDGET_HEIGHT = 40 const CM_LINE_RIGHT_PADDING = 8 @@ -43,7 +43,7 @@ const TOOLTIP_SHOW_DELAY = 120 const ReviewTooltipMenu: FC = () => { const state = useCodeMirrorStateContext() const view = useCodeMirrorViewContext() - const isViewer = useViewerPermissions() + const permissions = usePermissionsContext() const [show, setShow] = useState(true) const { setView } = useReviewPanelViewActionsContext() const { openReviewPanel } = useReviewPanelLayout() @@ -58,7 +58,7 @@ const ReviewTooltipMenu: FC = () => { const addComment = useCallback(() => { const { main } = view.state.selection - if (main.empty) { + if (main.empty || !permissions.comment) { return } @@ -74,11 +74,11 @@ const ReviewTooltipMenu: FC = () => { view.dispatch({ effects }) setShow(false) - }, [openReviewPanel, setView, setShow, view]) + }, [view, permissions.comment, openReviewPanel, setView]) useEventListener('add-new-review-comment', addComment) - if (isViewer || !show || !tooltipState) { + if (!permissions.comment || !show || !tooltipState) { return null } diff --git a/services/web/frontend/js/features/source-editor/components/toolbar/toolbar-items.tsx b/services/web/frontend/js/features/source-editor/components/toolbar/toolbar-items.tsx index 3404976d44..1811ccc999 100644 --- a/services/web/frontend/js/features/source-editor/components/toolbar/toolbar-items.tsx +++ b/services/web/frontend/js/features/source-editor/components/toolbar/toolbar-items.tsx @@ -16,6 +16,7 @@ import { isSplitTestEnabled } from '@/utils/splitTestUtils' import { isMac } from '@/shared/utils/os' import { useProjectContext } from '@/shared/context/project-context' import { useEditorPropertiesContext } from '@/features/ide-react/context/editor-properties-context' +import { usePermissionsContext } from '@/features/ide-react/context/permissions-context' export const ToolbarItems: FC<{ state: EditorState @@ -35,6 +36,7 @@ export const ToolbarItems: FC<{ useEditorPropertiesContext() const { writefullInstance } = useEditorContext() const { features } = useProjectContext() + const permissions = usePermissionsContext() const isActive = withinFormattingCommand(state) const symbolPaletteAvailable = getMeta('ol-symbolPaletteAvailable') @@ -131,7 +133,7 @@ export const ToolbarItems: FC<{ command={commands.wrapInHref} icon="add_link" /> - {features.trackChangesVisible && ( + {features.trackChangesVisible && permissions.comment && (