Tearing down "paywall-change-compile-timeout" (#26741)

* removing the split test

* removing translations

* removing comments

* removing odcRole

GitOrigin-RevId: 8654876a6d97c52058fe9416f4495845d1320765
This commit is contained in:
Davinder Singh
2025-07-10 08:06:10 +00:00
committed by Copybot
parent 97d2954cc0
commit 8adc7526d9
8 changed files with 6 additions and 397 deletions
@@ -43,7 +43,6 @@ const ProjectAuditLogHandler = require('./ProjectAuditLogHandler')
const PublicAccessLevels = require('../Authorization/PublicAccessLevels')
const TagsHandler = require('../Tags/TagsHandler')
const TutorialHandler = require('../Tutorial/TutorialHandler')
const OnboardingDataCollectionManager = require('../OnboardingDataCollection/OnboardingDataCollectionManager')
const UserUpdater = require('../User/UserUpdater')
const Modules = require('../../infrastructure/Modules')
const UserGetter = require('../User/UserGetter')
@@ -349,7 +348,6 @@ const _ProjectController = {
!anonymous && 'writefull-oauth-promotion',
'hotjar',
'editor-redesign',
'paywall-change-compile-timeout',
'overleaf-assist-bundle',
'word-count-client',
'editor-popup-ux-survey',
@@ -404,13 +402,6 @@ const _ProjectController = {
userId,
projectId
),
odcRole: OnboardingDataCollectionManager.getOnboardingDataValue(
userId,
'role'
).catch(err => {
logger.error({ err, userId })
return null
}),
})
)
const splitTestAssignments = {}
@@ -463,7 +454,6 @@ const _ProjectController = {
subscription,
isTokenMember,
isInvitedMember,
odcRole,
} = userValues
const brandVariation = project?.brandVariationId
@@ -745,14 +735,6 @@ const _ProjectController = {
fullFeatureSet = await UserGetter.promises.getUserFeatures(userId)
}
const isPaywallChangeCompileTimeoutEnabled =
splitTestAssignments['paywall-change-compile-timeout']?.variant ===
'enabled'
const paywallPlans =
isPaywallChangeCompileTimeoutEnabled &&
(await ProjectController._getPaywallPlansPrices(req, res))
const customerIoEnabled =
await SplitTestHandler.promises.hasUserBeenAssignedToVariant(
req,
@@ -873,17 +855,9 @@ const _ProjectController = {
fixedSizeDocument: true,
hasTrackChangesFeature: Features.hasFeature('track-changes'),
projectTags,
odcRole:
// only use the ODC role value if the split test is enabled
splitTestAssignments['paywall-change-compile-timeout']?.variant ===
'enabled'
? odcRole
: null,
isSaas: Features.hasFeature('saas'),
shouldLoadHotjar: splitTestAssignments.hotjar?.variant === 'enabled',
isPaywallChangeCompileTimeoutEnabled,
isOverleafAssistBundleEnabled,
paywallPlans,
customerIoEnabled,
addonPrices,
compileSettings: {
@@ -40,13 +40,8 @@ meta(name="ol-projectTags" data-type="json" content=projectTags)
meta(name="ol-ro-mirror-on-client-no-local-storage" data-type="boolean" content=roMirrorOnClientNoLocalStorage)
meta(name="ol-isSaas" data-type="boolean" content=isSaas)
meta(name="ol-shouldLoadHotjar" data-type="boolean" content=shouldLoadHotjar)
meta(name="ol-odcRole" data-type="string" content=odcRole)
meta(name="ol-isPaywallChangeCompileTimeoutEnabled" data-type="boolean" content=isPaywallChangeCompileTimeoutEnabled)
meta(name='ol-customerIoEnabled' data-type="boolean" content=customerIoEnabled)
meta(name='ol-compileSettings' data-type="json" content=compileSettings)
if(isPaywallChangeCompileTimeoutEnabled)
//- expose plans info to show prices in paywall-change-compile-timeout test
meta(name="ol-paywallPlans", data-type="json" content=paywallPlans)
if(isOverleafAssistBundleEnabled)
//- expose plans info to show prices in paywall-change-compile-timeout test
meta(name="ol-addonPrices", data-type="json" content=addonPrices)
@@ -523,7 +523,6 @@
"enable_single_sign_on": "",
"enable_sso": "",
"enable_stop_on_first_error_under_recompile_dropdown_menu": "",
"enable_stop_on_first_error_under_recompile_dropdown_menu_v2": "",
"enabled": "",
"enables_real_time_syntax_checking_in_the_editor": "",
"enabling": "",
@@ -898,7 +897,6 @@
"language": "",
"language_suggestions": "",
"large_or_high-resolution_images_taking_too_long": "",
"large_or_high_resolution_images_taking_too_long_to_process": "",
"last_active": "",
"last_active_description": "",
"last_edit": "",
@@ -921,7 +919,6 @@
"learn_more": "",
"learn_more_about": "",
"learn_more_about_account": "",
"learn_more_about_compile_timeouts": "",
"learn_more_about_link_sharing": "",
"learn_more_about_managed_users": "",
"learn_more_about_other_causes_of_compile_timeouts": "",
@@ -1296,7 +1293,6 @@
"professional": "",
"progress_bar_percentage": "",
"project_approaching_file_limit": "",
"project_failed_to_compile": "",
"project_figure_modal": "",
"project_files": "",
"project_flagged_too_many_compiles": "",
@@ -1805,7 +1801,6 @@
"this_project_has_more_than_max_collabs": "",
"this_project_is_public": "",
"this_project_is_public_read_only": "",
"this_project_need_more_time_to_compile": "",
"this_project_will_appear_in_your_dropbox_folder_at": "",
"this_tool_helps_you_insert_figures": "",
"this_tool_helps_you_insert_simple_tables_into_your_project_without_writing_latex_code_give_feedback": "",
@@ -1990,7 +1985,6 @@
"upgrade_to_add_more_collaborators_and_access_collaboration_features": "",
"upgrade_to_get_feature": "",
"upgrade_to_review": "",
"upgrade_to_unlock_more_time": "",
"upgrade_your_subscription": "",
"upload": "",
"upload_file": "",
@@ -2195,7 +2189,6 @@
"your_project_exceeded_collaborator_limit": "",
"your_project_exceeded_compile_timeout_limit_on_free_plan": "",
"your_project_near_compile_timeout_limit": "",
"your_project_need_more_time_to_compile": "",
"your_projects": "",
"your_role": "",
"your_subscription": "",
@@ -1,5 +1,5 @@
import { useTranslation } from 'react-i18next'
import { memo, useState } from 'react'
import { memo } from 'react'
import classnames from 'classnames'
import PdfValidationIssue from './pdf-validation-issue'
import StopOnFirstErrorPrompt from './stop-on-first-error-prompt'
@@ -14,7 +14,6 @@ import PdfCodeCheckFailedNotice from './pdf-code-check-failed-notice'
import { useDetachCompileContext as useCompileContext } from '../../../shared/context/detach-compile-context'
import PdfLogEntry from './pdf-log-entry'
import { usePdfPreviewContext } from '@/features/pdf-preview/components/pdf-preview-provider'
import TimeoutUpgradePaywallPrompt from './timeout-upgrade-paywall-prompt'
import getMeta from '@/utils/meta'
function PdfLogsViewer({ alwaysVisible = false }: { alwaysVisible?: boolean }) {
@@ -26,7 +25,6 @@ function PdfLogsViewer({ alwaysVisible = false }: { alwaysVisible?: boolean }) {
validationIssues,
showLogs,
stoppedOnFirstError,
isProjectOwner,
} = useCompileContext()
const { loadingError } = usePdfPreviewContext()
@@ -35,17 +33,6 @@ function PdfLogsViewer({ alwaysVisible = false }: { alwaysVisible?: boolean }) {
const { t } = useTranslation()
const [
isShowingPrimaryCompileTimeoutPaywall,
setIsShowingPrimaryCompileTimeoutPaywall,
] = useState(false)
const isPaywallChangeCompileTimeoutEnabled = getMeta(
'ol-isPaywallChangeCompileTimeoutEnabled'
)
const isCompileTimeoutPaywallDisplay =
isProjectOwner && isPaywallChangeCompileTimeoutEnabled
return (
<div
className={classnames('logs-pane', {
@@ -61,13 +48,7 @@ function PdfLogsViewer({ alwaysVisible = false }: { alwaysVisible?: boolean }) {
{loadingError && <PdfPreviewError error="pdf-viewer-loading-error" />}
{compileTimeout < 60 && error === 'timedout' ? (
isCompileTimeoutPaywallDisplay ? (
<TimeoutUpgradePaywallPrompt
setIsShowingPrimary={setIsShowingPrimaryCompileTimeoutPaywall}
/>
) : (
<TimeoutUpgradePromptNew />
)
<TimeoutUpgradePromptNew />
) : (
<>{error && <PdfPreviewError error={error} />}</>
)}
@@ -93,12 +74,10 @@ function PdfLogsViewer({ alwaysVisible = false }: { alwaysVisible?: boolean }) {
/>
)}
{!isShowingPrimaryCompileTimeoutPaywall && (
<div className="logs-pane-actions">
<PdfClearCacheButton />
<PdfDownloadFilesButton />
</div>
)}
<div className="logs-pane-actions">
<PdfClearCacheButton />
<PdfDownloadFilesButton />
</div>
</div>
</div>
)
@@ -1,212 +0,0 @@
import getMeta from '@/utils/meta'
import { Trans, useTranslation } from 'react-i18next'
import { memo, useMemo } from 'react'
import { useDetachCompileContext } from '@/shared/context/detach-compile-context'
import StartFreeTrialButton from '@/shared/components/start-free-trial-button'
import MaterialIcon from '@/shared/components/material-icon'
import * as eventTracking from '@/infrastructure/event-tracking'
import PdfLogEntry from './pdf-log-entry'
type TimeoutMessageProps = {
segmentation?: eventTracking.Segmentation
}
function TimeoutMessageAfterPaywallDismissal({
segmentation,
}: TimeoutMessageProps) {
const { lastCompileOptions, isProjectOwner } = useDetachCompileContext()
return (
<div className="website-redesign timeout-upgrade-paywall-prompt">
<CompileTimeout
isProjectOwner={isProjectOwner}
segmentation={segmentation}
/>
{getMeta('ol-ExposedSettings').enableSubscriptions && (
<PreventTimeoutHelpMessage
lastCompileOptions={lastCompileOptions}
segmentation={segmentation}
/>
)}
</div>
)
}
type CompileTimeoutProps = {
isProjectOwner: boolean
segmentation?: eventTracking.Segmentation
}
const CompileTimeout = memo(function CompileTimeout({
isProjectOwner,
segmentation,
}: CompileTimeoutProps) {
const { t } = useTranslation()
const eventSegmentation = useMemo(
() => ({
...segmentation,
'paywall-version': 'secondary',
}),
[segmentation]
)
return (
<PdfLogEntry
headerTitle={t('project_failed_to_compile')}
headerIcon={
<MaterialIcon
type="error"
className="log-entry-header-title"
size="2x"
unfilled
/>
}
formattedContent={
getMeta('ol-ExposedSettings').enableSubscriptions && (
<>
<p className="compile-timeout-message">
{isProjectOwner ? (
<div>
<p>{t('your_project_need_more_time_to_compile')}</p>
<p>{t('upgrade_to_unlock_more_time')}</p>
</div>
) : (
<div>
<p>{t('this_project_need_more_time_to_compile')}</p>
<p>{t('upgrade_to_unlock_more_time')}</p>
</div>
)}
</p>
{isProjectOwner === false && (
<Trans
i18nKey="tell_the_project_owner_and_ask_them_to_upgrade"
components={[
// eslint-disable-next-line react/jsx-key
<strong />,
]}
/>
)}
{isProjectOwner && (
<div className="log-entry-cta-container">
<StartFreeTrialButton
source="compile-timeout"
buttonProps={{ variant: 'secondary' }}
segmentation={eventSegmentation}
>
{t('try_for_free')}
</StartFreeTrialButton>
</div>
)}
</>
)
}
// @ts-ignore
entryAriaLabel={t('your_compile_timed_out')}
level="error"
/>
)
})
type PreventTimeoutHelpMessageProps = {
lastCompileOptions: any
segmentation?: eventTracking.Segmentation
}
const PreventTimeoutHelpMessage = memo(function PreventTimeoutHelpMessage({
lastCompileOptions,
segmentation,
}: PreventTimeoutHelpMessageProps) {
const { t } = useTranslation()
function sendInfoClickEvent() {
eventTracking.sendMB('paywall-info-click', {
'paywall-type': 'compile-timeout',
content: 'blog',
...segmentation,
})
}
const compileTimeoutChangesBlogLink = (
/* eslint-disable-next-line jsx-a11y/anchor-has-content, react/jsx-key */
<a
aria-label={t('read_more_about_free_compile_timeouts_servers')}
href="/blog/changes-to-free-compile-timeout"
rel="noopener noreferrer"
target="_blank"
onClick={sendInfoClickEvent}
/>
)
return (
<PdfLogEntry
headerTitle={t('reasons_for_compile_timeouts')}
formattedContent={
<>
{segmentation?.['10s-timeout-warning'] === 'enabled' && (
<p>
<em>
<Trans
i18nKey="were_reducing_compile_timeout"
components={[compileTimeoutChangesBlogLink]}
/>
</em>
</p>
)}
<p>{t('common_causes_of_compile_timeouts_include')}:</p>
<ul>
<li>
{t('large_or_high_resolution_images_taking_too_long_to_process')}
</li>
<li>
<Trans
i18nKey="a_fatal_compile_error_that_completely_blocks_compilation"
components={[
// eslint-disable-next-line jsx-a11y/anchor-has-content, react/jsx-key
<a
href="/learn/how-to/Fixing_and_preventing_compile_timeouts#Step_3:_Assess_your_project_for_time-consuming_tasks_and_fatal_errors"
rel="noopener noreferrer"
target="_blank"
/>,
]}
/>
{!lastCompileOptions.stopOnFirstError && (
<>
{' '}
<Trans
i18nKey="enable_stop_on_first_error_under_recompile_dropdown_menu_v2"
components={[
// eslint-disable-next-line react/jsx-key
<strong className="log-bold-text" />,
// eslint-disable-next-line react/jsx-key
<strong className="log-bold-text" />,
]}
/>{' '}
</>
)}
</li>
</ul>
<p className="mb-0">
<Trans
i18nKey="learn_more_about_compile_timeouts"
components={[
// eslint-disable-next-line jsx-a11y/anchor-has-content, react/jsx-key
<a
href="/learn/how-to/Fixing_and_preventing_compile_timeouts"
rel="noopener noreferrer"
target="_blank"
/>,
]}
/>
</p>
</>
}
// @ts-ignore
entryAriaLabel={t('reasons_for_compile_timeouts')}
level="raw"
/>
)
})
export default memo(TimeoutMessageAfterPaywallDismissal)
@@ -1,111 +0,0 @@
import {
Dispatch,
SetStateAction,
useCallback,
useEffect,
useMemo,
useState,
} from 'react'
import getMeta from '@/utils/meta'
import * as eventTracking from '@/infrastructure/event-tracking'
import TimeoutMessageAfterPaywallDismissal from './timeout-message-after-paywall-dismissal'
import { UpgradePrompt } from '@/shared/components/upgrade-prompt'
import { useDetachCompileContext } from '@/shared/context/detach-compile-context'
const studentRoles = [
'High-school student',
'Undergraduate student',
"Master's student (e.g. MSc, MA)",
'Doctoral student (e.g. PhD, MD, EngD)',
]
interface TimeoutUpgradePaywallPromptProps {
setIsShowingPrimary?: Dispatch<SetStateAction<boolean>>
}
function TimeoutUpgradePaywallPrompt({
setIsShowingPrimary,
}: TimeoutUpgradePaywallPromptProps) {
const odcRole = getMeta('ol-odcRole')
const planPrices = getMeta('ol-paywallPlans')
const isStudent = useMemo(() => studentRoles.includes(odcRole), [odcRole])
const { isProjectOwner } = useDetachCompileContext()
const [isPaywallDismissed, setIsPaywallDismissed] = useState<boolean>(false)
const { reducedTimeoutWarning, compileTimeout } =
getMeta('ol-compileSettings')
const sharedSegmentation = useMemo(
() => ({
'10s-timeout-warning': reducedTimeoutWarning,
'is-owner': isProjectOwner,
compileTime: compileTimeout,
}),
[isProjectOwner, reducedTimeoutWarning, compileTimeout]
)
const sendPaywallEvent = useCallback(
(event: string, segmentation?: eventTracking.Segmentation) => {
eventTracking.sendMB(event, {
'paywall-type': 'compile-timeout',
'paywall-version': 'primary',
...sharedSegmentation,
...segmentation,
})
},
[sharedSegmentation]
)
function onClose() {
sendPaywallEvent('paywall-dismiss')
setIsPaywallDismissed(true)
if (setIsShowingPrimary) {
setIsShowingPrimary(false)
}
}
function onClickInfoLink() {
sendPaywallEvent('paywall-info-click', { content: 'plans' })
}
function onClickPaywall() {
sendPaywallEvent('paywall-click', {
plan: isStudent ? 'student' : 'collaborator',
})
}
useEffect(() => {
sendPaywallEvent('paywall-prompt', {
plan: isStudent ? 'student' : 'collaborator',
})
if (setIsShowingPrimary) {
setIsShowingPrimary(true)
}
}, [isStudent, setIsShowingPrimary, sendPaywallEvent])
return (
<div>
{!isPaywallDismissed ? (
<UpgradePrompt
title="Unlock more compile time"
summary="Your project took too long to compile and timed out."
onClose={onClose}
planPricing={{
student: planPrices?.student,
standard: planPrices?.collaborator,
}}
itmCampaign="compile-timeout"
isStudent={isStudent}
onClickInfoLink={onClickInfoLink}
onClickPaywall={onClickPaywall}
/>
) : (
<TimeoutMessageAfterPaywallDismissal
segmentation={sharedSegmentation}
/>
)}
</div>
)
}
export default TimeoutUpgradePaywallPrompt
-2
View File
@@ -146,7 +146,6 @@ export interface Meta {
'ol-isCollectionMethodManual': boolean
'ol-isExternalAuthenticationSystemUsed': boolean
'ol-isManagedAccount': boolean
'ol-isPaywallChangeCompileTimeoutEnabled': boolean
'ol-isProfessional': boolean
'ol-isRegisteredViaGoogle': boolean
'ol-isRestrictedTokenMember': boolean
@@ -180,7 +179,6 @@ export interface Meta {
'ol-notificationsInstitution': InstitutionType[]
'ol-oauthProviders': OAuthProviders
'ol-odcData': OnboardingFormData
'ol-odcRole': string
'ol-overallThemes': OverallThemeMeta[]
'ol-pages': number
'ol-passwordStrengthOptions': PasswordStrengthOptions
-7
View File
@@ -677,7 +677,6 @@
"enable_single_sign_on": "Enable single sign-on",
"enable_sso": "Enable SSO",
"enable_stop_on_first_error_under_recompile_dropdown_menu": "Enable <0>“Stop on first error”</0> under the <1>Recompile</1> drop-down menu to help you find and fix errors right away.",
"enable_stop_on_first_error_under_recompile_dropdown_menu_v2": "Enable <0>Stop on first error</0> under the <1>Recompile</1> drop-down menu to help you find and fix errors right away.",
"enabled": "Enabled",
"enables_real_time_syntax_checking_in_the_editor": "Enables real-time syntax checking in the editor",
"enabling": "Enabling",
@@ -1166,7 +1165,6 @@
"language": "Language",
"language_suggestions": "Language suggestions",
"large_or_high-resolution_images_taking_too_long": "Large or high-resolution images taking too long to process. You may be able to <0>optimize them</0>.",
"large_or_high_resolution_images_taking_too_long_to_process": "Large or high-resolution images taking too long to process.",
"last_active": "Last Active",
"last_active_description": "Last time a project was opened.",
"last_edit": "Last edit",
@@ -1201,7 +1199,6 @@
"learn_more": "Learn more",
"learn_more_about": "Learn more about __appName__",
"learn_more_about_account": "<0>Learn more</0> about managing your __appName__ account.",
"learn_more_about_compile_timeouts": "<0>Learn more</0> about compile timeouts.",
"learn_more_about_emails": "<0>Learn more</0> about managing your __appName__ emails.",
"learn_more_about_link_sharing": "Learn more about Link Sharing",
"learn_more_about_managed_users": "Learn more about Managed Users.",
@@ -1712,7 +1709,6 @@
"progress_bar_percentage": "Progress bar from 0 to 100%",
"project": "project",
"project_approaching_file_limit": "This project is approaching the file limit",
"project_failed_to_compile": "Your project failed to compile",
"project_figure_modal": "Project",
"project_files": "Project files",
"project_flagged_too_many_compiles": "This project has been flagged for compiling too often. The limit will be lifted shortly.",
@@ -2331,7 +2327,6 @@
"this_project_has_more_than_max_collabs": "This project has more than the maximum number of collaborators allowed on the project owners Overleaf plan. This means you could lose edit access from __linkSharingDate__.",
"this_project_is_public": "This project is public and can be edited by anyone with the URL.",
"this_project_is_public_read_only": "This project is public and can be viewed but not edited by anyone with the URL",
"this_project_need_more_time_to_compile": "It looks like this project may need more time to compile than our free plan allows.",
"this_project_will_appear_in_your_dropbox_folder_at": "This project will appear in your Dropbox folder at ",
"this_tool_helps_you_insert_figures": "This tool helps you insert figures into your project without needing to write the LaTeX code. The following information explains more about the options in the tool and how to further customize your figures.",
"this_tool_helps_you_insert_simple_tables_into_your_project_without_writing_latex_code_give_feedback": "This tool helps you insert simple tables into your project without writing LaTeX code. This tool is new, so please <0>give us feedback</0> and look out for additional functionality coming soon.",
@@ -2527,7 +2522,6 @@
"upgrade_to_add_more_collaborators_and_access_collaboration_features": "Upgrade to add more collaborators and access collaboration features like track changes and full project history.",
"upgrade_to_get_feature": "Upgrade to get __feature__, plus:",
"upgrade_to_review": "Upgrade to Review",
"upgrade_to_unlock_more_time": "Upgrade now to unlock 24x more compile time on our fastest servers.",
"upgrade_your_subscription": "Upgrade your subscription",
"upload": "Upload",
"upload_failed": "Upload failed",
@@ -2756,7 +2750,6 @@
"your_project_exceeded_collaborator_limit": "Your project exceeded the collaborator limit and access levels were changed. Select a new access level for your collaborators, or upgrade to add more editors or reviewers.",
"your_project_exceeded_compile_timeout_limit_on_free_plan": "Your project exceeded the compile timeout limit on our free plan.",
"your_project_near_compile_timeout_limit": "Your project is near the compile timeout limit for our free plan.",
"your_project_need_more_time_to_compile": "It looks like your project may need more time to compile than our free plan allows.",
"your_projects": "Your projects",
"your_questions_answered": "Your questions answered",
"your_role": "Your role",