mirror of
https://github.com/yu-i-i/overleaf-cep.git
synced 2026-06-05 15:19:02 +02:00
Merge pull request #29511 from overleaf/dp-new-users-to-new-editor
Move all new users to use the new editor GitOrigin-RevId: e3611e5853da4b96db9f4cc37114ededb8632aed
This commit is contained in:
+2
-2
@@ -4,7 +4,7 @@ import { useSwitchEnableNewEditorState } from '@/features/ide-redesign/hooks/use
|
||||
import { useLayoutContext } from '@/shared/context/layout-context'
|
||||
import { useCallback } from 'react'
|
||||
import {
|
||||
canUseNewEditorViaNewUserFeatureFlag,
|
||||
canUseNewEditorAsNewUser,
|
||||
useIsNewEditorEnabled,
|
||||
} from '@/features/ide-redesign/utils/new-editor-utils'
|
||||
|
||||
@@ -13,7 +13,7 @@ export default function SettingsNewEditor() {
|
||||
const { setEditorRedesignStatus } = useSwitchEnableNewEditorState()
|
||||
const { setLeftMenuShown } = useLayoutContext()
|
||||
const enabled = useIsNewEditorEnabled()
|
||||
const show = canUseNewEditorViaNewUserFeatureFlag()
|
||||
const show = canUseNewEditorAsNewUser()
|
||||
|
||||
const onChange = useCallback(
|
||||
(newValue: boolean) => {
|
||||
|
||||
+2
-2
@@ -2,13 +2,13 @@ import { useCallback } from 'react'
|
||||
import OLButton from '../../shared/components/ol/ol-button'
|
||||
import { useIdeRedesignSwitcherContext } from '../ide-react/context/ide-redesign-switcher-context'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { canUseNewEditorViaPrimaryFeatureFlag } from '../ide-redesign/utils/new-editor-utils'
|
||||
import { canUseNewEditorAsExistingUser } from '../ide-redesign/utils/new-editor-utils'
|
||||
import { useSwitchEnableNewEditorState } from '../ide-redesign/hooks/use-switch-enable-new-editor-state'
|
||||
|
||||
const TryNewEditorButton = () => {
|
||||
const { t } = useTranslation()
|
||||
const { setShowSwitcherModal } = useIdeRedesignSwitcherContext()
|
||||
const showModal = canUseNewEditorViaPrimaryFeatureFlag()
|
||||
const showModal = canUseNewEditorAsExistingUser()
|
||||
const { loading, setEditorRedesignStatus } = useSwitchEnableNewEditorState()
|
||||
|
||||
const onClick = useCallback(() => {
|
||||
|
||||
+2
-2
@@ -11,7 +11,7 @@ import { FC, useCallback, useEffect } from 'react'
|
||||
import {
|
||||
canUseNewEditor,
|
||||
useIsNewEditorEnabled,
|
||||
useIsNewEditorEnabledViaPrimaryFeatureFlag,
|
||||
useIsNewEditorEnabledAsExistingUser,
|
||||
} from '../../utils/new-editor-utils'
|
||||
import Notification from '@/shared/components/notification'
|
||||
import { useSwitchEnableNewEditorState } from '../../hooks/use-switch-enable-new-editor-state'
|
||||
@@ -32,7 +32,7 @@ export const IdeRedesignIntroModal: FC = () => {
|
||||
name: TUTORIAL_KEY,
|
||||
}
|
||||
)
|
||||
const hasAccess = useIsNewEditorEnabledViaPrimaryFeatureFlag()
|
||||
const hasAccess = useIsNewEditorEnabledAsExistingUser()
|
||||
|
||||
useEffect(() => {
|
||||
if (!hasAccess) return
|
||||
|
||||
@@ -4,7 +4,7 @@ import OLTooltip from '@/shared/components/ol/ol-tooltip'
|
||||
import { useCallback } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { GiveFeedbackLink } from './give-feedback-link'
|
||||
import { useIsNewEditorEnabledViaPrimaryFeatureFlag } from '../../utils/new-editor-utils'
|
||||
import { useIsNewEditorEnabledAsExistingUser } from '../../utils/new-editor-utils'
|
||||
|
||||
export const BetaActions = () => {
|
||||
const { t } = useTranslation()
|
||||
@@ -12,7 +12,7 @@ export const BetaActions = () => {
|
||||
const openEditorRedesignSwitcherModal = useCallback(() => {
|
||||
setShowSwitcherModal(true)
|
||||
}, [setShowSwitcherModal])
|
||||
const showBetaActions = useIsNewEditorEnabledViaPrimaryFeatureFlag()
|
||||
const showBetaActions = useIsNewEditorEnabledAsExistingUser()
|
||||
|
||||
if (!showBetaActions) {
|
||||
return null
|
||||
|
||||
@@ -30,7 +30,7 @@ import { useSurveyUrl } from '../../hooks/use-survey-url'
|
||||
import getMeta from '@/utils/meta'
|
||||
import EditorCloneProjectModalWrapper from '@/features/clone-project-modal/components/editor-clone-project-modal-wrapper'
|
||||
import useOpenProject from '@/shared/hooks/use-open-project'
|
||||
import { canUseNewEditorViaPrimaryFeatureFlag } from '../../utils/new-editor-utils'
|
||||
import { canUseNewEditorAsExistingUser } from '../../utils/new-editor-utils'
|
||||
|
||||
export const ToolbarMenuBar = () => {
|
||||
const { t } = useTranslation()
|
||||
@@ -44,7 +44,7 @@ export const ToolbarMenuBar = () => {
|
||||
const [showWordCountModal, setShowWordCountModal] = useState(false)
|
||||
const [showCloneProjectModal, setShowCloneProjectModal] = useState(false)
|
||||
const openProject = useOpenProject()
|
||||
const showEditorSwitchMenuOption = canUseNewEditorViaPrimaryFeatureFlag()
|
||||
const showEditorSwitchMenuOption = canUseNewEditorAsExistingUser()
|
||||
|
||||
const anonymous = getMeta('ol-anonymous')
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ import FontFamilySetting from '../components/settings/appearance-settings/font-f
|
||||
import { AvailableUnfilledIcon } from '@/shared/components/material-icon'
|
||||
import { EditorLeftMenuProvider } from '@/features/editor-left-menu/components/editor-left-menu-context'
|
||||
import NewEditorSetting from '../components/settings/editor-settings/new-editor-setting'
|
||||
import { canUseNewEditorViaNewUserFeatureFlag } from '../utils/new-editor-utils'
|
||||
import { canUseNewEditorAsNewUser } from '../utils/new-editor-utils'
|
||||
|
||||
const [referenceSearchSettingModule] = importOverleafModules(
|
||||
'referenceSearchSetting'
|
||||
@@ -77,7 +77,7 @@ export const SettingsModalProvider: FC<React.PropsWithChildren> = ({
|
||||
children,
|
||||
}) => {
|
||||
const { t } = useTranslation()
|
||||
const showEditorSwitch = canUseNewEditorViaNewUserFeatureFlag()
|
||||
const showEditorSwitch = canUseNewEditorAsNewUser()
|
||||
|
||||
// TODO ide-redesign-cleanup: Rename this field and move it directly into this context
|
||||
const { leftMenuShown, setLeftMenuShown } = useLayoutContext()
|
||||
|
||||
@@ -2,13 +2,24 @@ import { useUserSettingsContext } from '@/shared/context/user-settings-context'
|
||||
import getMeta from '@/utils/meta'
|
||||
import { isSplitTestEnabled, getSplitTestVariant } from '@/utils/splitTestUtils'
|
||||
|
||||
export const ignoringUserCutoffDate =
|
||||
const ignoringUserCutoffDate =
|
||||
new URLSearchParams(window.location.search).get('skip-new-user-check') ===
|
||||
'true'
|
||||
|
||||
const NEW_USER_CUTOFF_DATE = new Date(Date.UTC(2025, 8, 23, 13, 0, 0)) // 2pm British Summer Time on September 23, 2025
|
||||
// For E2E tests, allow forcing a user to be treated as an existing user
|
||||
const existingUserOverride =
|
||||
new URLSearchParams(window.location.search).get('existing-user-override') ===
|
||||
'true'
|
||||
|
||||
// We don't want to enable the new editor on server-pro/CE until we have fully rolled it out on SaaS
|
||||
const { isOverleaf } = getMeta('ol-ExposedSettings')
|
||||
|
||||
const SPLIT_TEST_USER_CUTOFF_DATE = new Date(Date.UTC(2025, 8, 23, 13, 0, 0)) // 2pm British Summer Time on September 23, 2025
|
||||
const NEW_USER_CUTOFF_DATE = new Date(Date.UTC(2025, 10, 12, 12, 0, 0)) // 12pm GMT on November 12, 2025
|
||||
|
||||
export const isNewUser = () => {
|
||||
if (existingUserOverride) return false
|
||||
|
||||
if (ignoringUserCutoffDate) return true
|
||||
const user = getMeta('ol-user')
|
||||
|
||||
@@ -18,32 +29,37 @@ export const isNewUser = () => {
|
||||
return createdAt > NEW_USER_CUTOFF_DATE
|
||||
}
|
||||
|
||||
export const canUseNewEditorViaPrimaryFeatureFlag = () => {
|
||||
return isSplitTestEnabled('editor-redesign')
|
||||
export const isSplitTestUser = () => {
|
||||
if (existingUserOverride) return false
|
||||
|
||||
const user = getMeta('ol-user')
|
||||
if (!user.signUpDate) return false
|
||||
|
||||
const createdAt = new Date(user.signUpDate)
|
||||
return (
|
||||
createdAt > SPLIT_TEST_USER_CUTOFF_DATE && createdAt <= NEW_USER_CUTOFF_DATE
|
||||
)
|
||||
}
|
||||
|
||||
export const canUseNewEditorViaNewUserFeatureFlag = () => {
|
||||
const newUserTestVariant = getSplitTestVariant('editor-redesign-new-users')
|
||||
export const canUseNewEditorAsExistingUser = () => {
|
||||
return !canUseNewEditorAsNewUser() && isSplitTestEnabled('editor-redesign')
|
||||
}
|
||||
|
||||
export const canUseNewEditorAsNewUser = () => {
|
||||
const newUserTestVariant = getSplitTestVariant('editor-redesign-new-users')
|
||||
return (
|
||||
!canUseNewEditorViaPrimaryFeatureFlag() &&
|
||||
isNewUser() &&
|
||||
(newUserTestVariant === 'new-editor' ||
|
||||
newUserTestVariant === 'new-editor-old-logs' ||
|
||||
newUserTestVariant === 'new-editor-new-logs-old-position')
|
||||
isOverleaf &&
|
||||
(isNewUser() || (isSplitTestUser() && newUserTestVariant !== 'default'))
|
||||
)
|
||||
}
|
||||
|
||||
export const canUseNewEditor = () => {
|
||||
return (
|
||||
canUseNewEditorViaPrimaryFeatureFlag() ||
|
||||
canUseNewEditorViaNewUserFeatureFlag()
|
||||
)
|
||||
return canUseNewEditorAsExistingUser() || canUseNewEditorAsNewUser()
|
||||
}
|
||||
|
||||
export const useIsNewEditorEnabledViaPrimaryFeatureFlag = () => {
|
||||
export const useIsNewEditorEnabledAsExistingUser = () => {
|
||||
const { userSettings } = useUserSettingsContext()
|
||||
const hasAccess = canUseNewEditorViaPrimaryFeatureFlag()
|
||||
const hasAccess = canUseNewEditorAsExistingUser()
|
||||
const enabled = userSettings.enableNewEditor
|
||||
return hasAccess && enabled
|
||||
}
|
||||
@@ -54,9 +70,3 @@ export const useIsNewEditorEnabled = () => {
|
||||
const enabled = userSettings.enableNewEditor
|
||||
return hasAccess && enabled
|
||||
}
|
||||
|
||||
export function useNewEditorVariant() {
|
||||
const newEditor = useIsNewEditorEnabled()
|
||||
if (!newEditor) return 'default'
|
||||
return 'new-editor-new-logs-old-position'
|
||||
}
|
||||
|
||||
+5
-17
@@ -8,12 +8,9 @@ import OLButton from '@/shared/components/ol/ol-button'
|
||||
import * as eventTracking from '../../../infrastructure/event-tracking'
|
||||
import getMeta from '@/utils/meta'
|
||||
import { populateEditorRedesignSegmentation } from '@/shared/hooks/use-editor-analytics'
|
||||
import {
|
||||
isNewUser,
|
||||
useIsNewEditorEnabled,
|
||||
} from '@/features/ide-redesign/utils/new-editor-utils'
|
||||
import { getSplitTestVariant, isSplitTestEnabled } from '@/utils/splitTestUtils'
|
||||
import CompileTimeoutPaywallModal from '@/features/pdf-preview/components/compile-timeout-paywall-modal'
|
||||
import { useIsNewEditorEnabled } from '@/features/ide-redesign/utils/new-editor-utils'
|
||||
import { isSplitTestEnabled } from '@/utils/splitTestUtils'
|
||||
|
||||
function TimeoutUpgradePromptNew() {
|
||||
const {
|
||||
@@ -98,21 +95,12 @@ const CompileTimeout = memo(function CompileTimeout({
|
||||
isCompileTimeoutTargetPlansEnabled,
|
||||
}: CompileTimeoutProps) {
|
||||
const { t } = useTranslation()
|
||||
const newEditor = useIsNewEditorEnabled()
|
||||
const extraSearchParams = useMemo(() => {
|
||||
if (!isNewUser()) {
|
||||
return undefined
|
||||
}
|
||||
|
||||
const variant = getSplitTestVariant('editor-redesign-new-users')
|
||||
|
||||
if (!variant) {
|
||||
return undefined
|
||||
}
|
||||
|
||||
return {
|
||||
itm_content: variant,
|
||||
itm_content: newEditor ? 'new-editor' : 'old-editor',
|
||||
}
|
||||
}, [])
|
||||
}, [newEditor])
|
||||
|
||||
const handleFreeTrialClick = useCallback(
|
||||
(event: React.MouseEvent<HTMLButtonElement>) => {
|
||||
|
||||
@@ -1,86 +0,0 @@
|
||||
import { expect } from 'chai'
|
||||
import { mockScope } from './scope'
|
||||
import { EditorProviders } from '../../helpers/editor-providers'
|
||||
import { renderHook } from '@testing-library/react'
|
||||
import { useNewEditorVariant } from '@/features/ide-redesign/utils/new-editor-utils'
|
||||
|
||||
describe('new-editor-utils', function () {
|
||||
describe('useNewEditorVariant', function () {
|
||||
const newEditorVariants = [
|
||||
{ splitTestVariant: 'default', uiVariant: 'default' },
|
||||
{
|
||||
splitTestVariant: 'new-editor',
|
||||
uiVariant: 'new-editor-new-logs-old-position',
|
||||
},
|
||||
{
|
||||
splitTestVariant: 'new-editor-old-logs',
|
||||
uiVariant: 'new-editor-new-logs-old-position',
|
||||
},
|
||||
{
|
||||
splitTestVariant: 'new-editor-new-logs-old-position',
|
||||
uiVariant: 'new-editor-new-logs-old-position',
|
||||
},
|
||||
]
|
||||
for (const variant of newEditorVariants) {
|
||||
it(`forwards ?editor-redesign-new-users=${variant}`, function () {
|
||||
window.metaAttributesCache.set('ol-splitTestVariants', {
|
||||
'editor-redesign-new-users': variant.splitTestVariant,
|
||||
})
|
||||
|
||||
const scope = mockScope()
|
||||
|
||||
const { result } = renderHook(() => useNewEditorVariant(), {
|
||||
wrapper: ({ children }) => (
|
||||
<EditorProviders
|
||||
scope={scope}
|
||||
userSettings={{ enableNewEditor: true }}
|
||||
>
|
||||
{children}
|
||||
</EditorProviders>
|
||||
),
|
||||
})
|
||||
expect(result.current).to.equal(variant.uiVariant)
|
||||
})
|
||||
}
|
||||
for (const variant of newEditorVariants) {
|
||||
it(`ignores ?editor-redesign-new-users=${variant} when disabled by user`, function () {
|
||||
window.metaAttributesCache.set('ol-splitTestVariants', {
|
||||
'editor-redesign-new-users': variant.splitTestVariant,
|
||||
})
|
||||
|
||||
const scope = mockScope()
|
||||
|
||||
const { result } = renderHook(() => useNewEditorVariant(), {
|
||||
wrapper: ({ children }) => (
|
||||
<EditorProviders
|
||||
scope={scope}
|
||||
userSettings={{ enableNewEditor: false }}
|
||||
>
|
||||
{children}
|
||||
</EditorProviders>
|
||||
),
|
||||
})
|
||||
expect(result.current).to.equal('default')
|
||||
})
|
||||
}
|
||||
it(`handles ?editor-redesign=enabled`, function () {
|
||||
window.metaAttributesCache.set('ol-splitTestVariants', {
|
||||
'editor-redesign': 'enabled',
|
||||
})
|
||||
|
||||
const scope = mockScope()
|
||||
|
||||
const { result } = renderHook(() => useNewEditorVariant(), {
|
||||
wrapper: ({ children }) => (
|
||||
<EditorProviders
|
||||
scope={scope}
|
||||
userSettings={{ enableNewEditor: true }}
|
||||
>
|
||||
{children}
|
||||
</EditorProviders>
|
||||
),
|
||||
})
|
||||
expect(result.current).to.equal('new-editor-new-logs-old-position')
|
||||
})
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user