Bläddra i källkod

feat: migrate from aiErrorAssist naming for disabling AI features to aiFeatures.enabled to avoid confusion (#31273)

feat: keep aiErrorAssistant as setting on user object until migration is run
GitOrigin-RevId: df53914163566065d0b91b8d130476fbcdf1ea96
Jimmy Domagala-Tang 6 månader sedan
förälder
incheckning
551d7b3908

+ 6 - 9
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,

+ 8 - 2
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
   }
 

+ 2 - 2
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 ?? [],

+ 4 - 0
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 },
     },

+ 1 - 1
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)

+ 1 - 1
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]

+ 1 - 1
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

+ 1 - 1
services/web/frontend/stories/pdf-log-entry.stories.tsx

@@ -76,7 +76,7 @@ const MockEditorViewProvider: FC<React.PropsWithChildren> = ({ children }) => {
 const Provider: FC<React.PropsWithChildren<{ children: ReactNode }>> = ({
   children,
 }) => {
-  useMeta({ 'ol-showAiErrorAssistant': true })
+  useMeta({ 'ol-showAiFeatures': true })
   return (
     <MockEditorViewProvider>
       <div className="logs-pane p-2">{children}</div>

+ 14 - 9
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')
 }
 

+ 2 - 2
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(
         <Providers aiAssistEnabled={false}>