mirror of
https://github.com/overleaf/overleaf.git
synced 2024-11-21 20:47:08 -05:00
[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
This commit is contained in:
parent
7757d8d2ad
commit
d501bc4820
9 changed files with 184 additions and 1 deletions
|
@ -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,
|
err,
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
"also": "",
|
"also": "",
|
||||||
"anyone_with_link_can_edit": "",
|
"anyone_with_link_can_edit": "",
|
||||||
"anyone_with_link_can_view": "",
|
"anyone_with_link_can_view": "",
|
||||||
|
"approaching_compile_timeout_limit_upgrade_for_more_compile_time": "<0></0>",
|
||||||
"are_you_still_at": "",
|
"are_you_still_at": "",
|
||||||
"ask_proj_owner_to_upgrade_for_git_bridge": "",
|
"ask_proj_owner_to_upgrade_for_git_bridge": "",
|
||||||
"ask_proj_owner_to_upgrade_for_longer_compiles": "",
|
"ask_proj_owner_to_upgrade_for_longer_compiles": "",
|
||||||
|
|
|
@ -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 (
|
||||||
|
<div className="alert alert-success compile-time-warning" role="alert">
|
||||||
|
<Button
|
||||||
|
className="close"
|
||||||
|
data-dismiss="alert"
|
||||||
|
aria-label="Close"
|
||||||
|
onClick={closeWarning}
|
||||||
|
>
|
||||||
|
<span aria-hidden="true">×</span>
|
||||||
|
</Button>
|
||||||
|
<div>
|
||||||
|
<div className="warning-text">
|
||||||
|
<Trans
|
||||||
|
i18nKey="approaching_compile_timeout_limit_upgrade_for_more_compile_time"
|
||||||
|
// eslint-disable-next-line react/jsx-key
|
||||||
|
components={[<strong style={{ display: 'inline-block' }} />]}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="upgrade-prompt">
|
||||||
|
<Button bsStyle="primary" bsSize="sm" onClick={handleUpgradeClick}>
|
||||||
|
{t('upgrade')}
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default memo(CompileTimeWarning)
|
|
@ -1,5 +1,6 @@
|
||||||
import { memo, Suspense } from 'react'
|
import { memo, Suspense } from 'react'
|
||||||
import classNames from 'classnames'
|
import classNames from 'classnames'
|
||||||
|
import CompileTimeWarning from './compile-time-warning'
|
||||||
import PdfLogsViewer from './pdf-logs-viewer'
|
import PdfLogsViewer from './pdf-logs-viewer'
|
||||||
import PdfViewer from './pdf-viewer'
|
import PdfViewer from './pdf-viewer'
|
||||||
import LoadingSpinner from '../../../shared/components/loading-spinner'
|
import LoadingSpinner from '../../../shared/components/loading-spinner'
|
||||||
|
@ -15,6 +16,7 @@ function PdfPreviewPane() {
|
||||||
return (
|
return (
|
||||||
<div className={classes}>
|
<div className={classes}>
|
||||||
<PdfHybridPreviewToolbar />
|
<PdfHybridPreviewToolbar />
|
||||||
|
<CompileTimeWarning />
|
||||||
<Suspense fallback={<LoadingPreview />}>
|
<Suspense fallback={<LoadingPreview />}>
|
||||||
<div className="pdf-viewer">
|
<div className="pdf-viewer">
|
||||||
<PdfViewer />
|
<PdfViewer />
|
||||||
|
|
|
@ -48,11 +48,13 @@ export function DetachCompileProvider({ children }) {
|
||||||
setHasLintingError: _setHasLintingError,
|
setHasLintingError: _setHasLintingError,
|
||||||
setHighlights: _setHighlights,
|
setHighlights: _setHighlights,
|
||||||
setPosition: _setPosition,
|
setPosition: _setPosition,
|
||||||
|
setShowCompileTimeWarning: _setShowCompileTimeWarning,
|
||||||
setShowLogs: _setShowLogs,
|
setShowLogs: _setShowLogs,
|
||||||
toggleLogs: _toggleLogs,
|
toggleLogs: _toggleLogs,
|
||||||
setStopOnFirstError: _setStopOnFirstError,
|
setStopOnFirstError: _setStopOnFirstError,
|
||||||
setStopOnValidationError: _setStopOnValidationError,
|
setStopOnValidationError: _setStopOnValidationError,
|
||||||
showLogs: _showLogs,
|
showLogs: _showLogs,
|
||||||
|
showCompileTimeWarning: _showCompileTimeWarning,
|
||||||
showFasterCompilesFeedbackUI: _showFasterCompilesFeedbackUI,
|
showFasterCompilesFeedbackUI: _showFasterCompilesFeedbackUI,
|
||||||
stopOnFirstError: _stopOnFirstError,
|
stopOnFirstError: _stopOnFirstError,
|
||||||
stopOnValidationError: _stopOnValidationError,
|
stopOnValidationError: _stopOnValidationError,
|
||||||
|
@ -185,6 +187,12 @@ export function DetachCompileProvider({ children }) {
|
||||||
'detacher',
|
'detacher',
|
||||||
'detached'
|
'detached'
|
||||||
)
|
)
|
||||||
|
const [showCompileTimeWarning] = useDetachStateWatcher(
|
||||||
|
'showCompileTimeWarning',
|
||||||
|
_showCompileTimeWarning,
|
||||||
|
'detacher',
|
||||||
|
'detached'
|
||||||
|
)
|
||||||
const [showLogs] = useDetachStateWatcher(
|
const [showLogs] = useDetachStateWatcher(
|
||||||
'showLogs',
|
'showLogs',
|
||||||
_showLogs,
|
_showLogs,
|
||||||
|
@ -276,6 +284,12 @@ export function DetachCompileProvider({ children }) {
|
||||||
'detacher',
|
'detacher',
|
||||||
'detached'
|
'detached'
|
||||||
)
|
)
|
||||||
|
const setShowCompileTimeWarning = useDetachAction(
|
||||||
|
'setShowCompileTimeWarning',
|
||||||
|
_setShowCompileTimeWarning,
|
||||||
|
'detached',
|
||||||
|
'detacher'
|
||||||
|
)
|
||||||
const setShowLogs = useDetachAction(
|
const setShowLogs = useDetachAction(
|
||||||
'setShowLogs',
|
'setShowLogs',
|
||||||
_setShowLogs,
|
_setShowLogs,
|
||||||
|
@ -376,11 +390,13 @@ export function DetachCompileProvider({ children }) {
|
||||||
setHasLintingError,
|
setHasLintingError,
|
||||||
setHighlights,
|
setHighlights,
|
||||||
setPosition,
|
setPosition,
|
||||||
|
setShowCompileTimeWarning,
|
||||||
setShowLogs,
|
setShowLogs,
|
||||||
toggleLogs,
|
toggleLogs,
|
||||||
setStopOnFirstError,
|
setStopOnFirstError,
|
||||||
setStopOnValidationError,
|
setStopOnValidationError,
|
||||||
showLogs,
|
showLogs,
|
||||||
|
showCompileTimeWarning,
|
||||||
showFasterCompilesFeedbackUI,
|
showFasterCompilesFeedbackUI,
|
||||||
startCompile,
|
startCompile,
|
||||||
stopCompile,
|
stopCompile,
|
||||||
|
@ -425,10 +441,12 @@ export function DetachCompileProvider({ children }) {
|
||||||
setHasLintingError,
|
setHasLintingError,
|
||||||
setHighlights,
|
setHighlights,
|
||||||
setPosition,
|
setPosition,
|
||||||
|
setShowCompileTimeWarning,
|
||||||
setShowLogs,
|
setShowLogs,
|
||||||
toggleLogs,
|
toggleLogs,
|
||||||
setStopOnFirstError,
|
setStopOnFirstError,
|
||||||
setStopOnValidationError,
|
setStopOnValidationError,
|
||||||
|
showCompileTimeWarning,
|
||||||
showLogs,
|
showLogs,
|
||||||
showFasterCompilesFeedbackUI,
|
showFasterCompilesFeedbackUI,
|
||||||
startCompile,
|
startCompile,
|
||||||
|
|
|
@ -27,6 +27,9 @@ import { useIdeContext } from './ide-context'
|
||||||
import { useProjectContext } from './project-context'
|
import { useProjectContext } from './project-context'
|
||||||
import { useEditorContext } from './editor-context'
|
import { useEditorContext } from './editor-context'
|
||||||
import { buildFileList } from '../../features/pdf-preview/util/file-list'
|
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()
|
export const LocalCompileContext = createContext()
|
||||||
|
|
||||||
|
@ -57,10 +60,12 @@ export const CompileContextPropTypes = {
|
||||||
setHasLintingError: PropTypes.func.isRequired, // only for storybook
|
setHasLintingError: PropTypes.func.isRequired, // only for storybook
|
||||||
setHighlights: PropTypes.func.isRequired,
|
setHighlights: PropTypes.func.isRequired,
|
||||||
setPosition: PropTypes.func.isRequired,
|
setPosition: PropTypes.func.isRequired,
|
||||||
|
setShowCompileTimeWarning: PropTypes.func.isRequired,
|
||||||
setShowLogs: PropTypes.func.isRequired,
|
setShowLogs: PropTypes.func.isRequired,
|
||||||
toggleLogs: PropTypes.func.isRequired,
|
toggleLogs: PropTypes.func.isRequired,
|
||||||
setStopOnFirstError: PropTypes.func.isRequired,
|
setStopOnFirstError: PropTypes.func.isRequired,
|
||||||
setStopOnValidationError: PropTypes.func.isRequired,
|
setStopOnValidationError: PropTypes.func.isRequired,
|
||||||
|
showCompileTimeWarning: PropTypes.bool.isRequired,
|
||||||
showLogs: PropTypes.bool.isRequired,
|
showLogs: PropTypes.bool.isRequired,
|
||||||
showFasterCompilesFeedbackUI: PropTypes.bool.isRequired,
|
showFasterCompilesFeedbackUI: PropTypes.bool.isRequired,
|
||||||
stopOnFirstError: PropTypes.bool.isRequired,
|
stopOnFirstError: PropTypes.bool.isRequired,
|
||||||
|
@ -82,9 +87,21 @@ export function LocalCompileProvider({ children }) {
|
||||||
|
|
||||||
const { _id: projectId, rootDocId } = useProjectContext()
|
const { _id: projectId, rootDocId } = useProjectContext()
|
||||||
|
|
||||||
|
const { splitTestVariants } = useSplitTestContext()
|
||||||
|
|
||||||
// whether a compile is in progress
|
// whether a compile is in progress
|
||||||
const [compiling, setCompiling] = useState(false)
|
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
|
// the log entries parsed from the compile output log
|
||||||
const [logEntries, setLogEntries] = useScopeValueSetterOnly('pdf.logEntries')
|
const [logEntries, setLogEntries] = useScopeValueSetterOnly('pdf.logEntries')
|
||||||
|
|
||||||
|
@ -264,6 +281,31 @@ export function LocalCompileProvider({ children }) {
|
||||||
}
|
}
|
||||||
}, [compiledOnce, currentDoc, compiler])
|
}, [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
|
// handle the data returned from a compile request
|
||||||
// note: this should _only_ run when `data` changes,
|
// note: this should _only_ run when `data` changes,
|
||||||
// the other dependencies must all be static
|
// the other dependencies must all be static
|
||||||
|
@ -522,6 +564,8 @@ export function LocalCompileProvider({ children }) {
|
||||||
setHasLintingError, // only for stories
|
setHasLintingError, // only for stories
|
||||||
setHighlights,
|
setHighlights,
|
||||||
setPosition,
|
setPosition,
|
||||||
|
showCompileTimeWarning,
|
||||||
|
setShowCompileTimeWarning,
|
||||||
setShowLogs,
|
setShowLogs,
|
||||||
toggleLogs,
|
toggleLogs,
|
||||||
setStopOnFirstError,
|
setStopOnFirstError,
|
||||||
|
@ -570,8 +614,10 @@ export function LocalCompileProvider({ children }) {
|
||||||
setHasLintingError, // only for stories
|
setHasLintingError, // only for stories
|
||||||
setHighlights,
|
setHighlights,
|
||||||
setPosition,
|
setPosition,
|
||||||
|
setShowCompileTimeWarning,
|
||||||
setStopOnFirstError,
|
setStopOnFirstError,
|
||||||
setStopOnValidationError,
|
setStopOnValidationError,
|
||||||
|
showCompileTimeWarning,
|
||||||
showLogs,
|
showLogs,
|
||||||
showFasterCompilesFeedbackUI,
|
showFasterCompilesFeedbackUI,
|
||||||
startCompile,
|
startCompile,
|
||||||
|
|
|
@ -743,3 +743,36 @@ CodeMirror
|
||||||
.editor-container {
|
.editor-container {
|
||||||
overflow: visible !important;
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
@ol-green: #138a07;
|
@ol-green: #138a07;
|
||||||
@ol-type-green: #107206;
|
@ol-type-green: #107206;
|
||||||
@ol-dark-green: #004a0e;
|
@ol-dark-green: #004a0e;
|
||||||
|
@ol-darker-green: #083c03;
|
||||||
@ol-blue: #3e70bb;
|
@ol-blue: #3e70bb;
|
||||||
@ol-dark-blue: #2857a1;
|
@ol-dark-blue: #2857a1;
|
||||||
@ol-red: #c9453e;
|
@ol-red: #c9453e;
|
||||||
|
|
|
@ -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</0>.",
|
"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</0>.",
|
||||||
"would_you_like_to_see_a_university_subscription": "Would you like to see a university-wide __appName__ subscription at your university?",
|
"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.",
|
"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 <strong>Overleaf Premium</strong> for <0>4x more</0> compile time."
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue