diff --git a/packages/atlas-service/src/atlas-service.spec.ts b/packages/atlas-service/src/atlas-service.spec.ts
index 209737f1baf..4676114596a 100644
--- a/packages/atlas-service/src/atlas-service.spec.ts
+++ b/packages/atlas-service/src/atlas-service.spec.ts
@@ -29,9 +29,10 @@ function getAtlasService(
const atlasService = new AtlasService(
authService,
preferences,
- createNoopLogger()
+ createNoopLogger(),
+ undefined,
+ ATLAS_CONFIG
);
- atlasService['config'] = ATLAS_CONFIG;
return atlasService;
}
diff --git a/packages/atlas-service/src/atlas-service.ts b/packages/atlas-service/src/atlas-service.ts
index 4ffe27627d6..ce8d4138548 100644
--- a/packages/atlas-service/src/atlas-service.ts
+++ b/packages/atlas-service/src/atlas-service.ts
@@ -52,14 +52,17 @@ function getAutomationAgentClusterId(
}
export class AtlasService {
- private config: AtlasServiceConfig;
constructor(
private readonly authService: AtlasAuthService,
private readonly preferences: PreferencesAccess,
private readonly logger: Logger,
- private readonly options?: AtlasServiceOptions
- ) {
- this.config = getAtlasConfig(preferences);
+ private readonly options?: AtlasServiceOptions,
+ private readonly defaultConfigOverride?: AtlasServiceConfig
+ ) {}
+ // Config value is dynamic to make sure that process.env overrides are taken
+ // into account in runtime
+ get config(): AtlasServiceConfig {
+ return this.defaultConfigOverride ?? getAtlasConfig(this.preferences);
}
adminApiEndpoint(path?: string): string {
return `${this.config.atlasApiBaseUrl}${normalizePath(path)}`;
diff --git a/packages/atlas-service/src/util.ts b/packages/atlas-service/src/util.ts
index 0fa67be649c..080be1f5915 100644
--- a/packages/atlas-service/src/util.ts
+++ b/packages/atlas-service/src/util.ts
@@ -255,6 +255,7 @@ export function getAtlasConfig(
const { atlasServiceBackendPreset } = preferences.getPreferences();
const envConfig = {
atlasApiBaseUrl: process.env.COMPASS_ATLAS_SERVICE_UNAUTH_BASE_URL_OVERRIDE,
+ cloudBaseUrl: process.env.COMPASS_CLOUD_BASE_URL_OVERRIDE,
atlasLogin: {
clientId: process.env.COMPASS_CLIENT_ID_OVERRIDE,
issuer: process.env.COMPASS_OIDC_ISSUER_OVERRIDE,
diff --git a/packages/compass-assistant/src/compass-assistant-provider.spec.tsx b/packages/compass-assistant/src/compass-assistant-provider.spec.tsx
index 58351688d07..c5368006fb6 100644
--- a/packages/compass-assistant/src/compass-assistant-provider.spec.tsx
+++ b/packages/compass-assistant/src/compass-assistant-provider.spec.tsx
@@ -28,7 +28,7 @@ import { CompassAssistantDrawer } from './compass-assistant-drawer';
import { createBrokenTransport, createMockChat } from '../test/utils';
import type { AtlasAiService } from '@mongodb-js/compass-generative-ai/provider';
import type { TrackFunction } from '@mongodb-js/compass-telemetry';
-import { createLogger } from '@mongodb-js/compass-logging';
+import { createNoopLogger } from '@mongodb-js/compass-logging/provider';
function createMockProvider({
mockAtlasService,
@@ -480,7 +480,7 @@ describe('CompassAssistantProvider', function () {
.stub()
.returns('https://localhost:3000'),
} as unknown as AtlasService,
- logger: createLogger('COMPASS-ASSISTANT-TEST'),
+ logger: createNoopLogger(),
track: track as unknown as TrackFunction,
});
await renderOpenAssistantDrawer({
@@ -654,47 +654,42 @@ describe('CompassAssistantProvider', function () {
});
});
+ let sandbox: sinon.SinonSandbox;
+
+ beforeEach(function () {
+ sandbox = sinon.createSandbox();
+ });
+
+ afterEach(function () {
+ if (sandbox) {
+ sandbox.reset();
+ }
+ });
+
it('uses the Atlas Service assistantApiEndpoint', async function () {
const mockAtlasService = {
- assistantApiEndpoint: sinon
+ assistantApiEndpoint: sandbox
.stub()
.returns('https://example.com/assistant/api/v1'),
};
- const mockAtlasAiService = {
- ensureAiFeatureAccess: sinon.stub().callsFake(() => {
- return Promise.resolve();
- }),
- };
-
- const mockAtlasAuthService = {};
-
- const MockedProvider = CompassAssistantProvider.withMockServices({
+ const chat = createDefaultChat({
+ originForPrompt: 'foo',
+ appNameForPrompt: 'bar',
atlasService: mockAtlasService as unknown as AtlasService,
- atlasAiService: mockAtlasAiService as unknown as AtlasAiService,
- atlasAuthService: mockAtlasAuthService as unknown as AtlasAuthService,
+ logger: createNoopLogger(),
+ track: () => undefined,
});
- render(
-
-
-
- ,
- {
- preferences: {
- enableAIAssistant: true,
- enableGenAIFeatures: true,
- enableGenAIFeaturesAtlasOrg: true,
- cloudFeatureRolloutAccess: { GEN_AI_COMPASS: true },
- },
- }
- );
+ const fetchStub = sandbox
+ .stub(globalThis, 'fetch')
+ .resolves({ ok: true, headers: [] } as any);
- await waitFor(() => {
- expect(mockAtlasService.assistantApiEndpoint.calledOnce).to.be.true;
- });
+ await chat.sendMessage({ text: 'hello' });
+
+ expect(mockAtlasService.assistantApiEndpoint.calledOnce).to.be.true;
+ expect(fetchStub.lastCall.args[0]).to.eq(
+ 'https://example.com/assistant/api/v1/responses'
+ );
});
});
diff --git a/packages/compass-assistant/src/compass-assistant-provider.tsx b/packages/compass-assistant/src/compass-assistant-provider.tsx
index e9ced74b509..db7633f65c6 100644
--- a/packages/compass-assistant/src/compass-assistant-provider.tsx
+++ b/packages/compass-assistant/src/compass-assistant-provider.tsx
@@ -334,6 +334,7 @@ export function createDefaultChat({
transport: Chat['transport'];
};
}): Chat {
+ const initialBaseUrl = 'http://PLACEHOLDER_BASE_URL_TO_BE_REPLACED.invalid';
return new Chat({
transport:
options?.transport ??
@@ -343,8 +344,21 @@ export function createDefaultChat({
target: appNameForPrompt,
}),
model: createOpenAI({
- baseURL: atlasService.assistantApiEndpoint(),
+ baseURL: initialBaseUrl,
apiKey: '',
+ fetch(url, init) {
+ return globalThis.fetch(
+ // The `baseUrl` can be dynamically changed, but `createOpenAI`
+ // constructor doesn't allow us to change it after initial call.
+ // Instead we're going to update it every time the fetch call
+ // happens
+ String(url).replace(
+ initialBaseUrl,
+ atlasService.assistantApiEndpoint()
+ ),
+ init
+ );
+ },
}).responses('mongodb-chat-latest'),
}),
onError: (err: Error) => {
diff --git a/packages/compass-components/src/components/compass-components-provider.tsx b/packages/compass-components/src/components/compass-components-provider.tsx
index 8da0abfaf86..754edc45a8c 100644
--- a/packages/compass-components/src/components/compass-components-provider.tsx
+++ b/packages/compass-components/src/components/compass-components-provider.tsx
@@ -44,6 +44,11 @@ type CompassComponentsProviderProps = {
* Set to disable context menus in the application.
*/
disableContextMenus?: boolean;
+
+ /**
+ * Set to disable all guide cues in the application.
+ */
+ disableGuideCues?: boolean;
} & {
onNextGuideGue?: GuideCueProviderProps['onNext'];
onNextGuideCueGroup?: GuideCueProviderProps['onNextGroup'];
@@ -128,7 +133,8 @@ export const CompassComponentsProvider = ({
utmMedium,
stackedElementsZIndex,
popoverPortalContainer: _popoverPortalContainer,
- disableContextMenus,
+ disableContextMenus = false,
+ disableGuideCues = false,
...signalHooksProviderProps
}: CompassComponentsProviderProps) => {
const darkMode = useDarkMode(_darkMode);
@@ -164,6 +170,7 @@ export const CompassComponentsProvider = ({
utmMedium={utmMedium}
>
diff --git a/packages/compass-components/src/components/guide-cue/guide-cue-service.spec.ts b/packages/compass-components/src/components/guide-cue/guide-cue-service.spec.ts
index 625ef8450d7..0c6604afa08 100644
--- a/packages/compass-components/src/components/guide-cue/guide-cue-service.spec.ts
+++ b/packages/compass-components/src/components/guide-cue/guide-cue-service.spec.ts
@@ -604,10 +604,8 @@ describe('GuideCueService', function () {
});
context('when disabled', function () {
- const initialValue = process.env.DISABLE_GUIDE_CUES;
before(function () {
- process.env.DISABLE_GUIDE_CUES = 'true';
-
+ guideCueService.enabled = false;
guideCueService.addCue({ cueId: '1', isIntersecting: true, step: 1 });
guideCueService.addCue({
cueId: '3',
@@ -624,7 +622,7 @@ describe('GuideCueService', function () {
});
after(function () {
- process.env.DISABLE_GUIDE_CUES = initialValue;
+ guideCueService.enabled = true;
});
it('does not add a cue', function () {
diff --git a/packages/compass-components/src/components/guide-cue/guide-cue-service.ts b/packages/compass-components/src/components/guide-cue/guide-cue-service.ts
index 9443a6108e3..df06d14359d 100644
--- a/packages/compass-components/src/components/guide-cue/guide-cue-service.ts
+++ b/packages/compass-components/src/components/guide-cue/guide-cue-service.ts
@@ -38,12 +38,14 @@ export class GuideCueService extends EventTarget {
private _activeGroupId: GroupName | null = null;
private _activeCue: Cue | null = null;
+ enabled = true;
+
constructor(private readonly _storage: GuideCueStorage) {
super();
}
addCue(cue: Omit) {
- if (process.env.DISABLE_GUIDE_CUES === 'true') {
+ if (!this.enabled) {
return;
}
const cueIndex = this.getCueIndex(cue.cueId, cue.groupId);
diff --git a/packages/compass-components/src/components/guide-cue/guide-cue.tsx b/packages/compass-components/src/components/guide-cue/guide-cue.tsx
index d036c6a9b50..a9f840f0387 100644
--- a/packages/compass-components/src/components/guide-cue/guide-cue.tsx
+++ b/packages/compass-components/src/components/guide-cue/guide-cue.tsx
@@ -33,10 +33,16 @@ export type GroupCue = Cue & {
type GuideCueContextValue = {
onNext?: (cue: Cue) => void;
onNextGroup?: (groupCue: GroupCue) => void;
+ enabled?: boolean;
};
-const GuideCueContext = React.createContext({});
+
+const GuideCueContext = React.createContext({
+ enabled: true,
+});
+
export const GuideCueProvider: React.FC = ({
children,
+ enabled = true,
...callbacks
}) => {
const callbacksRef = useRef(callbacks);
@@ -49,9 +55,13 @@ export const GuideCueProvider: React.FC = ({
onNextGroup(groupCue: GroupCue) {
callbacksRef.current.onNextGroup?.(groupCue);
},
+ enabled,
}),
- []
+ [enabled]
);
+ useEffect(() => {
+ guideCueService.enabled = enabled;
+ }, [enabled]);
return (
{children}
@@ -253,7 +263,7 @@ export const GuideCue = ({
return (
<>
- {readyToRender && (
+ {context.enabled && readyToRender && (
(
browser: CompassBrowser,
name: K
): Promise {
- return await browser.execute(async (_name) => {
- return (
- // eslint-disable-next-line @typescript-eslint/no-require-imports
- (await require('electron').ipcRenderer.invoke('compass:get-preferences'))[
- _name
- ]
+ return (await getFeatures(browser))[name];
+}
+
+export async function getFeatures(
+ browser: CompassBrowser
+): Promise {
+ if (isTestingWeb()) {
+ // When running in Compass web we cannot use the IPC to read the
+ // preferences so we use a global function
+ await browser.waitUntil(async () => {
+ return await browser.execute(() => {
+ return (
+ Symbol.for('@compass-web-sandbox-preferences-access') in globalThis
+ );
+ });
+ });
+ return await browser.execute(() => {
+ return (globalThis as any)[
+ Symbol.for('@compass-web-sandbox-preferences-access')
+ ].getPreferences();
+ });
+ }
+ return await browser.execute(async () => {
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
+ return await require('electron').ipcRenderer.invoke(
+ 'compass:get-preferences'
);
- }, name);
+ });
}
diff --git a/packages/compass-e2e-tests/helpers/commands/set-env.ts b/packages/compass-e2e-tests/helpers/commands/set-env.ts
index 40ca31ae95b..58b2df75b21 100644
--- a/packages/compass-e2e-tests/helpers/commands/set-env.ts
+++ b/packages/compass-e2e-tests/helpers/commands/set-env.ts
@@ -2,8 +2,7 @@ import type { CompassBrowser } from '../compass-browser';
import { isTestingWeb } from '../test-runner-context';
/**
- * Sets an environment variable override in Compass Web.
- * This is only supported in Compass Web tests, not in Compass Desktop.
+ * Sets an environment variable override in Compass. This works the same way both for Compass desktop and web runtimes
*
* @example
* // Set the Atlas service URL override in a test
@@ -20,24 +19,35 @@ export async function setEnv(
browser: CompassBrowser,
key: string,
value: string
-): Promise {
+): Promise> {
+ // In web, use injected function to set the env
if (isTestingWeb()) {
- // When running in Compass web we use a global function to set env vars
- await browser.execute(
+ await browser.waitUntil(async () => {
+ return await browser.execute(() => {
+ return Symbol.for('@compass-web-sandbox-set-env') in globalThis;
+ });
+ });
+ return await browser.execute(
(_key, _value) => {
const kSandboxSetEnvFn = Symbol.for('@compass-web-sandbox-set-env');
// eslint-disable-next-line @typescript-eslint/no-explicit-any
- (globalThis as any)[kSandboxSetEnvFn]?.(_key, _value);
+ return (globalThis as any)[kSandboxSetEnvFn](_key, _value) as Record<
+ string,
+ string
+ >;
+ },
+ key,
+ value
+ );
+ } else {
+ // In electron, just set the existing global var
+ return await browser.execute(
+ (_key, _value) => {
+ process.env[_key] = _value;
+ return process.env as Record;
},
key,
value
);
- return;
}
-
- // When running in Compass desktop, we can't dynamically change env vars
- // after the process has started, so we throw an error
- throw new Error(
- 'setEnv is only supported in Compass web. For Compass desktop, set environment variables before starting the app.'
- );
}
diff --git a/packages/compass-e2e-tests/helpers/commands/set-feature.ts b/packages/compass-e2e-tests/helpers/commands/set-feature.ts
index 7d37bede91e..b8b68951bb4 100644
--- a/packages/compass-e2e-tests/helpers/commands/set-feature.ts
+++ b/packages/compass-e2e-tests/helpers/commands/set-feature.ts
@@ -12,17 +12,24 @@ export async function setFeature(
): Promise {
if (isTestingWeb()) {
// When running in Compass web we cannot use the IPC to update the
- // preferences so we use a global function.
+ // preferences so we use a global function
+ await browser.waitUntil(async () => {
+ return await browser.execute(() => {
+ return (
+ Symbol.for('@compass-web-sandbox-preferences-access') in globalThis
+ );
+ });
+ });
await browser.execute(
async (_name, _value) => {
const kSandboxUpdateFn = Symbol.for(
- '@compass-web-sandbox-update-preferences'
+ '@compass-web-sandbox-preferences-access'
);
const attributes: Partial = {
[_name]: _value === null ? undefined : _value,
};
// eslint-disable-next-line @typescript-eslint/no-explicit-any
- await (globalThis as any)[kSandboxUpdateFn]?.(attributes);
+ await (globalThis as any)[kSandboxUpdateFn].savePreferences(attributes);
},
name,
value
diff --git a/packages/compass-e2e-tests/helpers/compass-web-sandbox.ts b/packages/compass-e2e-tests/helpers/compass-web-sandbox.ts
index be0b83805dd..caccb9f9608 100644
--- a/packages/compass-e2e-tests/helpers/compass-web-sandbox.ts
+++ b/packages/compass-e2e-tests/helpers/compass-web-sandbox.ts
@@ -11,7 +11,6 @@ import {
} from './test-runner-paths';
import type { ConnectionInfo } from '@mongodb-js/connection-info';
import ConnectionString from 'mongodb-connection-string-url';
-import { MOCK_ASSISTANT_SERVER_PORT } from './assistant-service';
const debug = Debug('compass-e2e-tests:compass-web-sandbox');
@@ -22,9 +21,6 @@ const debug = Debug('compass-e2e-tests:compass-web-sandbox');
process.env.OPEN_BROWSER = 'false'; // tell webpack dev server not to open the default browser
process.env.DISABLE_DEVSERVER_OVERLAY = 'true';
process.env.APP_ENV = 'webdriverio';
-// Set the assistant base URL override for tests so we can mock the assistant server
-process.env.COMPASS_ASSISTANT_BASE_URL_OVERRIDE = `http://localhost:${MOCK_ASSISTANT_SERVER_PORT}`;
-process.env.COMPASS_OVERRIDE_ENABLE_AI_FEATURES = 'true';
const wait = (ms: number) => {
return new Promise((resolve) => {
diff --git a/packages/compass-e2e-tests/helpers/compass.ts b/packages/compass-e2e-tests/helpers/compass.ts
index 103598c880b..c6a4f4dce24 100644
--- a/packages/compass-e2e-tests/helpers/compass.ts
+++ b/packages/compass-e2e-tests/helpers/compass.ts
@@ -597,6 +597,34 @@ async function processCommonOpts({
};
}
+async function setCommonRendererEnv(browser: CompassBrowser) {
+ // TODO(COMPASS-9977) Turn off virtual scrolling in e2e tests until we can fix
+ // browser.scrollToVirtualItem() to work with it
+ await browser.setEnv('COMPASS_DISABLE_VIRTUAL_TABLE_RENDERING', 'true');
+}
+
+async function setCommonFeatures(browser: CompassBrowser) {
+ // Guide cues might affect too many tests in a way where the auto showing of the cue prevents
+ // clicks from working on elements. Dealing with this case-by-case is way too much work, so
+ // we disable the cues completely for the e2e tests
+ await browser.setFeature('enableGuideCues', false);
+
+ // Making sure end-of-life connection modal is not shown, simplify any test connecting to such a server
+ await browser.setFeature('showEndOfLifeConnectionModal', false);
+
+ // It's helpful to have devtools pre-enabled when running tests
+ await browser.setFeature('enableDevTools', true);
+
+ const { enableGuideCues, showEndOfLifeConnectionModal, enableDevTools } =
+ await browser.getFeatures();
+
+ debug('Updated common feature flags to new value', {
+ enableGuideCues,
+ showEndOfLifeConnectionModal,
+ enableDevTools,
+ });
+}
+
async function startCompassElectron(
name: string,
opts: StartCompassOptions = {}
@@ -652,18 +680,6 @@ async function startCompassElectron(
process.env.HADRON_PRODUCT_NAME_OVERRIDE = 'MongoDB Compass WebdriverIO';
}
- // Guide cues might affect too many tests in a way where the auto showing of the cue prevents
- // clicks from working on elements. Dealing with this case-by-case is way too much work, so
- // we disable the cues completely for the e2e tests
- process.env.DISABLE_GUIDE_CUES = 'true';
-
- // Making sure end-of-life connection modal is not shown, simplify any test connecting to such a server
- process.env.COMPASS_DISABLE_END_OF_LIFE_CONNECTION_MODAL = 'true';
-
- // TODO(COMPASS-9977) Turn off virtual scrolling in e2e tests until we can fix
- // browser.scrollToVirtualItem() to work with it
- process.env.COMPASS_DISABLE_VIRTUAL_TABLE_RENDERING = 'true';
-
const options = {
automationProtocol: 'webdriver' as const,
capabilities: {
@@ -772,7 +788,7 @@ export type StoredAtlasCloudCookies = {
expirationDate: number;
}[];
-export async function startBrowser(
+async function startBrowser(
name: string,
// eslint-disable-next-line @typescript-eslint/no-unused-vars
opts: StartCompassOptions = {}
@@ -1125,6 +1141,9 @@ export async function init(
});
}
+ await setCommonRendererEnv(browser);
+ await setCommonFeatures(browser);
+
if (compass.needsCloseWelcomeModal) {
await browser.closeWelcomeModal();
}
diff --git a/packages/compass-e2e-tests/helpers/atlas-service.ts b/packages/compass-e2e-tests/helpers/mock-atlas-service.ts
similarity index 56%
rename from packages/compass-e2e-tests/helpers/atlas-service.ts
rename to packages/compass-e2e-tests/helpers/mock-atlas-service.ts
index cad0687736c..47d7068fefb 100644
--- a/packages/compass-e2e-tests/helpers/atlas-service.ts
+++ b/packages/compass-e2e-tests/helpers/mock-atlas-service.ts
@@ -61,33 +61,62 @@ export async function startMockAtlasServiceServer(
let response = _response;
const server = http
.createServer((req, res) => {
- if (req.method === 'GET') {
- requests.push({
- req,
- content: null,
- });
- return aiFeatureEnableResponse(req, res);
+ res.setHeader('Access-Control-Allow-Origin', req.headers.origin ?? '*');
+ res.setHeader('Access-Control-Allow-Credentials', 'true');
+ res.setHeader(
+ 'Access-Control-Allow-Headers',
+ req.headers['access-control-request-headers'] ?? '*'
+ );
+
+ if (req.method === 'OPTIONS') {
+ res.statusCode = 200;
+ res.end();
+ return;
+ }
+
+ if (req.url?.startsWith('/settings/optInDataExplorerGenAIFeatures')) {
+ res.statusCode = 200;
+ res.end();
+ return;
}
- let body = '';
- req
- .setEncoding('utf8')
- .on('data', (chunk) => {
- body += chunk;
- })
- .on('end', () => {
- const jsonObject = JSON.parse(body);
+ if (req.url?.startsWith('/unauth/ai/api/v1/mql-query')) {
+ if (req.method === 'GET') {
requests.push({
req,
- content: jsonObject,
+ content: null,
});
+ return aiFeatureEnableResponse(req, res);
+ }
+
+ let body = '';
+
+ req
+ .setEncoding('utf8')
+ .on('data', (chunk) => {
+ body += chunk;
+ })
+ .on('end', () => {
+ const jsonObject = JSON.parse(body);
+ requests.push({
+ req,
+ content: jsonObject,
+ });
+
+ res.setHeader('Content-Type', 'application/json');
+ if (response.status !== 200) {
+ res.writeHead(response.status);
+ }
+ return res.end(JSON.stringify(response.body));
+ });
+
+ return;
+ }
- res.setHeader('Content-Type', 'application/json');
- if (response.status !== 200) {
- res.writeHead(response.status);
- }
- return res.end(JSON.stringify(response.body));
- });
+ res.statusCode = 404;
+ res.statusMessage =
+ 'Route not found in the mock Atlas backend. Did you forget to add a mock route support?';
+ res.end();
})
.listen(0);
await once(server, 'listening');
diff --git a/packages/compass-e2e-tests/helpers/test-runner-global-fixtures.ts b/packages/compass-e2e-tests/helpers/test-runner-global-fixtures.ts
index 50d6fdd520a..8a6def6ee32 100644
--- a/packages/compass-e2e-tests/helpers/test-runner-global-fixtures.ts
+++ b/packages/compass-e2e-tests/helpers/test-runner-global-fixtures.ts
@@ -93,10 +93,6 @@ export async function mochaGlobalSetup(this: Mocha.Runner) {
if (isTestingWeb(context) && !isTestingAtlasCloudExternal(context)) {
debug('Starting Compass Web server ...');
- // TODO(COMPASS-9977) Turn off virtual scrolling in e2e tests until we can fix
- // browser.scrollToVirtualItem() to work with it
- process.env.COMPASS_DISABLE_VIRTUAL_TABLE_RENDERING = 'true';
-
if (isTestingAtlasCloudSandbox(context)) {
const compassWeb = await spawnCompassWebSandboxAndSignInToAtlas(
{
diff --git a/packages/compass-e2e-tests/tests/assistant.test.ts b/packages/compass-e2e-tests/tests/assistant.test.ts
index d1dce32ddd7..a6366b13829 100644
--- a/packages/compass-e2e-tests/tests/assistant.test.ts
+++ b/packages/compass-e2e-tests/tests/assistant.test.ts
@@ -9,14 +9,12 @@ import {
cleanup,
screenshotIfFailed,
DEFAULT_CONNECTION_NAME_1,
- skipForWeb,
} from '../helpers/compass';
import type { Compass } from '../helpers/compass';
import * as Selectors from '../helpers/selectors';
-import { startMockAtlasServiceServer } from '../helpers/atlas-service';
+import { startMockAtlasServiceServer } from '../helpers/mock-atlas-service';
import { startMockAssistantServer } from '../helpers/assistant-service';
import type { MockAssistantResponse } from '../helpers/assistant-service';
-import { isTestingWeb } from '../helpers/test-runner-context';
import { context } from '../helpers/test-runner-context';
@@ -51,12 +49,22 @@ describe('MongoDB Assistant', function () {
mockAtlasServer = await startMockAtlasServiceServer();
mockAssistantServer = await startMockAssistantServer();
- process.env.COMPASS_ATLAS_SERVICE_UNAUTH_BASE_URL_OVERRIDE =
- mockAtlasServer.endpoint;
-
telemetry = await startTelemetryServer();
compass = await init(this.test?.fullTitle());
+ await compass.browser.setEnv(
+ 'COMPASS_ATLAS_SERVICE_UNAUTH_BASE_URL_OVERRIDE',
+ mockAtlasServer.endpoint
+ );
+ await compass.browser.setEnv(
+ 'COMPASS_CLOUD_BASE_URL_OVERRIDE',
+ mockAtlasServer.endpoint
+ );
+ await compass.browser.setEnv(
+ 'COMPASS_ASSISTANT_BASE_URL_OVERRIDE',
+ mockAssistantServer.endpoint
+ );
+
sendMessage = async (
text: string,
{
@@ -124,13 +132,8 @@ describe('MongoDB Assistant', function () {
};
setAIFeatures = async (newValue: boolean) => {
- if (isTestingWeb()) {
- await browser.setEnv(
- 'COMPASS_OVERRIDE_ENABLE_AI_FEATURES',
- newValue ? 'true' : 'false'
- );
- }
await browser.setFeature('enableGenAIFeatures', newValue);
+ await browser.setFeature('enableGenAISampleDocumentPassing', newValue);
if (newValue) {
await browser.$(Selectors.AssistantDrawerButton).waitForDisplayed();
@@ -142,26 +145,6 @@ describe('MongoDB Assistant', function () {
};
setAIOptIn = async (newValue: boolean) => {
- if (
- isTestingWeb() ||
- ((await browser.getFeature('optInGenAIFeatures')) === true &&
- newValue === false)
- ) {
- await cleanup(compass);
- // Reseting the opt-in to false can be tricky so it's best to start over in this case.
- compass = await init(this.test?.fullTitle(), { firstRun: true });
- await setup();
-
- if (isTestingWeb()) {
- await setAIFeatures(true);
- }
- await browser.setFeature(
- 'optInGenAIFeatures',
- newValue ? 'true' : 'false'
- );
- return;
- }
-
await browser.setFeature('optInGenAIFeatures', newValue);
};
@@ -171,9 +154,6 @@ describe('MongoDB Assistant', function () {
after(async function () {
await mockAtlasServer.stop();
await mockAssistantServer.stop();
-
- delete process.env.COMPASS_ATLAS_SERVICE_UNAUTH_BASE_URL_OVERRIDE;
-
await cleanup(compass);
await telemetry.stop();
});
@@ -195,12 +175,7 @@ describe('MongoDB Assistant', function () {
});
it('does not show the assistant drawer button when AI features are disabled', async function () {
- // we cannot opt back out on web because it is stored server-side
- skipForWeb(
- this,
- 'E2E testing for assistant drawer visibility on compass-web is not yet implemented'
- );
-
+ await setAIOptIn(false);
await setAIFeatures(false);
const drawerButton = browser.$(Selectors.AssistantDrawerButton);
@@ -225,12 +200,7 @@ describe('MongoDB Assistant', function () {
});
describe('before opt-in', function () {
- // we cannot opt back out on web because it is stored server-side
before(async function () {
- skipForWeb(
- this,
- 'E2E testing for opt-in on compass-web is not yet implemented'
- );
await setAIOptIn(false);
});
@@ -291,11 +261,6 @@ describe('MongoDB Assistant', function () {
describe('opting in', function () {
before(async function () {
- // we cannot opt back out on web because it is stored server-side
- skipForWeb(
- this,
- 'E2E testing for opt-in on compass-web is not yet implemented'
- );
await setAIOptIn(false);
await openAssistantDrawer(browser);
});
diff --git a/packages/compass-e2e-tests/tests/collection-ai-query.test.ts b/packages/compass-e2e-tests/tests/collection-ai-query.test.ts
index d1454932598..2614fd4ad9d 100644
--- a/packages/compass-e2e-tests/tests/collection-ai-query.test.ts
+++ b/packages/compass-e2e-tests/tests/collection-ai-query.test.ts
@@ -7,15 +7,13 @@ import {
init,
cleanup,
screenshotIfFailed,
- skipForWeb,
- TEST_COMPASS_WEB,
DEFAULT_CONNECTION_NAME_1,
} from '../helpers/compass';
import type { Compass } from '../helpers/compass';
import * as Selectors from '../helpers/selectors';
import { createNumbersCollection } from '../helpers/insert-data';
-import { startMockAtlasServiceServer } from '../helpers/atlas-service';
-import type { MockAtlasServerResponse } from '../helpers/atlas-service';
+import { startMockAtlasServiceServer } from '../helpers/mock-atlas-service';
+import type { MockAtlasServerResponse } from '../helpers/mock-atlas-service';
describe('Collection ai query', function () {
let compass: Compass;
@@ -27,10 +25,6 @@ describe('Collection ai query', function () {
let clearRequests: () => void;
before(async function () {
- skipForWeb(this, 'ai queries not yet available in compass-web');
-
- process.env.COMPASS_E2E_SKIP_AI_OPT_IN = 'true';
-
// Start a mock server to pass an ai response.
const {
endpoint,
@@ -45,11 +39,18 @@ describe('Collection ai query', function () {
clearRequests = _clearRequests;
setMockAtlasServerResponse = _setMockAtlasServerResponse;
- process.env.COMPASS_ATLAS_SERVICE_UNAUTH_BASE_URL_OVERRIDE = endpoint;
-
telemetry = await startTelemetryServer();
compass = await init(this.test?.fullTitle());
browser = compass.browser;
+
+ await browser.setEnv(
+ 'COMPASS_ATLAS_SERVICE_UNAUTH_BASE_URL_OVERRIDE',
+ endpoint
+ );
+
+ await browser.setFeature('enableGenAISampleDocumentPassing', true);
+ await browser.setFeature('optInGenAIFeatures', true);
+
await browser.setupDefaultConnections();
});
@@ -66,14 +67,8 @@ describe('Collection ai query', function () {
});
after(async function () {
- if (TEST_COMPASS_WEB) {
- return;
- }
-
await stopMockAtlasServer();
- delete process.env.COMPASS_E2E_SKIP_AI_OPT_IN;
-
await cleanup(compass);
await telemetry.stop();
});
diff --git a/packages/compass-generative-ai/src/atlas-ai-service.spec.ts b/packages/compass-generative-ai/src/atlas-ai-service.spec.ts
index b2748eda075..1767fef6dd5 100644
--- a/packages/compass-generative-ai/src/atlas-ai-service.spec.ts
+++ b/packages/compass-generative-ai/src/atlas-ai-service.spec.ts
@@ -21,28 +21,30 @@ const ATLAS_USER = {
const BASE_URL = 'http://example.com';
-const mockConnectionInfo: ConnectionInfo = {
- id: 'TEST',
- connectionOptions: {
- connectionString: 'mongodb://localhost:27020',
- },
- atlasMetadata: {
- orgId: 'testOrg',
- projectId: 'testProject',
- clusterName: 'pineapple',
- regionalBaseUrl: null,
- metricsId: 'metricsId',
- metricsType: 'replicaSet',
- instanceSize: 'M10',
- clusterType: 'REPLICASET',
- clusterUniqueId: 'clusterUniqueId',
- clusterState: 'IDLE',
- supports: {
- globalWrites: false,
- rollingIndexes: false,
+const getMockConnectionInfo = (): ConnectionInfo => {
+ return {
+ id: 'TEST',
+ connectionOptions: {
+ connectionString: 'mongodb://localhost:27020',
+ },
+ atlasMetadata: {
+ orgId: 'testOrg',
+ projectId: 'testProject',
+ clusterName: 'pineapple',
+ regionalBaseUrl: null,
+ metricsId: 'metricsId',
+ metricsType: 'replicaSet',
+ instanceSize: 'M10',
+ clusterType: 'REPLICASET',
+ clusterUniqueId: 'clusterUniqueId',
+ clusterState: 'IDLE',
+ supports: {
+ globalWrites: false,
+ rollingIndexes: false,
+ },
+ userConnectionString: 'mongodb+srv://localhost:27020',
},
- userConnectionString: 'mongodb+srv://localhost:27020',
- },
+ };
};
class MockAtlasService {
@@ -104,9 +106,19 @@ describe('AtlasAiService', function () {
] as const;
for (const { apiURLPreset, expectedEndpoints } of endpointBasepathTests) {
- describe(`api URL Preset "${apiURLPreset}"`, function () {
+ const describeName =
+ apiURLPreset === 'admin-api'
+ ? 'connection WITHOUT atlas metadata'
+ : 'connection WITH atlas metadata';
+ describe(describeName, function () {
let atlasAiService: AtlasAiService;
+ const mockConnectionInfo = getMockConnectionInfo();
+
+ if (apiURLPreset === 'admin-api') {
+ delete mockConnectionInfo.atlasMetadata;
+ }
+
beforeEach(function () {
const mockAtlasService = new MockAtlasService();
atlasAiService = new AtlasAiService({
@@ -574,26 +586,6 @@ describe('AtlasAiService', function () {
expect(requestBody).to.have.property('schema');
});
- it('throws AtlasAiServiceInvalidInputError when connection info lacks atlas metadata', async function () {
- const connectionInfoWithoutAtlas = {
- ...mockConnectionInfo,
- atlasMetadata: undefined,
- };
-
- try {
- await atlasAiService.getMockDataSchema(
- mockSchemaInput,
- connectionInfoWithoutAtlas as any
- );
- expect.fail('Expected getMockDataSchema to throw');
- } catch (err) {
- expect(err).to.be.instanceOf(AtlasAiServiceInvalidInputError);
- expect((err as Error).message).to.match(
- /atlasMetadata is not available/i
- );
- }
- });
-
it('throws AtlasAiServiceApiResponseParseError when API response has invalid format', async function () {
const invalidMockResponse = {
invalidField: 'invalid data',
diff --git a/packages/compass-generative-ai/src/atlas-ai-service.ts b/packages/compass-generative-ai/src/atlas-ai-service.ts
index c2df97354bd..22d930e436d 100644
--- a/packages/compass-generative-ai/src/atlas-ai-service.ts
+++ b/packages/compass-generative-ai/src/atlas-ai-service.ts
@@ -208,10 +208,11 @@ const aiURLConfig = {
query: 'unauth/ai/api/v1/mql-query',
},
cloud: {
- aggregation: (groupId: string) => `ai/v1/groups/${groupId}/mql-aggregation`,
- query: (groupId: string) => `ai/v1/groups/${groupId}/mql-query`,
- 'mock-data-schema': (groupId: string) =>
- `ai/v1/groups/${groupId}/mock-data-schema`,
+ aggregation: (projectId: string) =>
+ `ai/v1/groups/${projectId}/mql-aggregation`,
+ query: (projectId: string) => `ai/v1/groups/${projectId}/mql-query`,
+ 'mock-data-schema': (projectId: string) =>
+ `ai/v1/groups/${projectId}/mock-data-schema`,
},
} as const;
@@ -290,18 +291,13 @@ export class AtlasAiService {
*/
private getUrlForEndpoint(
resourceType: AIResourceType,
- connectionInfo?: ConnectionInfo
+ connectionInfo: ConnectionInfo
) {
- if (this.apiURLPreset === 'cloud') {
- const atlasMetadata = connectionInfo?.atlasMetadata;
- if (!atlasMetadata) {
- throw new AtlasAiServiceInvalidInputError(
- "Can't perform generative ai request: atlasMetadata is not available"
- );
- }
+ const atlasMetadata = connectionInfo.atlasMetadata;
+ if (atlasMetadata) {
return this.atlasService.cloudEndpoint(
- aiURLConfig[this.apiURLPreset][resourceType](atlasMetadata.projectId)
+ aiURLConfig.cloud[resourceType](atlasMetadata.projectId)
);
}
@@ -311,7 +307,7 @@ export class AtlasAiService {
);
}
- const urlPath = aiURLConfig[this.apiURLPreset][resourceType];
+ const urlPath = aiURLConfig['admin-api'][resourceType];
return this.atlasService.adminApiEndpoint(urlPath);
}
@@ -353,8 +349,7 @@ export class AtlasAiService {
}: {
urlId: 'query' | 'aggregation';
input: GenerativeAiInput;
-
- connectionInfo?: ConnectionInfo;
+ connectionInfo: ConnectionInfo;
},
validationFn: (res: any) => asserts res is T
): Promise => {
diff --git a/packages/compass-preferences-model/src/preferences-schema.tsx b/packages/compass-preferences-model/src/preferences-schema.tsx
index eeefc5b4f0b..08eb3531efe 100644
--- a/packages/compass-preferences-model/src/preferences-schema.tsx
+++ b/packages/compass-preferences-model/src/preferences-schema.tsx
@@ -134,6 +134,7 @@ export type InternalUserPreferences = {
isMaximized?: boolean;
isFullScreen?: boolean;
};
+ enableGuideCues: boolean;
};
// UserPreferences contains all preferences stored to disk.
@@ -450,11 +451,7 @@ export const storedUserPreferencesProps: Required<{
cli: false,
global: false,
description: null,
- validator: z
- .boolean()
- .default(
- process.env.COMPASS_DISABLE_END_OF_LIFE_CONNECTION_MODAL !== 'true'
- ),
+ validator: z.boolean().default(true),
type: 'boolean',
},
/**
@@ -721,7 +718,7 @@ export const storedUserPreferencesProps: Required<{
long: `Enable the Chromium Developer Tools that can be used to debug Electron's process.`,
},
deriveValue: deriveFeatureRestrictingOptionsState('enableDevTools'),
- validator: z.boolean().default(process.env.APP_ENV === 'webdriverio'),
+ validator: z.boolean().default(false),
type: 'boolean',
},
/**
@@ -1093,6 +1090,16 @@ export const storedUserPreferencesProps: Required<{
type: 'number',
},
+ enableGuideCues: {
+ ui: false,
+ cli: false,
+ global: false,
+ omitFromHelp: true,
+ description: null,
+ validator: z.boolean().default(true),
+ type: 'boolean',
+ },
+
...allFeatureFlagsProps,
};
diff --git a/packages/compass-web/polyfills/process/index.ts b/packages/compass-web/polyfills/process/index.ts
index 009fd9e5af2..0a446bd6b7f 100644
--- a/packages/compass-web/polyfills/process/index.ts
+++ b/packages/compass-web/polyfills/process/index.ts
@@ -6,17 +6,4 @@ import hrtime from 'browser-process-hrtime';
(process as any).platform = 'Unknown';
(process as any).arch = 'Unknown';
-// Allow e2e tests to override environment variables
-if (process.env.APP_ENV === 'webdriverio') {
- const kSandboxSetEnvFn = Symbol.for('@compass-web-sandbox-set-env');
- // eslint-disable-next-line no-console
- console.info(
- `[compass-web sandbox] call window[Symbol.for('@compass-web-sandbox-set-env')]('KEY', 'value') to dynamically set environment variables`
- );
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
- (globalThis as any)[kSandboxSetEnvFn] = (key: string, value: string) => {
- process.env[key] = value;
- };
-}
-
export { process };
diff --git a/packages/compass-web/sandbox/index.tsx b/packages/compass-web/sandbox/index.tsx
index cb9c6e4b0e7..01722fd0c0c 100644
--- a/packages/compass-web/sandbox/index.tsx
+++ b/packages/compass-web/sandbox/index.tsx
@@ -8,12 +8,13 @@ import {
} from '@mongodb-js/compass-components';
import { CompassWeb } from '../src/index';
import { SandboxConnectionStorageProvider } from '../src/connection-storage';
+import './sandbox-process';
import { sandboxLogger } from './sandbox-logger';
import { sandboxTelemetry } from './sandbox-telemetry';
import { useAtlasProxySignIn } from './sandbox-atlas-sign-in';
import { sandboxConnectionStorage } from './sandbox-connection-storage';
import { useWorkspaceTabRouter } from './sandbox-workspace-tab-router';
-import { SandboxPreferencesUpdateProvider } from '../src/preferences';
+import { SandboxPreferencesGlobalAccessProvider } from '../src/preferences';
const sandboxContainerStyles = css({
width: '100%',
@@ -90,14 +91,11 @@ const App = () => {
return { readOnly: true };
})();
- const overrideGenAIFeatures =
- process.env.COMPASS_OVERRIDE_ENABLE_AI_FEATURES === 'true';
-
return (
-
+
{
enableRollingIndexes: isAtlas,
showDisabledConnections: true,
enableGenAIFeaturesAtlasProject:
- overrideGenAIFeatures ||
- (isAtlas && !!enableGenAIFeaturesAtlasProject),
+ !isAtlas || !!enableGenAIFeaturesAtlasProject,
enableGenAISampleDocumentPassing:
- overrideGenAIFeatures ||
- (isAtlas && !!enableGenAISampleDocumentPassing),
+ !isAtlas || !!enableGenAISampleDocumentPassing,
enableGenAIFeaturesAtlasOrg:
- overrideGenAIFeatures ||
- (isAtlas && !!enableGenAIFeaturesAtlasOrg),
- optInGenAIFeatures:
- overrideGenAIFeatures || (isAtlas && !!optInGenAIFeatures),
+ !isAtlas || !!enableGenAIFeaturesAtlasOrg,
+ optInGenAIFeatures: isAtlas ? !!optInGenAIFeatures : false,
enableDataModeling: true,
enableMyQueries: false,
...groupRolePreferences,
@@ -135,7 +129,7 @@ const App = () => {
onFailToLoadConnections={onFailToLoadConnections}
>
-
+
);
};
diff --git a/packages/compass-web/sandbox/sandbox-atlas-sign-in.tsx b/packages/compass-web/sandbox/sandbox-atlas-sign-in.tsx
index b7d7b1f72e9..51c5c964bc0 100644
--- a/packages/compass-web/sandbox/sandbox-atlas-sign-in.tsx
+++ b/packages/compass-web/sandbox/sandbox-atlas-sign-in.tsx
@@ -130,25 +130,20 @@ export function useAtlasProxySignIn(): AtlasLoginReturnValue {
userRoles,
currentOrganization,
} = params;
- const overrideGenAIFeatures =
- process.env.COMPASS_OVERRIDE_ENABLE_AI_FEATURES === 'true';
setProjectParams({
orgId: currentOrganization.id,
projectId,
csrfToken,
csrfTime,
optInGenAIFeatures: isOptedIntoDataExplorerGenAIFeatures,
- enableGenAIFeaturesAtlasOrg:
- overrideGenAIFeatures || genAIFeaturesEnabled,
+ enableGenAIFeaturesAtlasOrg: genAIFeaturesEnabled,
enableGenAISampleDocumentPassing:
!groupEnabledFeatureFlags.includes(
'DISABLE_DATA_EXPLORER_GEN_AI_SAMPLE_DOCUMENT_PASSING'
),
- enableGenAIFeaturesAtlasProject:
- overrideGenAIFeatures ||
- groupEnabledFeatureFlags.includes(
- 'ENABLE_DATA_EXPLORER_GEN_AI_FEATURES'
- ),
+ enableGenAIFeaturesAtlasProject: groupEnabledFeatureFlags.includes(
+ 'ENABLE_DATA_EXPLORER_GEN_AI_FEATURES'
+ ),
userRoles,
});
setStatus('signed-in');
diff --git a/packages/compass-web/sandbox/sandbox-process.ts b/packages/compass-web/sandbox/sandbox-process.ts
new file mode 100644
index 00000000000..6a850b49e12
--- /dev/null
+++ b/packages/compass-web/sandbox/sandbox-process.ts
@@ -0,0 +1,12 @@
+const kSandboxSetEnvFn = Symbol.for('@compass-web-sandbox-set-env');
+// eslint-disable-next-line no-console
+console.info(
+ `[compass-web sandbox] call window[Symbol.for('@compass-web-sandbox-set-env')]('KEY', 'value') to dynamically set environment variables`
+);
+// Even though it doesn't look like it, process is module scoped in web bundle,
+// to allow overriding it in runtime in the sandbox we add a special global
+// scoped method
+// eslint-disable-next-line @typescript-eslint/no-explicit-any
+(globalThis as any)[kSandboxSetEnvFn] = (key: string, value: string) => {
+ process.env[key] = value;
+};
diff --git a/packages/compass-web/src/entrypoint.tsx b/packages/compass-web/src/entrypoint.tsx
index e2b33f2e2a9..1ade5ef2d2e 100644
--- a/packages/compass-web/src/entrypoint.tsx
+++ b/packages/compass-web/src/entrypoint.tsx
@@ -47,7 +47,10 @@ import type {
AllPreferences,
AtlasCloudFeatureFlags,
} from 'compass-preferences-model/provider';
-import { PreferencesProvider } from 'compass-preferences-model/provider';
+import {
+ PreferencesProvider,
+ usePreference,
+} from 'compass-preferences-model/provider';
import FieldStorePlugin from '@mongodb-js/compass-field-store';
import {
atlasServiceLocator,
@@ -55,7 +58,10 @@ import {
} from '@mongodb-js/atlas-service/provider';
import { AtlasAiServiceProvider } from '@mongodb-js/compass-generative-ai/provider';
import { LoggerProvider } from '@mongodb-js/compass-logging/provider';
-import { TelemetryProvider } from '@mongodb-js/compass-telemetry/provider';
+import {
+ TelemetryProvider,
+ useTelemetry,
+} from '@mongodb-js/compass-telemetry/provider';
import CompassConnections from '@mongodb-js/compass-connections';
import { AtlasCloudConnectionStorageProvider } from './connection-storage';
import { AtlasCloudAuthServiceProvider } from './atlas-auth-service';
@@ -383,6 +389,79 @@ const connectedContainerStyles = css({
display: 'flex',
});
+const CompassWebComponentsProvider: React.FunctionComponent<{
+ darkMode?: boolean;
+}> = ({ darkMode, children }) => {
+ const track = useTelemetry();
+ const disableGuideCues = !usePreference('enableGuideCues');
+ return (
+ {
+ track('Guide Cue Dismissed', {
+ groupId: cue.groupId,
+ cueId: cue.cueId,
+ step: cue.step,
+ });
+ }}
+ onNextGuideCueGroup={(cue) => {
+ if (cue.groupSteps !== cue.step) {
+ track('Guide Cue Group Dismissed', {
+ groupId: cue.groupId,
+ cueId: cue.cueId,
+ step: cue.step,
+ });
+ }
+ }}
+ onContextMenuOpen={(itemGroups) => {
+ if (itemGroups.length > 0) {
+ track('Context Menu Opened', {
+ item_groups: itemGroups.map((group) => group.telemetryLabel),
+ });
+ }
+ }}
+ onContextMenuItemClick={(itemGroup, item) => {
+ track('Context Menu Item Clicked', {
+ item_group: itemGroup.telemetryLabel,
+ item_label: item.label,
+ });
+ }}
+ onDrawerSectionOpen={(drawerSectionId) => {
+ track('Drawer Section Opened', {
+ sectionId: drawerSectionId,
+ });
+ }}
+ onDrawerSectionHide={(drawerSectionId) => {
+ track('Drawer Section Closed', {
+ sectionId: drawerSectionId,
+ });
+ }}
+ onSignalMount={(id) => {
+ track('Signal Shown', { id });
+ }}
+ onSignalOpen={(id) => {
+ track('Signal Opened', { id });
+ }}
+ onSignalPrimaryActionClick={(id) => {
+ track('Signal Action Button Clicked', { id });
+ }}
+ onSignalLinkClick={(id) => {
+ track('Signal Link Clicked', { id });
+ }}
+ onSignalClose={(id) => {
+ track('Signal Closed', { id });
+ }}
+ disableGuideCues={disableGuideCues}
+ {...LINK_PROPS}
+ >
+ {children}
+
+ );
+};
+
/** @public */
const CompassWeb = ({
appName,
@@ -452,67 +531,7 @@ const CompassWeb = ({
return (
- {
- onTrackRef.current?.('Guide Cue Dismissed', {
- groupId: cue.groupId,
- cueId: cue.cueId,
- step: cue.step,
- });
- }}
- onNextGuideCueGroup={(cue) => {
- if (cue.groupSteps !== cue.step) {
- onTrackRef.current?.('Guide Cue Group Dismissed', {
- groupId: cue.groupId,
- cueId: cue.cueId,
- step: cue.step,
- });
- }
- }}
- onContextMenuOpen={(itemGroups) => {
- if (itemGroups.length > 0) {
- onTrackRef.current?.('Context Menu Opened', {
- item_groups: itemGroups.map((group) => group.telemetryLabel),
- });
- }
- }}
- onContextMenuItemClick={(itemGroup, item) => {
- onTrackRef.current?.('Context Menu Item Clicked', {
- item_group: itemGroup.telemetryLabel,
- item_label: item.label,
- });
- }}
- onDrawerSectionOpen={(drawerSectionId) => {
- onTrackRef.current?.('Drawer Section Opened', {
- sectionId: drawerSectionId,
- });
- }}
- onDrawerSectionHide={(drawerSectionId) => {
- onTrackRef.current?.('Drawer Section Closed', {
- sectionId: drawerSectionId,
- });
- }}
- onSignalMount={(id) => {
- onTrackRef.current?.('Signal Shown', { id });
- }}
- onSignalOpen={(id) => {
- onTrackRef.current?.('Signal Opened', { id });
- }}
- onSignalPrimaryActionClick={(id) => {
- onTrackRef.current?.('Signal Action Button Clicked', { id });
- }}
- onSignalLinkClick={(id) => {
- onTrackRef.current?.('Signal Link Clicked', { id });
- }}
- onSignalClose={(id) => {
- onTrackRef.current?.('Signal Closed', { id });
- }}
- {...LINK_PROPS}
- >
+
@@ -596,7 +615,7 @@ const CompassWeb = ({
-
+
);
diff --git a/packages/compass-web/src/preferences.tsx b/packages/compass-web/src/preferences.tsx
index 73ce582a970..91bccc01a68 100644
--- a/packages/compass-web/src/preferences.tsx
+++ b/packages/compass-web/src/preferences.tsx
@@ -1,55 +1,48 @@
-import React, { useContext, useEffect, useRef, useState } from 'react';
+import React, { useCallback, useContext, useEffect, useRef } from 'react';
import type {
AllPreferences,
AtlasCloudFeatureFlags,
+ PreferencesAccess,
} from 'compass-preferences-model/provider';
import { CompassWebPreferencesAccess } from 'compass-preferences-model/provider';
-export type SandboxPreferencesUpdateTrigger = (
- updatePreference: (
- preferences: Partial
- ) => Promise
+type SandboxSetPreferencesGlobalAccess = (
+ preferences: PreferencesAccess
) => () => void;
-const SandboxPreferencesUpdateTriggerContext =
- React.createContext(null);
+const SandboxPreferencesGlobalAccessContext =
+ React.createContext(null);
-const kSandboxUpdateFn = Symbol.for('@compass-web-sandbox-update-preferences');
+const kSandboxPreferencesAccess = Symbol.for(
+ '@compass-web-sandbox-preferences-access'
+);
/**
* Only used in the sandbox to provide a way to update preferences.
* @internal
*/
-export const SandboxPreferencesUpdateProvider = ({
+export const SandboxPreferencesGlobalAccessProvider = ({
children,
}: {
children: React.ReactNode;
}) => {
- const [updateTrigger] = useState(() => {
- return (
- updatePreferencesFn: (
- preferences: Partial
- ) => Promise
- ) => {
- // eslint-disable-next-line no-console
- console.info(
- `[compass-web sandbox] call window[Symbol.for('@compass-web-sandbox-update-preferences')]({}) to dynamically update preferences`
- );
- (globalThis as any)[kSandboxUpdateFn] = (
- preferences: Partial
- ) => {
- return updatePreferencesFn(preferences);
- };
- return () => {
- delete (globalThis as any)[kSandboxUpdateFn];
- };
+ const setPreferencesAccess = useCallback((preferences: PreferencesAccess) => {
+ (globalThis as any)[kSandboxPreferencesAccess] = preferences;
+ // eslint-disable-next-line no-console
+ console.info(
+ `[compass-web sandbox] call window[Symbol.for('@compass-web-sandbox-preferences-access')].savePreferences({}) to dynamically update preferences`
+ );
+ return () => {
+ delete (globalThis as any)[kSandboxPreferencesAccess];
};
- });
+ }, []);
return (
-
+
{children}
-
+
);
};
@@ -92,17 +85,15 @@ export function useCompassWebPreferences(
)
);
- const onPreferencesUpdateTriggered = useContext(
- SandboxPreferencesUpdateTriggerContext
+ const setPreferencesAccess = useContext(
+ SandboxPreferencesGlobalAccessContext
);
useEffect(() => {
// This is used by our sandbox so that we can call a global function in the
- // browser from the sandbox / testing runtime to update preferences.
- return onPreferencesUpdateTriggered?.(async (preferences) => {
- return await preferencesAccess.current.savePreferences(preferences);
- });
- }, [onPreferencesUpdateTriggered]);
+ // browser from the sandbox / testing runtime to access preferences.
+ return setPreferencesAccess?.(preferencesAccess.current);
+ }, [setPreferencesAccess]);
return preferencesAccess;
}
diff --git a/packages/compass-web/webpack.config.js b/packages/compass-web/webpack.config.js
index 93cbc21d1ef..bff3ec5ad3b 100644
--- a/packages/compass-web/webpack.config.js
+++ b/packages/compass-web/webpack.config.js
@@ -151,28 +151,10 @@ module.exports = (env, args) => {
// Can be either `web` or `webdriverio`, helpful if we need special
// behavior for tests in sandbox
'process.env.APP_ENV': JSON.stringify(process.env.APP_ENV ?? 'web'),
- ...(process.env.COMPASS_ASSISTANT_BASE_URL_OVERRIDE
- ? {
- 'process.env.COMPASS_ASSISTANT_BASE_URL_OVERRIDE': JSON.stringify(
- process.env.COMPASS_ASSISTANT_BASE_URL_OVERRIDE
- ),
- }
- : {}),
- ...(process.env.COMPASS_OVERRIDE_ENABLE_AI_FEATURES
- ? {
- 'process.env.COMPASS_OVERRIDE_ENABLE_AI_FEATURES': JSON.stringify(
- process.env.COMPASS_OVERRIDE_ENABLE_AI_FEATURES
- ),
- }
- : {}),
- ...(process.env.COMPASS_DISABLE_VIRTUAL_TABLE_RENDERING
- ? {
- 'process.env.COMPASS_DISABLE_VIRTUAL_TABLE_RENDERING':
- JSON.stringify(
- process.env.COMPASS_DISABLE_VIRTUAL_TABLE_RENDERING
- ),
- }
- : {}),
+ // NB: DefinePlugin completely replaces matched string with a provided
+ // value, in most cases WE DO NOT WANT THAT and process variables in the
+ // code are added to be able to change them in runtime. Do not add new
+ // records unless you're super sure it's needed
}),
new webpack.ProvidePlugin({
diff --git a/packages/compass/src/app/components/home.tsx b/packages/compass/src/app/components/home.tsx
index db15bedbbb5..565dc5bffc6 100644
--- a/packages/compass/src/app/components/home.tsx
+++ b/packages/compass/src/app/components/home.tsx
@@ -163,8 +163,10 @@ export default function ThemedHome(
): ReturnType {
const track = useTelemetry();
const disableContextMenus = !usePreference('enableContextMenus');
+ const disableGuideCues = !usePreference('enableGuideCues');
return (
{
track('Guide Cue Dismissed', {
groupId: cue.groupId,