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 features0>.",
"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 more0> compile time."
}