Merge pull request #28050 from overleaf/dp-3-way-feature-flag

Add 3 way editor-redesign-new-users feature flag in preparation for new user split test

GitOrigin-RevId: adc1ce43277647208a2f0098bf9dcf2101a86f65
This commit is contained in:
David
2025-09-04 14:23:51 +01:00
committed by Copybot
parent 236065eb4a
commit 0eda16cb15
10 changed files with 75 additions and 25 deletions
@@ -379,8 +379,8 @@ const _ProjectController = {
'overleaf-assist-bundle',
'word-count-client',
'editor-popup-ux-survey',
'new-editor-error-logs-redesign',
'client-side-references',
'editor-redesign-new-users',
].filter(Boolean)
const getUserValues = async userId =>
@@ -980,6 +980,7 @@
"log_entry_maximum_entries": "",
"log_entry_maximum_entries_enable_stop_on_first_error": "",
"log_entry_maximum_entries_see_full_logs": "",
"log_entry_maximum_entries_see_full_logs_new": "",
"log_entry_maximum_entries_title": "",
"log_hint_extra_info": "",
"log_in": "",
@@ -5,9 +5,13 @@ import PdfCompileButton from '@/features/pdf-preview/components/pdf-compile-butt
import PdfHybridDownloadButton from '@/features/pdf-preview/components/pdf-hybrid-download-button'
import { DetachedSynctexControl } from '@/features/pdf-preview/components/detach-synctex-control'
import SwitchToEditorButton from '@/features/pdf-preview/components/switch-to-editor-button'
import PdfHybridLogsButton from '@/features/pdf-preview/components/pdf-hybrid-logs-button'
import { useAreNewErrorLogsEnabled } from '../../utils/new-editor-utils'
function PdfPreviewHybridToolbar() {
const { t } = useTranslation()
const newErrorLogs = useAreNewErrorLogsEnabled()
// TODO: add detached pdf logic
return (
<OLButtonToolbar
@@ -16,6 +20,7 @@ function PdfPreviewHybridToolbar() {
>
<div className="toolbar-pdf-left">
<PdfCompileButton />
{!newErrorLogs && <PdfHybridLogsButton />}
<PdfHybridDownloadButton />
</div>
<div className="toolbar-pdf-right">
@@ -1,4 +1,3 @@
import { useFeatureFlag } from '@/shared/context/split-test-context'
import { Panel } from 'react-resizable-panels'
import { useRailContext } from '../../contexts/rail-context'
import classNames from 'classnames'
@@ -20,8 +19,6 @@ export default function RailPanel({
const { selectedTab, panelRef, handlePaneExpand, handlePaneCollapse } =
useRailContext()
const newErrorlogs = useFeatureFlag('new-editor-error-logs-redesign')
const prevTab = usePreviousValue(selectedTab)
const tabHasChanged = useMemo(() => {
@@ -36,11 +33,7 @@ export default function RailPanel({
return (
<Panel
id={
newErrorlogs
? `ide-redesign-sidebar-panel-${isHistoryView ? 'file-tree' : selectedTab}`
: 'ide-redesign-sidebar-panel'
}
id={`ide-redesign-sidebar-panel-${isHistoryView ? 'file-tree' : selectedTab}`}
className={classNames({ hidden: isReviewPanelOpen })}
order={1}
defaultSize={15}
@@ -18,8 +18,6 @@ import {
import { sendSearchEvent } from '@/features/event-tracking/search-events'
import ErrorLogsPanel from '../error-logs/error-logs-panel'
import { useDetachCompileContext as useCompileContext } from '@/shared/context/detach-compile-context'
import OldErrorPane from '../error-logs/old-error-pane'
import { useFeatureFlag } from '@/shared/context/split-test-context'
import { useProjectContext } from '@/shared/context/project-context'
import { useCommandProvider } from '@/features/ide-react/hooks/use-command-provider'
import RailHelpDropdown from './rail-help-dropdown'
@@ -31,6 +29,7 @@ import RailResizeHandle from './rail-resize-handle'
import RailModals from './rail-modals'
import RailOverflowDropdown from './rail-overflow-dropdown'
import useRailOverflow from '../../hooks/use-rail-overflow'
import { useAreNewErrorLogsEnabled } from '../../utils/new-editor-utils'
export const RailLayout = () => {
const { sendEvent } = useEditorAnalytics()
@@ -46,7 +45,7 @@ export const RailLayout = () => {
const isHistoryView = view === 'history'
const newErrorlogs = useFeatureFlag('new-editor-error-logs-redesign')
const newErrorlogs = useAreNewErrorLogsEnabled()
const railTabs: RailElement[] = useMemo(
() => [
@@ -92,9 +91,10 @@ export const RailLayout = () => {
key: 'errors',
icon: 'report',
title: t('error_log'),
component: newErrorlogs ? <ErrorLogsPanel /> : <OldErrorPane />,
component: <ErrorLogsPanel />,
indicator: <ErrorIndicator />,
disabled: errorLogsDisabled,
hide: !newErrorlogs,
},
],
[t, features.trackChangesVisible, newErrorlogs, errorLogsDisabled, view]
@@ -1,8 +1,43 @@
import { useUserSettingsContext } from '@/shared/context/user-settings-context'
import { isSplitTestEnabled } from '@/utils/splitTestUtils'
import getMeta from '@/utils/meta'
import { isSplitTestEnabled, getSplitTestVariant } from '@/utils/splitTestUtils'
// TODO: change this when we have a launch date
const NEW_USER_CUTOFF_DATE = new Date('2100-01-01')
const isNewUser = () => {
const user = getMeta('ol-user')
if (!user.signUpDate) return false
const createdAt = new Date(user.signUpDate)
return createdAt > NEW_USER_CUTOFF_DATE
}
export const canUseNewEditor = () => {
return isSplitTestEnabled('editor-redesign')
const newUserTestVariant = getSplitTestVariant('editor-redesign-new-users')
const canUseNewEditorViaPrimaryFeatureFlag =
isSplitTestEnabled('editor-redesign')
const canUseNewEditorViaNewUserFeatureFlag =
isNewUser() &&
(newUserTestVariant === 'new-editor' ||
newUserTestVariant === 'new-editor-old-logs')
return (
canUseNewEditorViaPrimaryFeatureFlag || canUseNewEditorViaNewUserFeatureFlag
)
}
const canUseNewLogs = () => {
const newUserTestVariant = getSplitTestVariant('editor-redesign-new-users')
const canUseNewLogsViaPrimaryFeatureFlag =
isSplitTestEnabled('editor-redesign')
const canUseNewLogsViaNewUserFeatureFlag =
isNewUser() && newUserTestVariant === 'new-editor'
return (
canUseNewLogsViaPrimaryFeatureFlag || canUseNewLogsViaNewUserFeatureFlag
)
}
export const useIsNewEditorEnabled = () => {
@@ -11,3 +46,8 @@ export const useIsNewEditorEnabled = () => {
const enabled = userSettings.enableNewEditor
return hasAccess && enabled
}
export const useAreNewErrorLogsEnabled = () => {
const newEditorEnabled = useIsNewEditorEnabled()
return newEditorEnabled && canUseNewLogs()
}
@@ -5,9 +5,8 @@ import HumanReadableLogsHints from '../../../ide/human-readable-logs/HumanReadab
import { sendMB } from '@/infrastructure/event-tracking'
import getMeta from '@/utils/meta'
import { ErrorLevel, LogEntry, SourceLocation } from '../util/types'
import { useIsNewEditorEnabled } from '@/features/ide-redesign/utils/new-editor-utils'
import { useAreNewErrorLogsEnabled } from '@/features/ide-redesign/utils/new-editor-utils'
import NewLogEntry from '@/features/ide-redesign/components/error-logs/log-entry'
import { useFeatureFlag } from '@/shared/context/split-test-context'
function PdfLogEntry({
autoExpand,
@@ -71,10 +70,9 @@ function PdfLogEntry({
[level, onSourceLocationClick, ruleId, sourceLocation]
)
const newEditor = useIsNewEditorEnabled()
const newErrorlogs = useFeatureFlag('new-editor-error-logs-redesign')
const newErrorlogs = useAreNewErrorLogsEnabled()
if (newEditor && newErrorlogs) {
if (newErrorlogs) {
return (
<NewLogEntry
autoExpand={autoExpand}
@@ -10,7 +10,10 @@ import CompileTimeWarningUpgradePrompt from './compile-time-warning-upgrade-prom
import { PdfPreviewProvider } from './pdf-preview-provider'
import PdfPreviewHybridToolbarNew from '@/features/ide-redesign/components/pdf-preview/pdf-preview-hybrid-toolbar'
import PdfErrorState from '@/features/ide-redesign/components/pdf-preview/pdf-error-state/pdf-error-state'
import { useIsNewEditorEnabled } from '@/features/ide-redesign/utils/new-editor-utils'
import {
useAreNewErrorLogsEnabled,
useIsNewEditorEnabled,
} from '@/features/ide-redesign/utils/new-editor-utils'
import importOverleafModules from '../../../../macros/import-overleaf-module.macro'
import PdfCodeCheckFailedBanner from '@/features/ide-redesign/components/pdf-preview/pdf-code-check-failed-banner'
import getMeta from '@/utils/meta'
@@ -22,6 +25,7 @@ function PdfPreviewPane() {
'pdf-empty': !pdfUrl,
})
const newEditor = useIsNewEditorEnabled()
const newErrorLogs = useAreNewErrorLogsEnabled()
const pdfPromotions = importOverleafModules('pdfPreviewPromotions') as {
import: { default: ElementType }
path: string
@@ -35,7 +39,7 @@ function PdfPreviewPane() {
) : (
<PdfHybridPreviewToolbar />
)}
{newEditor && <PdfCodeCheckFailedBanner />}
{newErrorLogs && <PdfCodeCheckFailedBanner />}
<PdfPreviewMessages>
{compileTimeout < 60 && <CompileTimeWarningUpgradePrompt />}
</PdfPreviewMessages>
@@ -44,7 +48,7 @@ function PdfPreviewPane() {
<PdfViewer />
</div>
</Suspense>
{newEditor ? <PdfErrorState /> : <PdfLogsViewer />}
{newErrorLogs ? <PdfErrorState /> : <PdfLogsViewer />}
{pdfPromotions.map(({ import: { default: Component }, path }) => (
<Component key={path} />
))}
@@ -5,6 +5,7 @@ import { useDetachCompileContext as useCompileContext } from '../../../shared/co
import { useStopOnFirstError } from '../../../shared/hooks/use-stop-on-first-error'
import MaterialIcon from '@/shared/components/material-icon'
import PdfLogEntry from '@/features/pdf-preview/components/pdf-log-entry'
import { useAreNewErrorLogsEnabled } from '@/features/ide-redesign/utils/new-editor-utils'
function PreviewLogsPaneMaxEntries({
totalEntries,
@@ -39,6 +40,7 @@ function PreviewLogsPaneMaxEntriesContent({
}: {
hasErrors?: boolean
}) {
const newLogs = useAreNewErrorLogsEnabled()
const { t } = useTranslation()
const { startCompile, stoppedOnFirstError, setAnimateCompileDropdownArrow } =
useCompileContext()
@@ -76,7 +78,11 @@ function PreviewLogsPaneMaxEntriesContent({
]}
/>{' '}
</p>
<p>{t('log_entry_maximum_entries_see_full_logs')}</p>
<p>
{newLogs
? t('log_entry_maximum_entries_see_full_logs_new')
: t('log_entry_maximum_entries_see_full_logs')}
</p>
</>
)
}
@@ -86,7 +92,9 @@ function PreviewLogsPaneMaxEntriesContent({
<MaterialIcon type="lightbulb" className="align-middle" />
&nbsp;
<strong>{t('tip')}: </strong>
{t('log_entry_maximum_entries_see_full_logs')}
{newLogs
? t('log_entry_maximum_entries_see_full_logs_new')
: t('log_entry_maximum_entries_see_full_logs')}
</p>
)
}
+1
View File
@@ -1266,6 +1266,7 @@
"log_entry_maximum_entries": "Maximum log entries limit hit",
"log_entry_maximum_entries_enable_stop_on_first_error": "Try to fix the first error and recompile. Often one error causes many later error messages. You can <0>Enable “Stop on first error”</0> to focus on fixing errors. We recommend fixing errors as soon as possible; letting them accumulate may lead to hard-to-debug and fatal errors. <1>Learn more</1>",
"log_entry_maximum_entries_see_full_logs": "If you need to see the full logs, you can still download them or view the raw logs below.",
"log_entry_maximum_entries_see_full_logs_new": "If you need to see the full logs, you can still view the raw logs at the bottom of this pane or download them using the button at the top.",
"log_entry_maximum_entries_title": "__total__ log messages total. Showing the first __displayed__",
"log_hint_extra_info": "Learn more",
"log_in": "Log in",