From a2f88dc4084265ec5a6692288144d73d96713bab Mon Sep 17 00:00:00 2001 From: Jacob Samuel Lu Date: Thu, 23 Oct 2025 15:07:38 -0400 Subject: [PATCH 1/3] Gate behind assign call --- .../src/stores/collection-tab.spec.ts | 36 ++++++++++++++++++ .../src/stores/collection-tab.ts | 37 ++++++++++--------- 2 files changed, 55 insertions(+), 18 deletions(-) diff --git a/packages/compass-collection/src/stores/collection-tab.spec.ts b/packages/compass-collection/src/stores/collection-tab.spec.ts index 0d6ea908085..b773949675a 100644 --- a/packages/compass-collection/src/stores/collection-tab.spec.ts +++ b/packages/compass-collection/src/stores/collection-tab.spec.ts @@ -263,6 +263,42 @@ describe('Collection Tab Content store', function () { .deep.eq(defaultMetadata); }); }); + + it('should not assign experiment for readonly collections', async function () { + const assignExperiment = sandbox.spy(() => Promise.resolve(null)); + + await configureStore( + undefined, + {}, + { assignExperiment }, + mockAtlasConnectionInfo, + undefined, + undefined, + { ...defaultMetadata, isReadonly: true } + ); + + // Wait a bit to ensure assignment would have happened if it was going to + await new Promise((resolve) => setTimeout(resolve, 50)); + expect(assignExperiment).to.not.have.been.called; + }); + + it('should not assign experiment for time series collections', async function () { + const assignExperiment = sandbox.spy(() => Promise.resolve(null)); + + await configureStore( + undefined, + {}, + { assignExperiment }, + mockAtlasConnectionInfo, + undefined, + undefined, + { ...defaultMetadata, isTimeSeries: true } + ); + + // Wait a bit to ensure assignment would have happened if it was going to + await new Promise((resolve) => setTimeout(resolve, 50)); + expect(assignExperiment).to.not.have.been.called; + }); }); describe('schema analysis on collection load', function () { diff --git a/packages/compass-collection/src/stores/collection-tab.ts b/packages/compass-collection/src/stores/collection-tab.ts index fc404e20c1f..6bf6377dd61 100644 --- a/packages/compass-collection/src/stores/collection-tab.ts +++ b/packages/compass-collection/src/stores/collection-tab.ts @@ -142,26 +142,27 @@ export function activatePlugin( void collectionModel.fetchMetadata({ dataService }).then((metadata) => { store.dispatch(collectionMetadataFetched(metadata)); - // Assign experiment for Mock Data Generator - // Only assign when we're connected to Atlas and the org-level setting for AI features is enabled - if ( - connectionInfoRef.current?.atlasMetadata?.clusterName && // Ensures we only assign in Atlas - isAIFeatureEnabled(preferences.getPreferences()) // Ensures org-level AI features setting is enabled - ) { - void experimentationServices - .assignExperiment(ExperimentTestName.mockDataGenerator, { - team: 'Atlas Growth', - }) - .catch((error) => { - logger.debug('Mock Data Generator experiment assignment failed', { - experiment: ExperimentTestName.mockDataGenerator, - namespace: namespace, - error: error instanceof Error ? error.message : String(error), + if (!metadata.isReadonly && !metadata.isTimeSeries) { + // Assign experiment for Mock Data Generator + // Only assign when we're connected to Atlas, the org-level setting for AI features is enabled, + // and the collection supports the Mock Data Generator feature (not readonly/timeseries) + if ( + connectionInfoRef.current?.atlasMetadata?.clusterName && // Ensures we only assign in Atlas + isAIFeatureEnabled(preferences.getPreferences()) // Ensures org-level AI features setting is enabled + ) { + void experimentationServices + .assignExperiment(ExperimentTestName.mockDataGenerator, { + team: 'Atlas Growth', + }) + .catch((error) => { + logger.debug('Mock Data Generator experiment assignment failed', { + experiment: ExperimentTestName.mockDataGenerator, + namespace: namespace, + error: error instanceof Error ? error.message : String(error), + }); }); - }); - } + } - if (!metadata.isReadonly && !metadata.isTimeSeries) { // Check experiment variant before running schema analysis // Only run schema analysis if user is in treatment variant const shouldRunSchemaAnalysis = async () => { From 9627f064fd1253e12c754f3613445cb459abbe95 Mon Sep 17 00:00:00 2001 From: Jacob Samuel Lu Date: Mon, 27 Oct 2025 15:22:33 -0400 Subject: [PATCH 2/3] Hide time series --- .../collection-header-actions.spec.tsx | 15 +++++++++++++++ .../collection-header-actions.tsx | 3 +++ .../collection-header/collection-header.tsx | 1 + 3 files changed, 19 insertions(+) diff --git a/packages/compass-collection/src/components/collection-header-actions/collection-header-actions.spec.tsx b/packages/compass-collection/src/components/collection-header-actions/collection-header-actions.spec.tsx index 1450a7566d2..982e2773a5b 100644 --- a/packages/compass-collection/src/components/collection-header-actions/collection-header-actions.spec.tsx +++ b/packages/compass-collection/src/components/collection-header-actions/collection-header-actions.spec.tsx @@ -54,6 +54,7 @@ describe('CollectionHeaderActions [Component]', function () { = ({ namespace, isReadonly, + isTimeSeries, editViewName, sourceName, sourcePipeline, @@ -116,6 +118,7 @@ const CollectionHeaderActions: React.FunctionComponent< isInMockDataTreatmentVariant && atlasMetadata && // Only show in Atlas !isReadonly && // Don't show for readonly collections (views) + !isTimeSeries && // Don't show for time series collections !sourceName; // sourceName indicates it's a view const exceedsMaxNestingDepth = diff --git a/packages/compass-collection/src/components/collection-header/collection-header.tsx b/packages/compass-collection/src/components/collection-header/collection-header.tsx index 1219529954c..bbca8d22b48 100644 --- a/packages/compass-collection/src/components/collection-header/collection-header.tsx +++ b/packages/compass-collection/src/components/collection-header/collection-header.tsx @@ -185,6 +185,7 @@ const CollectionHeader: React.FunctionComponent = ({ Date: Mon, 27 Oct 2025 16:21:47 -0400 Subject: [PATCH 3/3] WIP --- .../collection-header-actions.spec.tsx | 34 +++++++++++++++- .../collection-header-actions.tsx | 19 +++++---- .../src/stores/collection-tab.ts | 40 ++++++++++--------- 3 files changed, 65 insertions(+), 28 deletions(-) diff --git a/packages/compass-collection/src/components/collection-header-actions/collection-header-actions.spec.tsx b/packages/compass-collection/src/components/collection-header-actions/collection-header-actions.spec.tsx index 982e2773a5b..763e81b165b 100644 --- a/packages/compass-collection/src/components/collection-header-actions/collection-header-actions.spec.tsx +++ b/packages/compass-collection/src/components/collection-header-actions/collection-header-actions.spec.tsx @@ -222,6 +222,22 @@ describe('CollectionHeaderActions [Component]', function () { }; it('should call useAssignment with correct parameters', async function () { + await renderCollectionHeaderActions( + { + namespace: 'test.collection', + isReadonly: false, + }, + {}, + atlasConnectionInfo + ); + + expect(mockUseAssignment).to.have.been.calledWith( + ExperimentTestName.mockDataGenerator, + true // trackIsInSample - Experiment viewed analytics event + ); + }); + + it('should call useAssignment with trackIsInSample set to false in non-Atlas environments', async function () { await renderCollectionHeaderActions({ namespace: 'test.collection', isReadonly: false, @@ -229,7 +245,23 @@ describe('CollectionHeaderActions [Component]', function () { expect(mockUseAssignment).to.have.been.calledWith( ExperimentTestName.mockDataGenerator, - true // trackIsInSample - Experiment viewed analytics event + false // Not eligible - no Atlas metadata + ); + }); + + it('should call useAssignment with trackIsInSample set to false for readonly collections', async function () { + await renderCollectionHeaderActions( + { + namespace: 'test.collection', + isReadonly: true, + }, + {}, + atlasConnectionInfo + ); + + expect(mockUseAssignment).to.have.been.calledWith( + ExperimentTestName.mockDataGenerator, + false // Not eligible - readonly collection ); }); diff --git a/packages/compass-collection/src/components/collection-header-actions/collection-header-actions.tsx b/packages/compass-collection/src/components/collection-header-actions/collection-header-actions.tsx index 13659560657..35238ca9b7f 100644 --- a/packages/compass-collection/src/components/collection-header-actions/collection-header-actions.tsx +++ b/packages/compass-collection/src/components/collection-header-actions/collection-header-actions.tsx @@ -101,25 +101,28 @@ const CollectionHeaderActions: React.FunctionComponent< 'enableGenAISampleDocumentPassing' ); + const { database, collection } = toNS(namespace); + + const isMockDataGeneratorEligible = Boolean( + atlasMetadata && // Only show in Atlas + !isReadonly && // Don't show for readonly collections (views) + !isTimeSeries && // Don't show for time series collections + !sourceName // sourceName indicates it's a view + ); + // Get experiment assignment for Mock Data Generator const mockDataGeneratorAssignment = useAssignment( ExperimentTestName.mockDataGenerator, - true // trackIsInSample - this will fire the "Experiment Viewed" event + isMockDataGeneratorEligible // Only track eligible collections ); - const { database, collection } = toNS(namespace); - // Check if user is in treatment group for Mock Data Generator experiment const isInMockDataTreatmentVariant = mockDataGeneratorAssignment?.assignment?.assignmentData?.variant === ExperimentTestGroup.mockDataGeneratorVariant; const shouldShowMockDataButton = - isInMockDataTreatmentVariant && - atlasMetadata && // Only show in Atlas - !isReadonly && // Don't show for readonly collections (views) - !isTimeSeries && // Don't show for time series collections - !sourceName; // sourceName indicates it's a view + isMockDataGeneratorEligible && isInMockDataTreatmentVariant; const exceedsMaxNestingDepth = analyzedSchemaDepth > MAX_COLLECTION_NESTING_DEPTH; diff --git a/packages/compass-collection/src/stores/collection-tab.ts b/packages/compass-collection/src/stores/collection-tab.ts index 6bf6377dd61..bc310f5768a 100644 --- a/packages/compass-collection/src/stores/collection-tab.ts +++ b/packages/compass-collection/src/stores/collection-tab.ts @@ -142,27 +142,29 @@ export function activatePlugin( void collectionModel.fetchMetadata({ dataService }).then((metadata) => { store.dispatch(collectionMetadataFetched(metadata)); - if (!metadata.isReadonly && !metadata.isTimeSeries) { - // Assign experiment for Mock Data Generator - // Only assign when we're connected to Atlas, the org-level setting for AI features is enabled, - // and the collection supports the Mock Data Generator feature (not readonly/timeseries) - if ( - connectionInfoRef.current?.atlasMetadata?.clusterName && // Ensures we only assign in Atlas - isAIFeatureEnabled(preferences.getPreferences()) // Ensures org-level AI features setting is enabled - ) { - void experimentationServices - .assignExperiment(ExperimentTestName.mockDataGenerator, { - team: 'Atlas Growth', - }) - .catch((error) => { - logger.debug('Mock Data Generator experiment assignment failed', { - experiment: ExperimentTestName.mockDataGenerator, - namespace: namespace, - error: error instanceof Error ? error.message : String(error), - }); + // Assign experiment for Mock Data Generator + // Only assign when we're connected to Atlas, the org-level setting for AI features is enabled, + // and the collection supports the Mock Data Generator feature (not readonly/timeseries) + if ( + !metadata.isReadonly && + !metadata.isTimeSeries && + connectionInfoRef.current?.atlasMetadata?.clusterName && // Ensures we only assign in Atlas + isAIFeatureEnabled(preferences.getPreferences()) // Ensures org-level AI features setting is enabled + ) { + void experimentationServices + .assignExperiment(ExperimentTestName.mockDataGenerator, { + team: 'Atlas Growth', + }) + .catch((error) => { + logger.debug('Mock Data Generator experiment assignment failed', { + experiment: ExperimentTestName.mockDataGenerator, + namespace: namespace, + error: error instanceof Error ? error.message : String(error), }); - } + }); + } + if (!metadata.isReadonly && !metadata.isTimeSeries) { // Check experiment variant before running schema analysis // Only run schema analysis if user is in treatment variant const shouldRunSchemaAnalysis = async () => {