diff --git a/services/web/app/src/Features/Project/ProjectController.mjs b/services/web/app/src/Features/Project/ProjectController.mjs index 695d61aa49..ea1087bde9 100644 --- a/services/web/app/src/Features/Project/ProjectController.mjs +++ b/services/web/app/src/Features/Project/ProjectController.mjs @@ -472,7 +472,7 @@ const _ProjectController = { user: (async () => { const user = await User.findById( userId, - 'email first_name last_name referal_id signUpDate featureSwitches features featuresEpoch refProviders alphaProgram betaProgram isAdmin ace labsProgram labsExperiments completedTutorials writefull aiErrorAssistant' + 'email first_name last_name referal_id signUpDate featureSwitches features featuresEpoch refProviders alphaProgram betaProgram isAdmin ace labsProgram labsExperiments completedTutorials writefull aiFeatures aiErrorAssistant' ).exec() // Handle case of deleted user if (!user) { @@ -844,13 +844,10 @@ const _ProjectController = { } const hasPaidSubscription = isPaidSubscription(subscription) - const hasManuallyCollectedSubscription = - subscription?.collectionMethod === 'manual' - const assistantDisabled = user.aiErrorAssistant?.enabled === false // the assistant has been manually disabled by the user - const canUseErrorAssistant = - (!hasManuallyCollectedSubscription || - fullFeatureSet?.aiErrorAssistant) && - !assistantDisabled + // todo: assist clean-up: remove other case once migration finishes + const aiFeaturesDisabled = + user.aiFeatures?.enabled === false || + user.aiErrorAssistant?.enabled === false // the assistant has been manually disabled by the user const addonPrices = isOverleafAssistBundleEnabled && @@ -958,7 +955,7 @@ const _ProjectController = { showSymbolPalette, symbolPaletteAvailable: Features.hasFeature('symbol-palette'), userRestrictions: Array.from(req.userRestrictions || []), - showAiErrorAssistant: aiFeaturesAllowed && canUseErrorAssistant, + showAiFeatures: aiFeaturesAllowed && !aiFeaturesDisabled, detachRole, metadata: { viewport: false }, showUpgradePrompt, diff --git a/services/web/app/src/Features/Project/ProjectListController.mjs b/services/web/app/src/Features/Project/ProjectListController.mjs index 8b48a51e8c..5fd7c7d797 100644 --- a/services/web/app/src/Features/Project/ProjectListController.mjs +++ b/services/web/app/src/Features/Project/ProjectListController.mjs @@ -168,7 +168,9 @@ async function projectListPage(req, res, next) { const user = await User.findById( userId, `email isAdmin emails features alphaProgram betaProgram lastPrimaryEmailCheck lastActive signUpDate ace refProviders${ - isSaas ? ' enrollment writefull completedTutorials aiErrorAssistant' : '' + isSaas + ? ' enrollment writefull completedTutorials aiFeatures aiErrorAssistant' + : '' }` ) @@ -904,7 +906,11 @@ async function _userHasAIAssist(user) { // It does NOT determine if the user has AI Assist enabled async function _canUseAIAssist(user) { // Check if the assistant has been manually disabled by the user - if (user.aiErrorAssistant?.enabled === false) { + // todo: assist clean-up: remove other case once migration finishes + if ( + user.aiErrorAssistant?.enabled === false || + user.aiFeatures?.enabled === false + ) { return false } diff --git a/services/web/app/src/Features/User/UserPagesController.mjs b/services/web/app/src/Features/User/UserPagesController.mjs index e70f9b92a8..6a69bc5057 100644 --- a/services/web/app/src/Features/User/UserPagesController.mjs +++ b/services/web/app/src/Features/User/UserPagesController.mjs @@ -147,8 +147,8 @@ async function settingsPage(req, res) { writefull: { enabled: Boolean(user.writefull?.enabled), }, - aiErrorAssistant: { - enabled: Boolean(user.aiErrorAssistant?.enabled), + aiFeatures: { + enabled: Boolean(user.aiFeatures?.enabled), }, }, labsExperiments: user.labsExperiments ?? [], diff --git a/services/web/app/src/models/User.mjs b/services/web/app/src/models/User.mjs index 041a1e8a11..4ecdee7c9f 100644 --- a/services/web/app/src/models/User.mjs +++ b/services/web/app/src/models/User.mjs @@ -198,6 +198,10 @@ export const UserSchema = new Schema( isPremium: { type: Boolean, default: false }, premiumSource: { type: String, default: null }, }, + aiFeatures: { + enabled: { type: Boolean, default: true }, + }, + // todo: assist clean-up: remove this once migration is finished aiErrorAssistant: { enabled: { type: Boolean, default: true }, }, diff --git a/services/web/app/views/project/editor/_meta.pug b/services/web/app/views/project/editor/_meta.pug index d1d871679a..2aa4ca617a 100644 --- a/services/web/app/views/project/editor/_meta.pug +++ b/services/web/app/views/project/editor/_meta.pug @@ -24,7 +24,7 @@ meta(name="ol-wsRetryHandshake" data-type="json" content=settings.wsRetryHandsha meta(name="ol-debugPdfDetach" data-type="boolean" content=debugPdfDetach) 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-showAiFeatures" data-type="boolean" content=showAiFeatures) meta(name="ol-detachRole" data-type="string" content=detachRole) meta(name="ol-imageNames" data-type="json" content=imageNames) meta(name="ol-languages" data-type="json" content=languages) diff --git a/services/web/frontend/js/features/pdf-preview/components/pdf-log-entry.tsx b/services/web/frontend/js/features/pdf-preview/components/pdf-log-entry.tsx index dafcf05376..524026b0b4 100644 --- a/services/web/frontend/js/features/pdf-preview/components/pdf-log-entry.tsx +++ b/services/web/frontend/js/features/pdf-preview/components/pdf-log-entry.tsx @@ -45,7 +45,7 @@ function PdfLogEntry({ logEntry?: LogEntry id?: string }) { - const showAiErrorAssistant = getMeta('ol-showAiErrorAssistant') + const showAiErrorAssistant = getMeta('ol-showAiFeatures') if (ruleId && HumanReadableLogsHints[ruleId]) { const hint = HumanReadableLogsHints[ruleId] diff --git a/services/web/frontend/js/utils/meta.ts b/services/web/frontend/js/utils/meta.ts index 533f3c1733..fa6ddb6e46 100644 --- a/services/web/frontend/js/utils/meta.ts +++ b/services/web/frontend/js/utils/meta.ts @@ -260,7 +260,7 @@ export interface Meta { 'ol-settingsPlans': Plan[] 'ol-shouldAllowEditingDetails': boolean 'ol-shouldLoadHotjar': boolean - 'ol-showAiErrorAssistant': boolean + 'ol-showAiFeatures': boolean 'ol-showCouponField': boolean 'ol-showGroupDiscount': boolean 'ol-showGroupsAndEnterpriseBanner': boolean diff --git a/services/web/frontend/stories/pdf-log-entry.stories.tsx b/services/web/frontend/stories/pdf-log-entry.stories.tsx index 12f7594621..7574b347f2 100644 --- a/services/web/frontend/stories/pdf-log-entry.stories.tsx +++ b/services/web/frontend/stories/pdf-log-entry.stories.tsx @@ -76,7 +76,7 @@ const MockEditorViewProvider: FC = ({ children }) => { const Provider: FC> = ({ children, }) => { - useMeta({ 'ol-showAiErrorAssistant': true }) + useMeta({ 'ol-showAiFeatures': true }) return (
{children}
diff --git a/services/web/scripts/writefull/back_fill_hiding_ai_features.mjs b/services/web/scripts/writefull/back_fill_hiding_ai_features.mjs index 60e74304fe..3c80f8e0ad 100644 --- a/services/web/scripts/writefull/back_fill_hiding_ai_features.mjs +++ b/services/web/scripts/writefull/back_fill_hiding_ai_features.mjs @@ -3,21 +3,26 @@ import { batchedUpdate } from '@overleaf/mongo-utils/batchedUpdate.js' import { scriptRunner } from '../lib/ScriptRunner.mjs' async function main(trackProgress) { - // update all applicable user models + // Set aiFeatures.enabled to false where writefull.enabled is false await batchedUpdate( db.users, - { - 'writefull.enabled': false, - }, - { - $set: { - 'aiErrorAssistant.enabled': false, - }, - }, + { 'writefull.enabled': false }, + { $set: { 'aiFeatures.enabled': false } }, undefined, undefined, { trackProgress } ) + + // Set aiFeatures.enabled to true for all other cases (true, null, or not exists) + await batchedUpdate( + db.users, + { 'writefull.enabled': { $ne: false } }, + { $set: { 'aiFeatures.enabled': true } }, + undefined, + undefined, + { trackProgress } + ) + console.log('completed syncing writefull state with error assist') } diff --git a/services/web/test/frontend/features/workbench/chat.spec.tsx b/services/web/test/frontend/features/workbench/chat.spec.tsx index fc78d84a35..3f9ae43f3f 100644 --- a/services/web/test/frontend/features/workbench/chat.spec.tsx +++ b/services/web/test/frontend/features/workbench/chat.spec.tsx @@ -9,7 +9,7 @@ import { TutorialProvider } from '@/shared/context/tutorial-context' describe('Workbench', { scrollBehavior: false }, function () { beforeEach(function () { cy.window().then(win => { - win.metaAttributesCache.set('ol-showAiErrorAssistant', true) + win.metaAttributesCache.set('ol-showAiFeatures', true) win.metaAttributesCache.set('ol-splitTestVariants', { 'ai-workbench-release': 'enabled', }) @@ -106,7 +106,7 @@ describe('Workbench', { scrollBehavior: false }, function () { describe('when AI assist is not enabled', function () { beforeEach(function () { cy.window().then(win => { - win.metaAttributesCache.set('ol-showAiErrorAssistant', false) + win.metaAttributesCache.set('ol-showAiFeatures', false) }) cy.mount(