From d501bc482024a7f0e6ba5e5a70743bca9506dbd8 Mon Sep 17 00:00:00 2001 From: Alexandre Bourdin Date: Wed, 13 Jul 2022 10:33:47 +0200 Subject: [PATCH] [web] Compile time warning split test (#8813) * Implement compile time warning split test * Add i18n for compile time warning * Memoize CompileTimeWarning component * Reuse startFreeTrial() function from account-upgrade * Improve usage of react bootstrap native properties * Cleanup compile-time-warning * Move all logic into CompileTimeWarning component * Only show compile time warning to project owners * Handle compile time warning in detached mode and while switching layout GitOrigin-RevId: 4fc40acfc113f91c81a6744c14c0f8b3ef766e39 --- .../src/Features/Project/ProjectController.js | 19 ++++++ .../web/frontend/extracted-translations.json | 1 + .../components/compile-time-warning.tsx | 62 +++++++++++++++++++ .../components/pdf-preview-pane.js | 2 + .../shared/context/detach-compile-context.js | 18 ++++++ .../shared/context/local-compile-context.js | 46 ++++++++++++++ .../web/frontend/stylesheets/app/editor.less | 33 ++++++++++ .../frontend/stylesheets/core/variables.less | 1 + services/web/locales/en.json | 3 +- 9 files changed, 184 insertions(+), 1 deletion(-) create mode 100644 services/web/frontend/js/features/pdf-preview/components/compile-time-warning.tsx diff --git a/services/web/app/src/Features/Project/ProjectController.js b/services/web/app/src/Features/Project/ProjectController.js index 936a7ec5da..0195926c44 100644 --- a/services/web/app/src/Features/Project/ProjectController.js +++ b/services/web/app/src/Features/Project/ProjectController.js @@ -949,6 +949,25 @@ const ProjectController = { } ) }, + compileTimeWarningAssignment: [ + 'user', + (results, cb) => { + if (results.user?.features?.compileTimeout <= 60) { + SplitTestHandler.getAssignment( + req, + res, + 'compile-time-warning', + {}, + () => { + // do not fail editor load if assignment fails + cb() + } + ) + } else { + cb() + } + }, + ], }, ( err, diff --git a/services/web/frontend/extracted-translations.json b/services/web/frontend/extracted-translations.json index 4234c8bfb7..11fc720261 100644 --- a/services/web/frontend/extracted-translations.json +++ b/services/web/frontend/extracted-translations.json @@ -10,6 +10,7 @@ "also": "", "anyone_with_link_can_edit": "", "anyone_with_link_can_view": "", + "approaching_compile_timeout_limit_upgrade_for_more_compile_time": "<0>", "are_you_still_at": "", "ask_proj_owner_to_upgrade_for_git_bridge": "", "ask_proj_owner_to_upgrade_for_longer_compiles": "", diff --git a/services/web/frontend/js/features/pdf-preview/components/compile-time-warning.tsx b/services/web/frontend/js/features/pdf-preview/components/compile-time-warning.tsx new file mode 100644 index 0000000000..57a801053e --- /dev/null +++ b/services/web/frontend/js/features/pdf-preview/components/compile-time-warning.tsx @@ -0,0 +1,62 @@ +import { memo, useCallback, useEffect } from 'react' +import { Button } from 'react-bootstrap' +import { Trans, useTranslation } from 'react-i18next' +import * as eventTracking from '../../../infrastructure/event-tracking' +import { useDetachCompileContext } from '../../../shared/context/detach-compile-context' +import { startFreeTrial } from '../../../main/account-upgrade' + +function CompileTimeWarning() { + const { t } = useTranslation() + + const { showCompileTimeWarning, setShowCompileTimeWarning } = + useDetachCompileContext() + + useEffect(() => { + if (showCompileTimeWarning) { + eventTracking.sendMB('compile-time-warning-displayed', {}) + } + }, [showCompileTimeWarning]) + + const closeWarning = () => { + eventTracking.sendMB('compile-time-warning-dismissed', {}) + setShowCompileTimeWarning(false) + } + + const handleUpgradeClick = useCallback(event => { + event.preventDefault() + startFreeTrial('compile-time-warning') + }, []) + + if (!showCompileTimeWarning) { + return null + } + + return ( +
+ +
+
+ ]} + /> +
+
+ +
+
+
+ ) +} + +export default memo(CompileTimeWarning) diff --git a/services/web/frontend/js/features/pdf-preview/components/pdf-preview-pane.js b/services/web/frontend/js/features/pdf-preview/components/pdf-preview-pane.js index 9ebfe92d0c..f4834ce105 100644 --- a/services/web/frontend/js/features/pdf-preview/components/pdf-preview-pane.js +++ b/services/web/frontend/js/features/pdf-preview/components/pdf-preview-pane.js @@ -1,5 +1,6 @@ import { memo, Suspense } from 'react' import classNames from 'classnames' +import CompileTimeWarning from './compile-time-warning' import PdfLogsViewer from './pdf-logs-viewer' import PdfViewer from './pdf-viewer' import LoadingSpinner from '../../../shared/components/loading-spinner' @@ -15,6 +16,7 @@ function PdfPreviewPane() { return (
+ }>
diff --git a/services/web/frontend/js/shared/context/detach-compile-context.js b/services/web/frontend/js/shared/context/detach-compile-context.js index 9ac8ac19d4..d2d043d130 100644 --- a/services/web/frontend/js/shared/context/detach-compile-context.js +++ b/services/web/frontend/js/shared/context/detach-compile-context.js @@ -48,11 +48,13 @@ export function DetachCompileProvider({ children }) { setHasLintingError: _setHasLintingError, setHighlights: _setHighlights, setPosition: _setPosition, + setShowCompileTimeWarning: _setShowCompileTimeWarning, setShowLogs: _setShowLogs, toggleLogs: _toggleLogs, setStopOnFirstError: _setStopOnFirstError, setStopOnValidationError: _setStopOnValidationError, showLogs: _showLogs, + showCompileTimeWarning: _showCompileTimeWarning, showFasterCompilesFeedbackUI: _showFasterCompilesFeedbackUI, stopOnFirstError: _stopOnFirstError, stopOnValidationError: _stopOnValidationError, @@ -185,6 +187,12 @@ export function DetachCompileProvider({ children }) { 'detacher', 'detached' ) + const [showCompileTimeWarning] = useDetachStateWatcher( + 'showCompileTimeWarning', + _showCompileTimeWarning, + 'detacher', + 'detached' + ) const [showLogs] = useDetachStateWatcher( 'showLogs', _showLogs, @@ -276,6 +284,12 @@ export function DetachCompileProvider({ children }) { 'detacher', 'detached' ) + const setShowCompileTimeWarning = useDetachAction( + 'setShowCompileTimeWarning', + _setShowCompileTimeWarning, + 'detached', + 'detacher' + ) const setShowLogs = useDetachAction( 'setShowLogs', _setShowLogs, @@ -376,11 +390,13 @@ export function DetachCompileProvider({ children }) { setHasLintingError, setHighlights, setPosition, + setShowCompileTimeWarning, setShowLogs, toggleLogs, setStopOnFirstError, setStopOnValidationError, showLogs, + showCompileTimeWarning, showFasterCompilesFeedbackUI, startCompile, stopCompile, @@ -425,10 +441,12 @@ export function DetachCompileProvider({ children }) { setHasLintingError, setHighlights, setPosition, + setShowCompileTimeWarning, setShowLogs, toggleLogs, setStopOnFirstError, setStopOnValidationError, + showCompileTimeWarning, showLogs, showFasterCompilesFeedbackUI, startCompile, diff --git a/services/web/frontend/js/shared/context/local-compile-context.js b/services/web/frontend/js/shared/context/local-compile-context.js index c00b7b6714..4ace5e3d9b 100644 --- a/services/web/frontend/js/shared/context/local-compile-context.js +++ b/services/web/frontend/js/shared/context/local-compile-context.js @@ -27,6 +27,9 @@ import { useIdeContext } from './ide-context' import { useProjectContext } from './project-context' import { useEditorContext } from './editor-context' import { buildFileList } from '../../features/pdf-preview/util/file-list' +import { useSplitTestContext } from './split-test-context' + +const ONE_DAY = 24 * 60 * 60 * 24 * 1000 export const LocalCompileContext = createContext() @@ -57,10 +60,12 @@ export const CompileContextPropTypes = { setHasLintingError: PropTypes.func.isRequired, // only for storybook setHighlights: PropTypes.func.isRequired, setPosition: PropTypes.func.isRequired, + setShowCompileTimeWarning: PropTypes.func.isRequired, setShowLogs: PropTypes.func.isRequired, toggleLogs: PropTypes.func.isRequired, setStopOnFirstError: PropTypes.func.isRequired, setStopOnValidationError: PropTypes.func.isRequired, + showCompileTimeWarning: PropTypes.bool.isRequired, showLogs: PropTypes.bool.isRequired, showFasterCompilesFeedbackUI: PropTypes.bool.isRequired, stopOnFirstError: PropTypes.bool.isRequired, @@ -82,9 +87,21 @@ export function LocalCompileProvider({ children }) { const { _id: projectId, rootDocId } = useProjectContext() + const { splitTestVariants } = useSplitTestContext() + // whether a compile is in progress const [compiling, setCompiling] = useState(false) + // whether to show the compile time warning + const [showCompileTimeWarning, setShowCompileTimeWarning] = useState(false) + + // the last time the compile time warning was displayed + const [lastDisplay, setLastDisplay] = usePersistedState( + 'compile-time-warning-displayed-at', + 0, + true + ) + // the log entries parsed from the compile output log const [logEntries, setLogEntries] = useScopeValueSetterOnly('pdf.logEntries') @@ -264,6 +281,31 @@ export function LocalCompileProvider({ children }) { } }, [compiledOnce, currentDoc, compiler]) + useEffect(() => { + const compileTimeWarningEnabled = + splitTestVariants['compile-time-warning'] === 'show-upgrade-prompt' + + if (compileTimeWarningEnabled && compiling && isProjectOwner) { + const timeout = window.setTimeout(() => { + if (lastDisplay && Date.now() - lastDisplay < ONE_DAY) { + return + } + setShowCompileTimeWarning(true) + setLastDisplay(Date.now()) + }, 30000) + + return () => { + window.clearTimeout(timeout) + } + } + }, [ + compiling, + isProjectOwner, + lastDisplay, + setLastDisplay, + splitTestVariants, + ]) + // handle the data returned from a compile request // note: this should _only_ run when `data` changes, // the other dependencies must all be static @@ -522,6 +564,8 @@ export function LocalCompileProvider({ children }) { setHasLintingError, // only for stories setHighlights, setPosition, + showCompileTimeWarning, + setShowCompileTimeWarning, setShowLogs, toggleLogs, setStopOnFirstError, @@ -570,8 +614,10 @@ export function LocalCompileProvider({ children }) { setHasLintingError, // only for stories setHighlights, setPosition, + setShowCompileTimeWarning, setStopOnFirstError, setStopOnValidationError, + showCompileTimeWarning, showLogs, showFasterCompilesFeedbackUI, startCompile, diff --git a/services/web/frontend/stylesheets/app/editor.less b/services/web/frontend/stylesheets/app/editor.less index a7755baae3..c80b719499 100644 --- a/services/web/frontend/stylesheets/app/editor.less +++ b/services/web/frontend/stylesheets/app/editor.less @@ -743,3 +743,36 @@ CodeMirror .editor-container { overflow: visible !important; } + +.compile-time-warning { + position: absolute; + right: @margin-sm; + top: @margin-xl; + padding: @padding-sm; + background-color: @ol-green; + width: 400px; + z-index: @zindex-popover; + box-shadow: 5px 5px 6px rgba(0, 0, 0, 0.3); + + .warning-text { + max-width: 300px; + padding-right: @alert-padding; + display: inline-block; + font-size: @font-size-small; + } + .upgrade-prompt { + display: inline-block; + position: absolute; + height: 100%; + top: @margin-lg; + right: 32px; + } + + button.btn { + background-color: @ol-darker-green; + + &.close { + background-color: @ol-green; + } + } +} diff --git a/services/web/frontend/stylesheets/core/variables.less b/services/web/frontend/stylesheets/core/variables.less index a739fe75f7..a7f98945eb 100644 --- a/services/web/frontend/stylesheets/core/variables.less +++ b/services/web/frontend/stylesheets/core/variables.less @@ -22,6 +22,7 @@ @ol-green: #138a07; @ol-type-green: #107206; @ol-dark-green: #004a0e; +@ol-darker-green: #083c03; @ol-blue: #3e70bb; @ol-dark-blue: #2857a1; @ol-red: #c9453e; diff --git a/services/web/locales/en.json b/services/web/locales/en.json index 7a8fff3208..e19f4a541b 100644 --- a/services/web/locales/en.json +++ b/services/web/locales/en.json @@ -1792,5 +1792,6 @@ "get_most_subscription_by_checking_premium_features": "Get the most out of your __appName__ subscription by checking out the list of <0>__appName__’s premium features.", "would_you_like_to_see_a_university_subscription": "Would you like to see a university-wide __appName__ subscription at your university?", "student_and_faculty_support_make_difference": "Student and faculty support make a difference! We can share this information with our contacts at your university when discussing an Overleaf institutional account.", - "show_your_support": "Show your support" + "show_your_support": "Show your support", + "approaching_compile_timeout_limit_upgrade_for_more_compile_time": "You are approaching your compile timeout limit. Upgrade to Overleaf Premium for <0>4x more compile time." }