Skip to content

Commit 6944c4a

Browse files
authored
fix(preferences, settings, atlas-service): ensure Atlas Login doesn't show in settings if user didn't get the Gen AI feature rollout (#4912)
chore(preferences, settings, atlas-service): use the same check everywhere for whether or not the feature is enabled
1 parent 6b79e1c commit 6944c4a

File tree

12 files changed

+95
-98
lines changed

12 files changed

+95
-98
lines changed

packages/atlas-service/src/main.ts

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ import preferences from 'compass-preferences-model';
4141
import { SecretStore, SECRET_STORE_KEY } from './secret-store';
4242
import { AtlasUserConfigStore } from './user-config-store';
4343
import { OidcPluginLogger } from './oidc-plugin-logger';
44-
import { getActiveUser } from 'compass-preferences-model';
44+
import { getActiveUser, isAIFeatureEnabled } from 'compass-preferences-model';
4545
import { spawn } from 'child_process';
4646

4747
const { log, track } = createLoggerAndTelemetry('COMPASS-ATLAS-SERVICE');
@@ -92,11 +92,7 @@ export async function throwIfNotOk(
9292
}
9393

9494
function throwIfAINotEnabled(atlasService: typeof AtlasService) {
95-
if (
96-
(!preferences.getPreferences().cloudFeatureRolloutAccess?.GEN_AI_COMPASS &&
97-
!preferences.getPreferences().enableAIWithoutRolloutAccess) ||
98-
!preferences.getPreferences().enableAIFeatures
99-
) {
95+
if (!isAIFeatureEnabled()) {
10096
throw new Error(
10197
"Compass' AI functionality is not currently enabled. Please try again later."
10298
);

packages/compass-e2e-tests/tests/collection-ai-query.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ describe('Collection ai query', function () {
4444

4545
telemetry = await startTelemetryServer();
4646
compass = await beforeTests({
47-
extraSpawnArgs: ['--enableAIExperience'],
47+
extraSpawnArgs: ['--enableGenAIExperience'],
4848
});
4949
browser = compass.browser;
5050
});

packages/compass-preferences-model/src/feature-flags.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ export type FeatureFlagDefinition = {
1414
};
1515

1616
export type FeatureFlags = {
17-
enableAIExperience: boolean;
17+
enableGenAIExperience: boolean;
1818
enableAIWithoutRolloutAccess: boolean;
1919
enableLgDarkmode: boolean;
2020
enableOidc: boolean; // Not capitalized "OIDC" for spawn arg casing.
@@ -31,7 +31,7 @@ export const featureFlags: Required<{
3131
* Feature flag for enabling the natural text input on the query bar.
3232
* Epic: COMPASS-6866
3333
*/
34-
enableAIExperience: {
34+
enableGenAIExperience: {
3535
stage: 'released',
3636
description: {
3737
short: 'Compass AI Features',

packages/compass-preferences-model/src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ export {
2929
setupPreferencesAndUser,
3030
getActiveUser,
3131
useIsAIFeatureEnabled,
32+
isAIFeatureEnabled,
3233
} from './utils';
3334
export type { User } from './storage';
3435

packages/compass-preferences-model/src/preferences.spec.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,7 @@ describe('Preferences class', function () {
151151
enableDevTools: 'set-global',
152152
networkTraffic: 'set-global',
153153
trackUsageStatistics: 'set-global',
154-
enableAIFeatures: 'set-global',
154+
enableGenAIFeatures: 'set-global',
155155
enableMaps: 'set-cli',
156156
enableShell: 'set-cli',
157157
readOnly: 'set-global',
@@ -215,7 +215,7 @@ describe('Preferences class', function () {
215215
},
216216
{
217217
networkTraffic: false,
218-
enableAIFeatures: false,
218+
enableGenAIFeatures: false,
219219
enableMaps: false,
220220
enableFeedbackPanel: false,
221221
trackUsageStatistics: false,
@@ -248,7 +248,7 @@ describe('Preferences class', function () {
248248

249249
const states = preferences.getPreferenceStates();
250250
expect(states).to.deep.equal({
251-
enableAIFeatures: 'hardcoded',
251+
enableGenAIFeatures: 'hardcoded',
252252
enableDevTools: 'set-global',
253253
enableMaps: 'set-cli',
254254
enableFeedbackPanel: 'hardcoded',

packages/compass-preferences-model/src/preferences.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ export type UserConfigurablePreferences = PermanentFeatureFlags &
2626
FeatureFlags & {
2727
// User-facing preferences
2828
autoUpdates: boolean;
29-
enableAIFeatures: boolean;
29+
enableGenAIFeatures: boolean;
3030
enableMaps: boolean;
3131
trackUsageStatistics: boolean;
3232
enableFeedbackPanel: boolean;
@@ -439,15 +439,15 @@ export const storedUserPreferencesProps: Required<{
439439
validator: z.boolean().default(false),
440440
type: 'boolean',
441441
},
442-
enableAIFeatures: {
442+
enableGenAIFeatures: {
443443
ui: true,
444444
cli: true,
445445
global: true,
446446
description: {
447447
short: 'Enable AI Features',
448448
long: 'Allow the use of AI features in Compass which make requests to 3rd party services. These features are currently experimental and offered as a preview to only a limited number of users.',
449449
},
450-
deriveValue: deriveNetworkTrafficOptionState('enableAIFeatures'),
450+
deriveValue: deriveNetworkTrafficOptionState('enableGenAIFeatures'),
451451
validator: z.boolean().default(true),
452452
type: 'boolean',
453453
},
@@ -1064,7 +1064,7 @@ export class Preferences {
10641064
if (!showedNetworkOptIn) {
10651065
await this.savePreferences({
10661066
autoUpdates: true,
1067-
enableAIFeatures: true,
1067+
enableGenAIFeatures: true,
10681068
enableMaps: true,
10691069
trackUsageStatistics: true,
10701070
enableFeedbackPanel: true,

packages/compass-preferences-model/src/utils.ts

Lines changed: 49 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import preferences, { preferencesAccess, usePreference } from '.';
2-
import type { ParsedGlobalPreferencesResult } from '.';
2+
import type { AllPreferences, ParsedGlobalPreferencesResult } from '.';
33
import { setupPreferences } from './setup-preferences';
44
import { UserStorage } from './storage';
55
import type { ReactHooks } from './react';
@@ -41,21 +41,58 @@ export function capMaxTimeMSAtPreferenceLimit<T>(value: T): T | number {
4141
return value;
4242
}
4343

44+
/**
45+
* Helper method to check whether or not AI feature is enabled in Compass. The
46+
* feature is considered enabled if:
47+
* - AI feature flag is enabled
48+
* - config preference that controls AI is enabled
49+
* - either mms backend rollout enabled feature for the compass user or special
50+
* option to bypass the check is passed
51+
*/
52+
export function isAIFeatureEnabled(
53+
preferences: Pick<
54+
AllPreferences,
55+
| 'enableGenAIFeatures'
56+
| 'enableGenAIExperience'
57+
| 'cloudFeatureRolloutAccess'
58+
| 'enableAIWithoutRolloutAccess'
59+
> = preferencesAccess.getPreferences()
60+
) {
61+
const {
62+
// a "kill switch" property from configuration file to be able to disable
63+
// feature in global config
64+
enableGenAIFeatures,
65+
// feature flag
66+
enableGenAIExperience,
67+
// based on mms backend rollout response
68+
cloudFeatureRolloutAccess,
69+
// feature flag to bypass rollout access check
70+
enableAIWithoutRolloutAccess,
71+
} = preferences;
72+
return (
73+
enableGenAIFeatures &&
74+
enableGenAIExperience &&
75+
(!!cloudFeatureRolloutAccess?.GEN_AI_COMPASS ||
76+
enableAIWithoutRolloutAccess)
77+
);
78+
}
79+
4480
export function useIsAIFeatureEnabled(React: ReactHooks) {
81+
const enableGenAIFeatures = usePreference('enableGenAIFeatures', React);
82+
const enableGenAIExperience = usePreference('enableGenAIExperience', React);
83+
const cloudFeatureRolloutAccess = usePreference(
84+
'cloudFeatureRolloutAccess',
85+
React
86+
);
4587
const enableAIWithoutRolloutAccess = usePreference(
4688
'enableAIWithoutRolloutAccess',
4789
React
4890
);
49-
const enableAIExperience = usePreference('enableAIExperience', React);
50-
const isAIFeatureEnabled = usePreference(
51-
'cloudFeatureRolloutAccess',
52-
React
53-
)?.GEN_AI_COMPASS;
54-
const enableAIFeatures = usePreference('enableAIFeatures', React);
5591

56-
return (
57-
enableAIExperience &&
58-
(enableAIWithoutRolloutAccess || isAIFeatureEnabled) &&
59-
enableAIFeatures
60-
);
92+
return isAIFeatureEnabled({
93+
enableGenAIFeatures,
94+
enableGenAIExperience,
95+
cloudFeatureRolloutAccess,
96+
enableAIWithoutRolloutAccess,
97+
});
6198
}

packages/compass-query-bar/src/components/query-bar.spec.tsx

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -125,8 +125,8 @@ describe('QueryBar Component', function () {
125125
beforeEach(function () {
126126
sandbox = sinon.createSandbox();
127127
sandbox.stub(preferencesAccess, 'getPreferences').returns({
128-
enableAIExperience: true,
129-
enableAIFeatures: true,
128+
enableGenAIExperience: true,
129+
enableGenAIFeatures: true,
130130
cloudFeatureRolloutAccess: {
131131
GEN_AI_COMPASS: true,
132132
},
@@ -172,14 +172,14 @@ describe('QueryBar Component', function () {
172172
});
173173
});
174174

175-
describe('with enableAIExperience ai disabled', function () {
175+
describe('with enableGenAIExperience ai disabled', function () {
176176
let sandbox: sinon.SinonSandbox;
177177

178178
beforeEach(function () {
179179
sandbox = sinon.createSandbox();
180180
sandbox.stub(preferencesAccess, 'getPreferences').returns({
181-
enableAIExperience: false,
182-
enableAIFeatures: true,
181+
enableGenAIExperience: false,
182+
enableGenAIFeatures: true,
183183
cloudFeatureRolloutAccess: {
184184
GEN_AI_COMPASS: true,
185185
},
@@ -198,14 +198,14 @@ describe('QueryBar Component', function () {
198198
});
199199
});
200200

201-
describe('with enableAIFeatures ai disabled', function () {
201+
describe('with enableGenAIFeatures ai disabled', function () {
202202
let sandbox: sinon.SinonSandbox;
203203

204204
beforeEach(function () {
205205
sandbox = sinon.createSandbox();
206206
sandbox.stub(preferencesAccess, 'getPreferences').returns({
207-
enableAIExperience: true,
208-
enableAIFeatures: false,
207+
enableGenAIExperience: true,
208+
enableGenAIFeatures: false,
209209
cloudFeatureRolloutAccess: {
210210
GEN_AI_COMPASS: true,
211211
},

packages/compass-settings/src/components/modal.tsx

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import Sidebar from './sidebar';
1919
import { saveSettings, closeModal } from '../stores/settings';
2020
import type { RootState } from '../stores';
2121
import { getUserInfo } from '../stores/atlas-login';
22+
import { useIsAIFeatureEnabled } from 'compass-preferences-model';
2223

2324
type Settings = {
2425
name: string;
@@ -27,7 +28,7 @@ type Settings = {
2728

2829
type SettingsModalProps = {
2930
isOpen: boolean;
30-
isOIDCTabEnabled: boolean;
31+
isOIDCEnabled: boolean;
3132
onMount?: () => void;
3233
onClose: () => void;
3334
onSave: () => void;
@@ -59,9 +60,10 @@ export const SettingsModal: React.FunctionComponent<SettingsModalProps> = ({
5960
onMount,
6061
onClose,
6162
onSave,
62-
isOIDCTabEnabled,
63+
isOIDCEnabled,
6364
hasChangedSettings,
6465
}) => {
66+
const aiFeatureEnabled = useIsAIFeatureEnabled(React);
6567
const onMountRef = useRef(onMount);
6668

6769
useEffect(() => {
@@ -74,7 +76,11 @@ export const SettingsModal: React.FunctionComponent<SettingsModalProps> = ({
7476
{ name: 'Privacy', component: PrivacySettings },
7577
];
7678

77-
if (isOIDCTabEnabled) {
79+
if (
80+
isOIDCEnabled ||
81+
// because oidc options overlap with atlas login used for ai feature
82+
aiFeatureEnabled
83+
) {
7884
settings.push({
7985
name: 'OIDC (Preview)',
8086
component: OIDCSettings,
@@ -133,12 +139,7 @@ export default connect(
133139
return {
134140
isOpen:
135141
state.settings.isModalOpen && state.settings.loadingState === 'ready',
136-
isOIDCTabEnabled:
137-
!!state.settings.settings.enableOidc ||
138-
// because oidc options overlap with atlas login used for ai feature
139-
!!state.settings.settings.enableAIWithoutRolloutAccess ||
140-
!!state.settings.settings.enableAIExperience ||
141-
!!state.settings.settings.enableAIFeatures,
142+
isOIDCEnabled: !!state.settings.settings.enableOidc,
142143
hasChangedSettings: state.settings.updatedFields.length > 0,
143144
};
144145
},

packages/compass-settings/src/components/settings/feature-preview.tsx

Lines changed: 9 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,8 @@ import SettingsList from './settings-list';
33
import {
44
usePreference,
55
featureFlags,
6-
withPreferences,
6+
useIsAIFeatureEnabled,
77
} from 'compass-preferences-model';
8-
import type { UserPreferences } from 'compass-preferences-model';
9-
import { connect } from 'react-redux';
10-
import type { RootState } from '../../stores';
118
import { ConnectedAtlasLoginSettings } from './atlas-login';
129
import { css, spacing } from '@mongodb-js/compass-components';
1310

@@ -36,33 +33,24 @@ function useShouldShowPreviewFeatures(): boolean {
3633

3734
export function useShouldShowFeaturePreviewSettings(): boolean {
3835
// We want show the feature preview settings tab if:
36+
// - AI feature flag is enabled
3937
// - there are feature flags in preview stage
4038
// - or if:
4139
// - we are in a development environment or 'showDevFeatureFlags' is explicitly enabled
4240
// - and there are feature flags in 'development' stage.
43-
// - AI feature flag is enabled
44-
const enableAIWithoutRolloutAccess = usePreference(
45-
'enableAIWithoutRolloutAccess',
46-
React
47-
);
48-
const enableAIExperience = usePreference('enableAIExperience', React);
41+
const aiFeatureEnabled = useIsAIFeatureEnabled(React);
4942
const showDevFeatures = useShouldShowDevFeatures();
5043
const showPreviewFeatures = useShouldShowPreviewFeatures();
51-
return (
52-
enableAIWithoutRolloutAccess ||
53-
enableAIExperience ||
54-
showPreviewFeatures ||
55-
showDevFeatures
56-
);
44+
45+
return aiFeatureEnabled || showPreviewFeatures || showDevFeatures;
5746
}
5847

5948
const atlasSettingsContainerStyles = css({
6049
marginTop: spacing[3],
6150
});
6251

63-
export const FeaturePreviewSettings: React.FunctionComponent<{
64-
showAtlasLoginSettings?: boolean;
65-
}> = ({ showAtlasLoginSettings }) => {
52+
export const FeaturePreviewSettings: React.FunctionComponent = () => {
53+
const aiFeatureEnabled = useIsAIFeatureEnabled(React);
6654
const showPreviewFeatures = useShouldShowPreviewFeatures();
6755
const showDevFeatures = useShouldShowDevFeatures();
6856

@@ -73,7 +61,7 @@ export const FeaturePreviewSettings: React.FunctionComponent<{
7361
your own risk!
7462
</div>
7563

76-
{showAtlasLoginSettings && (
64+
{aiFeatureEnabled && (
7765
<div className={atlasSettingsContainerStyles}>
7866
<ConnectedAtlasLoginSettings></ConnectedAtlasLoginSettings>
7967
</div>
@@ -92,30 +80,4 @@ export const FeaturePreviewSettings: React.FunctionComponent<{
9280
);
9381
};
9482

95-
export default withPreferences(
96-
connect(
97-
(
98-
state: RootState,
99-
ownProps: {
100-
enableAIExperience?: boolean;
101-
enableAIWithoutRolloutAccess?: boolean;
102-
cloudFeatureRolloutAccess?: UserPreferences['cloudFeatureRolloutAccess'];
103-
}
104-
) => {
105-
return {
106-
showAtlasLoginSettings:
107-
state.settings.settings.enableAIExperience ||
108-
['authenticated', 'in-progress'].includes(state.atlasLogin.status) ||
109-
ownProps.enableAIExperience ||
110-
ownProps.enableAIWithoutRolloutAccess ||
111-
ownProps.cloudFeatureRolloutAccess?.GEN_AI_COMPASS,
112-
};
113-
}
114-
)(FeaturePreviewSettings),
115-
[
116-
'enableAIExperience',
117-
'cloudFeatureRolloutAccess',
118-
'enableAIWithoutRolloutAccess',
119-
],
120-
React
121-
);
83+
export default FeaturePreviewSettings;

0 commit comments

Comments
 (0)