From 0c462d45d1e857d479ac652746704676c6f44fc3 Mon Sep 17 00:00:00 2001 From: Brian Gough Date: Fri, 4 Jul 2025 12:26:38 +0100 Subject: [PATCH] Merge pull request #26815 from overleaf/bg-sp-hotfix-5-5-2 [CE/SP] Hotfix 5.5.2 GitOrigin-RevId: bcd409968ef0321dd1d8050553e7c9a02d3efdc4 --- server-ce/hotfix/5.5.2/Dockerfile | 22 +++ server-ce/hotfix/5.5.2/pr_25944.patch | 219 ++++++++++++++++++++++++++ server-ce/hotfix/5.5.2/pr_26637.patch | 86 ++++++++++ server-ce/hotfix/5.5.2/pr_26697.patch | 172 ++++++++++++++++++++ server-ce/hotfix/5.5.2/pr_26783.patch | 58 +++++++ 5 files changed, 557 insertions(+) create mode 100644 server-ce/hotfix/5.5.2/Dockerfile create mode 100644 server-ce/hotfix/5.5.2/pr_25944.patch create mode 100644 server-ce/hotfix/5.5.2/pr_26637.patch create mode 100644 server-ce/hotfix/5.5.2/pr_26697.patch create mode 100644 server-ce/hotfix/5.5.2/pr_26783.patch diff --git a/server-ce/hotfix/5.5.2/Dockerfile b/server-ce/hotfix/5.5.2/Dockerfile new file mode 100644 index 0000000000..db9d8f27ee --- /dev/null +++ b/server-ce/hotfix/5.5.2/Dockerfile @@ -0,0 +1,22 @@ +FROM sharelatex/sharelatex:5.5.1 + +# https://github.com/overleaf/internal/pull/25944 +# Removed changes to services/web/frontend/js/features/ide-redesign/components/rail.tsx due to incompatibility with 5.5.1 +COPY pr_25944.patch . +RUN patch -p1 < pr_25944.patch && rm pr_25944.patch + +# https://github.com/overleaf/internal/pull/26637 +# Removed changes to server-ce/test/create-and-compile-project.spec.ts and server-ce/test/helpers/compile.ts due to incompatibility with 5.5.1 +COPY pr_26637.patch . +RUN patch -p1 < pr_26637.patch && rm pr_26637.patch + +# https://github.com/overleaf/internal/pull/26783 +COPY pr_26783.patch . +RUN patch -p1 < pr_26783.patch && rm pr_26783.patch + +# https://github.com/overleaf/internal/pull/26697 +COPY pr_26697.patch . +RUN patch -p1 < pr_26697.patch && rm pr_26697.patch + +# Recompile frontend assets +RUN node genScript compile | bash diff --git a/server-ce/hotfix/5.5.2/pr_25944.patch b/server-ce/hotfix/5.5.2/pr_25944.patch new file mode 100644 index 0000000000..e3b9f54246 --- /dev/null +++ b/server-ce/hotfix/5.5.2/pr_25944.patch @@ -0,0 +1,219 @@ +diff --git a/services/web/frontend/js/features/review-panel-new/context/review-panel-providers.tsx b/services/web/frontend/js/features/review-panel-new/context/review-panel-providers.tsx +index 20e157dfee9..ad943772d0d 100644 +--- a/services/web/frontend/js/features/review-panel-new/context/review-panel-providers.tsx ++++ b/services/web/frontend/js/features/review-panel-new/context/review-panel-providers.tsx +@@ -4,10 +4,16 @@ import { ChangesUsersProvider } from './changes-users-context' + import { TrackChangesStateProvider } from './track-changes-state-context' + import { ThreadsProvider } from './threads-context' + import { ReviewPanelViewProvider } from './review-panel-view-context' ++import { useProjectContext } from '@/shared/context/project-context' + + export const ReviewPanelProviders: FC = ({ + children, + }) => { ++ const { features } = useProjectContext() ++ if (!features.trackChangesVisible) { ++ return children ++ } ++ + return ( + + +diff --git a/services/web/frontend/js/features/share-project-modal/components/add-collaborators.tsx b/services/web/frontend/js/features/share-project-modal/components/add-collaborators.tsx +index 8606fb11fad..e80fb037116 100644 +--- a/services/web/frontend/js/features/share-project-modal/components/add-collaborators.tsx ++++ b/services/web/frontend/js/features/share-project-modal/components/add-collaborators.tsx +@@ -176,24 +176,34 @@ export default function AddCollaborators({ readOnly }: { readOnly?: boolean }) { + ]) + + const privilegeOptions = useMemo(() => { +- return [ ++ const options: { ++ key: string ++ label: string ++ description?: string | null ++ }[] = [ + { + key: 'readAndWrite', + label: t('editor'), + }, +- { ++ ] ++ ++ if (features.trackChangesVisible) { ++ options.push({ + key: 'review', + label: t('reviewer'), + description: !features.trackChanges + ? t('comment_only_upgrade_for_track_changes') + : null, +- }, +- { +- key: 'readOnly', +- label: t('viewer'), +- }, +- ] +- }, [features.trackChanges, t]) ++ }) ++ } ++ ++ options.push({ ++ key: 'readOnly', ++ label: t('viewer'), ++ }) ++ ++ return options ++ }, [features.trackChanges, features.trackChangesVisible, t]) + + return ( + +diff --git a/services/web/frontend/js/features/share-project-modal/components/edit-member.tsx b/services/web/frontend/js/features/share-project-modal/components/edit-member.tsx +index 6d806968b12..9f24cddc4ad 100644 +--- a/services/web/frontend/js/features/share-project-modal/components/edit-member.tsx ++++ b/services/web/frontend/js/features/share-project-modal/components/edit-member.tsx +@@ -244,14 +244,22 @@ function SelectPrivilege({ + const { features } = useProjectContext() + + const privileges = useMemo( +- (): Privilege[] => [ +- { key: 'owner', label: t('make_owner') }, +- { key: 'readAndWrite', label: t('editor') }, +- { key: 'review', label: t('reviewer') }, +- { key: 'readOnly', label: t('viewer') }, +- { key: 'removeAccess', label: t('remove_access') }, +- ], +- [t] ++ (): Privilege[] => ++ features.trackChangesVisible ++ ? [ ++ { key: 'owner', label: t('make_owner') }, ++ { key: 'readAndWrite', label: t('editor') }, ++ { key: 'review', label: t('reviewer') }, ++ { key: 'readOnly', label: t('viewer') }, ++ { key: 'removeAccess', label: t('remove_access') }, ++ ] ++ : [ ++ { key: 'owner', label: t('make_owner') }, ++ { key: 'readAndWrite', label: t('editor') }, ++ { key: 'readOnly', label: t('viewer') }, ++ { key: 'removeAccess', label: t('remove_access') }, ++ ], ++ [features.trackChangesVisible, t] + ) + + const downgradedPseudoPrivilege: Privilege = { +diff --git a/services/web/frontend/js/features/source-editor/components/codemirror-editor.tsx b/services/web/frontend/js/features/source-editor/components/codemirror-editor.tsx +index c1808cbb301..4bdfe2682c8 100644 +--- a/services/web/frontend/js/features/source-editor/components/codemirror-editor.tsx ++++ b/services/web/frontend/js/features/source-editor/components/codemirror-editor.tsx +@@ -18,6 +18,7 @@ import { + } from './codemirror-context' + import MathPreviewTooltip from './math-preview-tooltip' + import { useToolbarMenuBarEditorCommands } from '@/features/ide-redesign/hooks/use-toolbar-menu-editor-commands' ++import { useProjectContext } from '@/shared/context/project-context' + + // TODO: remove this when definitely no longer used + export * from './codemirror-context' +@@ -67,6 +68,7 @@ function CodeMirrorEditor() { + + function CodeMirrorEditorComponents() { + useToolbarMenuBarEditorCommands() ++ const { features } = useProjectContext() + + return ( + +@@ -83,8 +85,8 @@ function CodeMirrorEditorComponents() { + + + +- +- ++ {features.trackChangesVisible && } ++ {features.trackChangesVisible && } + + {sourceEditorComponents.map( + ({ import: { default: Component }, path }) => ( +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 e70663683fc..c5d9f3d3e47 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 +@@ -14,6 +14,7 @@ import { LegacyTableDropdown } from './table-inserter-dropdown-legacy' + import { withinFormattingCommand } from '@/features/source-editor/utils/tree-operations/formatting' + import { isSplitTestEnabled } from '@/utils/splitTestUtils' + import { isMac } from '@/shared/utils/os' ++import { useProjectContext } from '@/shared/context/project-context' + + export const ToolbarItems: FC<{ + state: EditorState +@@ -31,6 +32,7 @@ export const ToolbarItems: FC<{ + const { t } = useTranslation() + const { toggleSymbolPalette, showSymbolPalette, writefullInstance } = + useEditorContext() ++ const { features } = useProjectContext() + const isActive = withinFormattingCommand(state) + + const symbolPaletteAvailable = getMeta('ol-symbolPaletteAvailable') +@@ -127,13 +129,15 @@ export const ToolbarItems: FC<{ + command={commands.wrapInHref} + icon="add_link" + /> +- ++ {features.trackChangesVisible && ( ++ ++ )} + ', function () { + removeChangeIds, + }, + }, ++ projectFeatures: { trackChangesVisible: true }, + }) + + cy.wrap(scope).as('scope') +@@ -626,7 +627,7 @@ describe(' for free users', function () { + function mountEditor(ownerId = USER_ID) { + const scope = mockScope(undefined, { + permissions: { write: true, trackedWrite: false, comment: true }, +- projectFeatures: { trackChanges: false }, ++ projectFeatures: { trackChanges: false, trackChangesVisible: true }, + projectOwner: { + _id: ownerId, + }, +diff --git a/services/web/test/frontend/features/share-project-modal/components/share-project-modal.test.jsx b/services/web/test/frontend/features/share-project-modal/components/share-project-modal.test.jsx +index b86207fb0f7..dfce8134d1c 100644 +--- a/services/web/test/frontend/features/share-project-modal/components/share-project-modal.test.jsx ++++ b/services/web/test/frontend/features/share-project-modal/components/share-project-modal.test.jsx +@@ -694,6 +694,7 @@ describe('', function () { + features: { + collaborators: 0, + compileGroup: 'standard', ++ trackChangesVisible: true, + }, + }, + }, +@@ -723,6 +724,7 @@ describe('', function () { + ...project, + features: { + collaborators: 1, ++ trackChangesVisible: true, + }, + members: [ + { diff --git a/server-ce/hotfix/5.5.2/pr_26637.patch b/server-ce/hotfix/5.5.2/pr_26637.patch new file mode 100644 index 0000000000..f2183723bf --- /dev/null +++ b/server-ce/hotfix/5.5.2/pr_26637.patch @@ -0,0 +1,86 @@ +diff --git a/services/clsi/app/js/LocalCommandRunner.js b/services/clsi/app/js/LocalCommandRunner.js +index ce274733585..aa62825443c 100644 +--- a/services/clsi/app/js/LocalCommandRunner.js ++++ b/services/clsi/app/js/LocalCommandRunner.js +@@ -54,6 +54,7 @@ module.exports = CommandRunner = { + cwd: directory, + env, + stdio: ['pipe', 'pipe', 'ignore'], ++ detached: true, + }) + + let stdout = '' +diff --git a/services/clsi/test/acceptance/js/StopCompile.js b/services/clsi/test/acceptance/js/StopCompile.js +new file mode 100644 +index 00000000000..103a70f37d7 +--- /dev/null ++++ b/services/clsi/test/acceptance/js/StopCompile.js +@@ -0,0 +1,47 @@ ++const Client = require('./helpers/Client') ++const ClsiApp = require('./helpers/ClsiApp') ++const { expect } = require('chai') ++ ++describe('Stop compile', function () { ++ before(function (done) { ++ this.request = { ++ options: { ++ timeout: 100, ++ }, // seconds ++ resources: [ ++ { ++ path: 'main.tex', ++ content: `\ ++\\documentclass{article} ++\\begin{document} ++\\def\\x{Hello!\\par\\x} ++\\x ++\\end{document}\ ++`, ++ }, ++ ], ++ } ++ this.project_id = Client.randomId() ++ ClsiApp.ensureRunning(() => { ++ // start the compile in the background ++ Client.compile(this.project_id, this.request, (error, res, body) => { ++ this.compileResult = { error, res, body } ++ }) ++ // wait for 1 second before stopping the compile ++ setTimeout(() => { ++ Client.stopCompile(this.project_id, (error, res, body) => { ++ this.stopResult = { error, res, body } ++ setTimeout(done, 1000) // allow time for the compile request to terminate ++ }) ++ }, 1000) ++ }) ++ }) ++ ++ it('should force a compile response with an error status', function () { ++ expect(this.stopResult.error).to.be.null ++ expect(this.stopResult.res.statusCode).to.equal(204) ++ expect(this.compileResult.res.statusCode).to.equal(200) ++ expect(this.compileResult.body.compile.status).to.equal('terminated') ++ expect(this.compileResult.body.compile.error).to.equal('terminated') ++ }) ++}) +diff --git a/services/clsi/test/acceptance/js/helpers/Client.js b/services/clsi/test/acceptance/js/helpers/Client.js +index a0bdce734f3..49bf7390c6f 100644 +--- a/services/clsi/test/acceptance/js/helpers/Client.js ++++ b/services/clsi/test/acceptance/js/helpers/Client.js +@@ -42,6 +42,16 @@ module.exports = Client = { + ) + }, + ++ stopCompile(projectId, callback) { ++ if (callback == null) { ++ callback = function () {} ++ } ++ return request.post( ++ { url: `${this.host}/project/${projectId}/compile/stop` }, ++ callback ++ ) ++ }, ++ + clearCache(projectId, callback) { + if (callback == null) { + callback = function () {} diff --git a/server-ce/hotfix/5.5.2/pr_26697.patch b/server-ce/hotfix/5.5.2/pr_26697.patch new file mode 100644 index 0000000000..a6dd006d0a --- /dev/null +++ b/server-ce/hotfix/5.5.2/pr_26697.patch @@ -0,0 +1,172 @@ +diff --git a/services/web/frontend/js/features/project-list/components/project-list-ds-nav.tsx b/services/web/frontend/js/features/project-list/components/project-list-ds-nav.tsx +index 8f3b3a8e5d0..f8c8014e1c0 100644 +--- a/services/web/frontend/js/features/project-list/components/project-list-ds-nav.tsx ++++ b/services/web/frontend/js/features/project-list/components/project-list-ds-nav.tsx +@@ -55,7 +55,11 @@ export function ProjectListDsNav() { + + return ( +
+- ++ +
+ +
+diff --git a/services/web/frontend/js/features/ui/components/bootstrap-5/navbar/default-navbar.tsx b/services/web/frontend/js/features/ui/components/bootstrap-5/navbar/default-navbar.tsx +index 2480b7f061f..8e5429dbde6 100644 +--- a/services/web/frontend/js/features/ui/components/bootstrap-5/navbar/default-navbar.tsx ++++ b/services/web/frontend/js/features/ui/components/bootstrap-5/navbar/default-navbar.tsx +@@ -1,4 +1,4 @@ +-import { useState } from 'react' ++import React, { useState } from 'react' + import { sendMB } from '@/infrastructure/event-tracking' + import { useTranslation } from 'react-i18next' + import { Button, Container, Nav, Navbar } from 'react-bootstrap' +@@ -13,9 +13,15 @@ import MaterialIcon from '@/shared/components/material-icon' + import { useContactUsModal } from '@/shared/hooks/use-contact-us-modal' + import { UserProvider } from '@/shared/context/user-context' + import { X } from '@phosphor-icons/react' ++import overleafWhiteLogo from '@/shared/svgs/overleaf-white.svg' ++import overleafBlackLogo from '@/shared/svgs/overleaf-black.svg' ++import type { CSSPropertiesWithVariables } from '../../../../../../../types/css-properties-with-variables' + +-function DefaultNavbar(props: DefaultNavbarMetadata) { ++function DefaultNavbar( ++ props: DefaultNavbarMetadata & { overleafLogo?: string } ++) { + const { ++ overleafLogo, + customLogo, + title, + canDisplayAdminMenu, +@@ -49,10 +55,20 @@ function DefaultNavbar(props: DefaultNavbarMetadata) { + className="navbar-default navbar-main" + expand="lg" + onToggle={expanded => setExpanded(expanded)} ++ style={ ++ { ++ '--navbar-brand-image-default-url': `url("${overleafWhiteLogo}")`, ++ '--navbar-brand-image-redesign-url': `url("${overleafBlackLogo}")`, ++ } as CSSPropertiesWithVariables ++ } + > + +
+- ++ + {enableUpgradeButton ? ( +