Merge pull request #28589 from overleaf/revert-28283-jdt-monthly-tl-experiment

Revert "Rolling TexLive builds experiment"

GitOrigin-RevId: c3c6833dca7ef0d207f854c93bf0bb03bd814694
This commit is contained in:
Brian Gough
2025-09-19 08:55:33 +01:00
committed by Copybot
parent aaafb86fe2
commit aaa62b2dbc
14 changed files with 62 additions and 171 deletions

View File

@@ -513,7 +513,7 @@ const _ProjectController = {
req,
projectId
)
const imageNames = ProjectHelper.getAllowedImagesForUser(user)
const allowedImageNames = ProjectHelper.getAllowedImagesForUser(user)
const privilegeLevel =
await AuthorizationManager.promises.getPrivilegeLevelForProject(
@@ -847,7 +847,7 @@ const _ProjectController = {
maxReconnectGracefullyIntervalMs:
Settings.maxReconnectGracefullyIntervalMs,
brandVariation,
imageNames,
allowedImageNames,
gitBridgePublicBaseUrl: Settings.gitBridgePublicBaseUrl,
gitBridgeEnabled: Features.hasFeature('git-bridge'),
wsUrl,

View File

@@ -148,27 +148,11 @@ function _addNumericSuffixToProjectName(name, allProjectNames, maxLength) {
return null
}
function _imageAllowed(user, image) {
if (image.alphaOnly) {
return Boolean(user?.alphaProgram)
}
if (image.monthlyExperimental) {
return Boolean(
user?.labsProgram && user.labsExperiments.includes('monthly-texlive')
)
}
return true
}
function getAllowedImagesForUser(user) {
let images = Settings.allowedImageNames || []
images = images.map(image => {
return {
...image,
allowed: _imageAllowed(user, image),
}
})
return images
const images = Settings.allowedImageNames || []
if (user?.alphaProgram) {
return images
} else {
return images.filter(image => !image.alphaOnly)
}
}

View File

@@ -1,6 +1,6 @@
meta(name="ol-project_id" content=project_id)
meta(name="ol-projectName" content=projectName)
meta(name="ol-projectOwnerHasPremiumOnPageLoad" content=projectOwnerHasPremiumOnPageLoad)
meta(name="ol-projectOwnerHasPremiumOnPageLoad" data-type="boolean" content=projectOwnerHasPremiumOnPageLoad)
meta(name="ol-userSettings" data-type="json" content=userSettings)
meta(name="ol-user" data-type="json" content=user)
meta(name="ol-labsExperiments" data-type="json" content=labsExperiments)
@@ -26,16 +26,16 @@ meta(name="ol-showSymbolPalette" data-type="boolean" content=showSymbolPalette)
meta(name="ol-symbolPaletteAvailable" data-type="boolean" content=symbolPaletteAvailable)
meta(name="ol-showAiErrorAssistant" data-type="boolean" content=showAiErrorAssistant)
meta(name="ol-detachRole" data-type="string" content=detachRole)
meta(name="ol-imageNames" data-type="json" content=imageNames)
meta(name="ol-allowedImageNames" data-type="json" content=allowedImageNames)
meta(name="ol-languages" data-type="json" content=languages)
meta(name="ol-editorThemes" data-type="json" content=editorThemes)
meta(name="ol-legacyEditorThemes" data-type="json" content=legacyEditorThemes)
meta(name="ol-showUpgradePrompt" data-type="boolean" content=showUpgradePrompt)
meta(name="ol-showSupport" data-type="boolean" content=showSupport)
meta(name="ol-showTemplatesServerPro" data-type="boolean" content=showTemplatesServerPro)
meta(name="ol-hasTrackChangesFeature" data-type="boolean" content=hasTrackChangesFeature)
meta(name="ol-otMigrationStage" data-type="number" content=otMigrationStage)
meta(name="ol-inactiveTutorials" data-type="json" content=user.inactiveTutorials)
meta(name="ol-showSupport", data-type="boolean" content=showSupport)
meta(name="ol-showTemplatesServerPro", data-type="boolean" content=showTemplatesServerPro)
meta(name="ol-hasTrackChangesFeature", data-type="boolean" content=hasTrackChangesFeature)
meta(name="ol-otMigrationStage", data-type="number" content=otMigrationStage)
meta(name="ol-inactiveTutorials", data-type="json" content=user.inactiveTutorials)
meta(name="ol-projectTags" data-type="json" content=projectTags)
meta(name="ol-ro-mirror-on-client-no-local-storage" data-type="boolean" content=roMirrorOnClientNoLocalStorage)
meta(name="ol-isSaas" data-type="boolean" content=isSaas)
@@ -44,12 +44,12 @@ meta(name='ol-customerIoEnabled' data-type="boolean" content=customerIoEnabled)
meta(name='ol-compileSettings' data-type="json" content=compileSettings)
if(isOverleafAssistBundleEnabled)
//- expose plans info to show prices in paywall-change-compile-timeout test
meta(name="ol-addonPrices" data-type="json" content=addonPrices)
meta(name="ol-addonPrices", data-type="json" content=addonPrices)
// translations for the loading page, before i18n has loaded in the client
meta(name="ol-loadingText" data-type="string" content=translate("loading"))
meta(name="ol-translationIoNotLoaded" data-type="string" content=translate("could_not_connect_to_websocket_server"))
meta(name="ol-translationLoadErrorMessage" data-type="string" content=translate("could_not_load_translations"))
meta(name="ol-translationUnableToJoin" data-type="string" content=translate("could_not_connect_to_collaboration_server"))
meta(name="ol-loadingText", data-type="string" content=translate("loading"))
meta(name="ol-translationIoNotLoaded", data-type="string" content=translate("could_not_connect_to_websocket_server"))
meta(name="ol-translationLoadErrorMessage", data-type="string" content=translate("could_not_load_translations"))
meta(name="ol-translationUnableToJoin", data-type="string" content=translate("could_not_connect_to_collaboration_server"))
if (settings.overleaf != null)
meta(name="ol-overallThemes" data-type="json" content=overallThemes)

View File

@@ -1484,7 +1484,6 @@
"revoke_invite": "",
"right": "",
"role": "",
"rolling_texlive_build": "",
"saml_auth_error": "",
"saml_identity_exists_error": "",
"saml_invalid_signature_error": "",
@@ -1779,7 +1778,6 @@
"test": "",
"test_configuration": "",
"test_configuration_successful": "",
"test_more_recent_versions_of_texlive": "",
"tex_live_version": "",
"texgpt": "",
"thank_you": "",

View File

@@ -11,18 +11,18 @@ export default function SettingsImageName() {
const { imageName, setImageName } = useProjectSettingsContext()
const { write } = usePermissionsContext()
const allowedImageNames = useMemo(() => getMeta('ol-imageNames') || [], [])
const allowedImageNames = useMemo(
() => getMeta('ol-allowedImageNames') || [],
[]
)
const options: Array<Option> = useMemo(
() =>
allowedImageNames
// filter out images that aren't allowed, unless thats the current image the project is on
.filter(image => image.allowed || image.imageName === imageName)
.map(({ imageName, imageDesc }) => ({
value: imageName,
label: imageDesc,
})),
[allowedImageNames, imageName]
allowedImageNames.map(({ imageName, imageDesc }) => ({
value: imageName,
label: imageDesc,
})),
[allowedImageNames]
)
if (allowedImageNames.length === 0) {

View File

@@ -11,21 +11,21 @@ export default function ImageNameSetting() {
const { t } = useTranslation()
const { write } = usePermissionsContext()
const imageNames = useMemo(() => getMeta('ol-imageNames') || [], [])
const allowedImageNames = useMemo(
() => getMeta('ol-allowedImageNames') || [],
[]
)
const options: Array<Option> = useMemo(
() =>
imageNames
// filter out images that aren't allowed, unless thats the current image the project is on
.filter(image => image.allowed || image.imageName === imageName)
.map(({ imageName, imageDesc }) => ({
value: imageName,
label: imageDesc,
})),
[imageNames, imageName]
allowedImageNames.map(({ imageName, imageDesc }) => ({
value: imageName,
label: imageDesc,
})),
[allowedImageNames]
)
if (imageNames.length === 0) {
if (allowedImageNames.length === 0) {
return null
}

View File

@@ -1,44 +0,0 @@
import { useState } from 'react'
import LabsExperimentWidget from '../../shared/components/labs/labs-experiments-widget'
import { isInExperiment } from '@/utils/labs-utils'
import { useTranslation } from 'react-i18next'
import MaterialIcon from '@/shared/components/material-icon'
import { isSplitTestEnabled } from '@/utils/splitTestUtils'
const MonthlyTexliveLabsWidget = ({
labsProgram,
setErrorMessage,
}: {
labsProgram: boolean
setErrorMessage: (err: string) => void
}) => {
const { t } = useTranslation()
const [optedIn, setOptedIn] = useState(isInExperiment('monthly-texlive'))
const monthlyTexLiveSplitTestEnabled = isSplitTestEnabled('monthly-texlive')
if (!monthlyTexLiveSplitTestEnabled) {
return null
}
const logo = (
<MaterialIcon
type="construction"
size="2x"
className="rounded bg-primary-subtle"
/>
)
return (
<LabsExperimentWidget
description={t('test_more_recent_versions_of_texlive')}
experimentName="monthly-texlive"
logo={logo}
labsEnabled={labsProgram}
setErrorMessage={setErrorMessage}
optedIn={optedIn}
setOptedIn={setOptedIn}
title={t('rolling_texlive_build')}
/>
)
}
export default MonthlyTexliveLabsWidget

View File

@@ -2,7 +2,7 @@ import getMeta from './meta'
// Should be `never` when no experiments are active. Otherwise it should be a
// union of active experiment names e.g. `'experiment1' | 'experiment2'`
export type ActiveExperiment = 'monthly-texlive'
export type ActiveExperiment = never
export const isInExperiment = (experiment: ActiveExperiment): boolean => {
const experiments = getMeta('ol-labsExperiments')

View File

@@ -5,7 +5,7 @@ import { UserSettings } from '../../../types/user-settings'
import { OAuthProviders } from '../../../types/oauth-providers'
import { ExposedSettings } from '../../../types/exposed-settings'
import {
type ImageName,
type AllowedImageName,
OverallThemeMeta,
type SpellCheckLanguage,
} from '../../../types/project-settings'
@@ -80,6 +80,7 @@ export interface Meta {
'ol-algolia': AlgoliaConfig | undefined
'ol-allInReconfirmNotificationPeriods': UserEmailData[]
'ol-allowedExperiments': string[]
'ol-allowedImageNames': AllowedImageName[]
'ol-anonymous': boolean
'ol-baseAssetPath': string
'ol-brandVariation': Record<string, any>
@@ -162,7 +163,6 @@ export interface Meta {
owned?: boolean
}[]
'ol-i18n': { currentLangCode: string }
'ol-imageNames': ImageName[]
'ol-inactiveTutorials': string[]
'ol-institutionEmailNonCanonical': string | undefined
'ol-institutionLinked': InstitutionLink | undefined

View File

@@ -1935,7 +1935,6 @@
"right": "Right",
"ro": "Romanian",
"role": "Role",
"rolling_texlive_build": "Rolling TexLive Build",
"ru": "Russian",
"saml": "SAML",
"saml_auth_error": "Sorry, your identity provider responded with an error. Please contact your administrator for more information.",
@@ -2290,7 +2289,6 @@
"test": "Test",
"test_configuration": "Test configuration",
"test_configuration_successful": "Test configuration successful",
"test_more_recent_versions_of_texlive": "Test more recent versions of TexLive before they get turned into our annual release. This experiment adds the compiler option for a monthly build of the current TexLive version. This experimental version is primarily for testing changes to TexLive, packages, and previewing new accessibility features before theyre compiled into our annual TexLive release. Note that these images change month to month, and are untested by our team. Important projects should continue to be built on our yearly release to avoid issues that may occur when the monthly build changes.",
"tex_live_version": "TeX Live version",
"texgpt": "TeXGPT",
"text": "Text",

View File

@@ -1,6 +1,6 @@
import EditorLeftMenu from '../../../../frontend/js/features/editor-left-menu/components/editor-left-menu'
import {
ImageName,
AllowedImageName,
OverallThemeMeta,
SpellCheckLanguage,
} from '../../../../types/project-settings'
@@ -35,22 +35,20 @@ describe('<EditorLeftMenu />', function () {
},
]
const ImageNames: ImageName[] = [
const allowedImageNames: AllowedImageName[] = [
{
imageDesc: 'Image 1',
imageName: 'img-1',
allowed: true,
},
{
imageDesc: 'Image 2',
imageName: 'img-2',
allowed: true,
},
]
beforeEach(function () {
window.metaAttributesCache.set('ol-overallThemes', overallThemes)
window.metaAttributesCache.set('ol-imageNames', ImageNames)
window.metaAttributesCache.set('ol-allowedImageNames', allowedImageNames)
window.metaAttributesCache.set('ol-anonymous', false)
window.metaAttributesCache.set('ol-gitBridgeEnabled', true)
window.metaAttributesCache.set('ol-showSupport', true)

View File

@@ -2,26 +2,24 @@ import { screen, within, render } from '@testing-library/react'
import { expect } from 'chai'
import fetchMock from 'fetch-mock'
import SettingsImageName from '../../../../../../frontend/js/features/editor-left-menu/components/settings/settings-image-name'
import type { ImageName } from '../../../../../../types/project-settings'
import type { AllowedImageName } from '../../../../../../types/project-settings'
import { EditorLeftMenuProvider } from '@/features/editor-left-menu/components/editor-left-menu-context'
import { EditorProviders } from '../../../../helpers/editor-providers'
describe('<SettingsImageName />', function () {
const imageNames: ImageName[] = [
const allowedImageNames: AllowedImageName[] = [
{
imageDesc: 'Image 1',
imageName: 'img-1',
allowed: true,
},
{
imageDesc: 'Image 2',
imageName: 'img-2',
allowed: true,
},
]
beforeEach(function () {
window.metaAttributesCache.set('ol-imageNames', imageNames)
window.metaAttributesCache.set('ol-allowedImageNames', allowedImageNames)
})
afterEach(function () {
@@ -39,7 +37,7 @@ describe('<SettingsImageName />', function () {
const select = screen.getByLabelText('TeX Live version')
for (const { imageName, imageDesc } of imageNames) {
for (const { imageName, imageDesc } of allowedImageNames) {
const option = within(select).getByText(imageDesc)
expect(option.getAttribute('value')).to.equal(imageName)
}

View File

@@ -4,12 +4,6 @@ const { ObjectId } = require('mongodb-legacy')
const MODULE_PATH = '../../../../app/src/Features/Project/ProjectHelper.js'
function _mapToAllowed(images) {
return images.map(image => {
return { imageName: image.imageName, allowed: image.allowed }
})
}
describe('ProjectHelper', function () {
beforeEach(function () {
this.project = {
@@ -20,8 +14,6 @@ describe('ProjectHelper', function () {
_id: '588f3ddae8ebc1bac07c9fa4',
first_name: 'bjkdsjfk',
features: {},
labsProgram: true,
labsExperiments: ['monthly-texlive'],
}
this.adminUser = {
@@ -40,11 +32,6 @@ describe('ProjectHelper', function () {
imageDesc: 'TeX Live 2020',
alphaOnly: true,
},
{
imageName: 'texlive-full:2021.1',
imageDesc: 'TeX Live 2021',
monthlyExperimental: true,
},
],
}
@@ -141,58 +128,31 @@ describe('ProjectHelper', function () {
})
describe('getAllowedImagesForUser', function () {
it('marks alpha only images as not allowed when the user is anonymous', function () {
it('filters out alpha-only images when the user is anonymous', function () {
const images = this.ProjectHelper.getAllowedImagesForUser(null)
const imageNames = _mapToAllowed(images)
const imageNames = images.map(image => image.imageName)
expect(imageNames).to.deep.equal([
{ imageName: 'texlive-full:2018.1', allowed: true },
{ imageName: 'texlive-full:2019.1', allowed: true },
{ imageName: 'texlive-full:2020.1', allowed: false },
{ imageName: 'texlive-full:2021.1', allowed: false },
'texlive-full:2018.1',
'texlive-full:2019.1',
])
})
it('marks monthly labs images as not allowed when the user is anonymous', function () {
const images = this.ProjectHelper.getAllowedImagesForUser(null)
const imageNames = _mapToAllowed(images)
expect(imageNames).to.deep.equal([
{ imageName: 'texlive-full:2018.1', allowed: true },
{ imageName: 'texlive-full:2019.1', allowed: true },
{ imageName: 'texlive-full:2020.1', allowed: false },
{ imageName: 'texlive-full:2021.1', allowed: false },
])
})
it('marks monthly labs images as allowed when the user is enrolled', function () {
it('filters out alpha-only images when the user is not admin', function () {
const images = this.ProjectHelper.getAllowedImagesForUser(this.user)
const imageNames = _mapToAllowed(images)
const imageNames = images.map(image => image.imageName)
expect(imageNames).to.deep.equal([
{ imageName: 'texlive-full:2018.1', allowed: true },
{ imageName: 'texlive-full:2019.1', allowed: true },
{ imageName: 'texlive-full:2020.1', allowed: false },
{ imageName: 'texlive-full:2021.1', allowed: true },
])
})
it('marks alpha only images as not allowed when when the user is not admin', function () {
const images = this.ProjectHelper.getAllowedImagesForUser(this.user)
const imageNames = _mapToAllowed(images)
expect(imageNames).to.deep.equal([
{ imageName: 'texlive-full:2018.1', allowed: true },
{ imageName: 'texlive-full:2019.1', allowed: true },
{ imageName: 'texlive-full:2020.1', allowed: false },
{ imageName: 'texlive-full:2021.1', allowed: true },
'texlive-full:2018.1',
'texlive-full:2019.1',
])
})
it('returns all images when the user is admin', function () {
const images = this.ProjectHelper.getAllowedImagesForUser(this.adminUser)
const imageNames = _mapToAllowed(images)
const imageNames = images.map(image => image.imageName)
expect(imageNames).to.deep.equal([
{ imageName: 'texlive-full:2018.1', allowed: true },
{ imageName: 'texlive-full:2019.1', allowed: true },
{ imageName: 'texlive-full:2020.1', allowed: true },
{ imageName: 'texlive-full:2021.1', allowed: false },
'texlive-full:2018.1',
'texlive-full:2019.1',
'texlive-full:2020.1',
])
})
})

View File

@@ -1,10 +1,9 @@
import { Brand } from './helpers/brand'
import { OverallTheme } from '@/shared/utils/styles'
export type ImageName = {
export type AllowedImageName = {
imageDesc: string
imageName: string
allowed: boolean
}
export type DocId = Brand<string, 'DocId'>