From eda194e467d356044e3b5e5892275dcf60aac924 Mon Sep 17 00:00:00 2001 From: Jacob Samuel Lu Date: Tue, 9 Sep 2025 10:32:13 -0400 Subject: [PATCH 1/7] WIP --- .../collection-header-actions.spec.tsx | 75 +++------------ .../collection-header-actions.tsx | 24 ++--- .../collection-header.spec.tsx | 91 ++++++------------- 3 files changed, 49 insertions(+), 141 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 1f98a73199d..8b737157663 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 @@ -13,26 +13,16 @@ import { import type { PreferencesAccess } from 'compass-preferences-model'; import { createSandboxFromDefaultPreferences } from 'compass-preferences-model'; import { PreferencesProvider } from 'compass-preferences-model/provider'; -import { ExperimentTestName } from '@mongodb-js/compass-telemetry/provider'; -import { CompassExperimentationProvider } from '@mongodb-js/compass-telemetry'; + import type { ConnectionInfo } from '@mongodb-js/compass-connections/provider'; import CollectionHeaderActions from '../collection-header-actions'; describe('CollectionHeaderActions [Component]', function () { let preferences: PreferencesAccess; - let mockUseAssignment: sinon.SinonStub; beforeEach(async function () { preferences = await createSandboxFromDefaultPreferences(); - mockUseAssignment = sinon.stub(); - mockUseAssignment.returns({ - assignment: { - assignmentData: { - variant: 'mockDataGeneratorControl', - }, - }, - }); }); afterEach(function () { @@ -45,27 +35,19 @@ describe('CollectionHeaderActions [Component]', function () { connectionInfo?: ConnectionInfo ) => { return renderWithActiveConnection( - - - - - - - , + + + + + , connectionInfo ); }; @@ -225,34 +207,15 @@ describe('CollectionHeaderActions [Component]', function () { }, }; - it('should call useAssignment with correct parameters', async function () { - await renderCollectionHeaderActions({ - namespace: 'test.collection', - isReadonly: false, - }); - - expect(mockUseAssignment).to.have.been.calledWith( - ExperimentTestName.mockDataGenerator, - true // trackIsInSample - Experiment viewed analytics event - ); - }); - it('should call onOpenMockDataModal when CTA button is clicked', async function () { const onOpenMockDataModal = sinon.stub(); - mockUseAssignment.returns({ - assignment: { - assignmentData: { - variant: 'mockDataGeneratorVariant', - }, - }, - }); - await renderCollectionHeaderActions( { namespace: 'test.collection', isReadonly: false, onOpenMockDataModal, + schemaAnalysisStatus: 'complete', }, {}, atlasConnectionInfo @@ -267,14 +230,6 @@ describe('CollectionHeaderActions [Component]', function () { }); it('should disable button for deeply nested collections', async function () { - mockUseAssignment.returns({ - assignment: { - assignmentData: { - variant: 'mockDataGeneratorVariant', // Treatment variant - }, - }, - }); - await renderCollectionHeaderActions( { namespace: 'test.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 e8204823d5c..aaed671215f 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 @@ -12,14 +12,10 @@ import React from 'react'; import { usePreferences } from 'compass-preferences-model/provider'; import toNS from 'mongodb-ns'; import { wrapField } from '@mongodb-js/mongodb-constants'; -import { - useTelemetry, - useAssignment, - ExperimentTestName, - ExperimentTestGroup, -} from '@mongodb-js/compass-telemetry/provider'; +import { useTelemetry } from '@mongodb-js/compass-telemetry/provider'; import { SCHEMA_ANALYSIS_STATE_ANALYZING, + SCHEMA_ANALYSIS_STATE_COMPLETE, type SchemaAnalysisStatus, } from '../../schema-analysis-types'; @@ -82,21 +78,13 @@ const CollectionHeaderActions: React.FunctionComponent< usePreferences(['readOnly', 'enableShell']); const track = useTelemetry(); - // Get experiment assignment for Mock Data Generator - const mockDataGeneratorAssignment = useAssignment( - ExperimentTestName.mockDataGenerator, - true // trackIsInSample - this will fire the "Experiment Viewed" event - ); - 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; - + // Show Mock Data Generator button if schema analysis has bee initiated (indicating user is in treatment variant) + // Schema analysis only runs for users in the treatment variant const shouldShowMockDataButton = - isInMockDataTreatmentVariant && + (schemaAnalysisStatus === SCHEMA_ANALYSIS_STATE_ANALYZING || + schemaAnalysisStatus === SCHEMA_ANALYSIS_STATE_COMPLETE) && atlasMetadata && // Only show in Atlas !isReadonly && // Don't show for readonly collections (views) !sourceName; // sourceName indicates it's a view diff --git a/packages/compass-collection/src/components/collection-header/collection-header.spec.tsx b/packages/compass-collection/src/components/collection-header/collection-header.spec.tsx index 82553cc22af..40b72080fc2 100644 --- a/packages/compass-collection/src/components/collection-header/collection-header.spec.tsx +++ b/packages/compass-collection/src/components/collection-header/collection-header.spec.tsx @@ -17,8 +17,10 @@ import { type WorkspacesService, } from '@mongodb-js/compass-workspaces/provider'; import { MockDataGeneratorStep } from '../mock-data-generator-modal/types'; -import { SCHEMA_ANALYSIS_STATE_COMPLETE } from '../../schema-analysis-types'; -import { CompassExperimentationProvider } from '@mongodb-js/compass-telemetry'; +import { + SCHEMA_ANALYSIS_STATE_COMPLETE, + SCHEMA_ANALYSIS_STATE_INITIAL, +} from '../../schema-analysis-types'; import type { ConnectionInfo } from '@mongodb-js/compass-connections/provider'; import Sinon from 'sinon'; @@ -335,23 +337,6 @@ describe('CollectionHeader [Component]', function () { }); describe('Mock Data Generator integration', function () { - let mockUseAssignment: Sinon.SinonStub; - - beforeEach(function () { - // Mock the useAssignment hook from compass-experimentation - mockUseAssignment = Sinon.stub().returns({ - assignment: { - assignmentData: { - variant: 'mockDataGeneratorVariant', - }, - }, - }); - }); - - afterEach(function () { - Sinon.restore(); - }); - const atlasConnectionInfo: ConnectionInfo = { id: 'test-atlas-connection', connectionOptions: { @@ -375,7 +360,7 @@ describe('CollectionHeader [Component]', function () { }, }; - function renderCollectionHeaderWithExperimentation( + function renderCollectionHeaderWithSchemaAnalysis( props: Partial> = {}, workspaceService: Partial = {}, stateOverrides: any = {}, @@ -392,33 +377,27 @@ describe('CollectionHeader [Component]', function () { const mockStore = createStore(() => defaultState); return renderWithActiveConnection( - - - - - - - , + + + + + , connectionInfo ); } it('should show Mock Data Generator button when all conditions are met', async function () { - await renderCollectionHeaderWithExperimentation( + await renderCollectionHeaderWithSchemaAnalysis( { isAtlas: true, // Atlas environment isReadonly: false, // Not readonly @@ -447,7 +426,7 @@ describe('CollectionHeader [Component]', function () { }); it('should disable Mock Data Generator button when collection has no schema analysis data', async function () { - await renderCollectionHeaderWithExperimentation( + await renderCollectionHeaderWithSchemaAnalysis( { isAtlas: true, isReadonly: false, @@ -474,7 +453,7 @@ describe('CollectionHeader [Component]', function () { }); it('should disable Mock Data Generator button for collections with excessive nesting depth', async function () { - await renderCollectionHeaderWithExperimentation( + await renderCollectionHeaderWithSchemaAnalysis( { isAtlas: true, isReadonly: false, @@ -503,7 +482,7 @@ describe('CollectionHeader [Component]', function () { }); it('should not show Mock Data Generator button for readonly collections (views)', async function () { - await renderCollectionHeaderWithExperimentation( + await renderCollectionHeaderWithSchemaAnalysis( { isAtlas: true, isReadonly: true, // Readonly (view) @@ -530,7 +509,7 @@ describe('CollectionHeader [Component]', function () { }); it('should not show Mock Data Generator button in non-Atlas environments', async function () { - await renderCollectionHeaderWithExperimentation( + await renderCollectionHeaderWithSchemaAnalysis( { isAtlas: false, // Not Atlas isReadonly: false, @@ -556,16 +535,8 @@ describe('CollectionHeader [Component]', function () { ).to.not.exist; }); - it('should not show Mock Data Generator button when not in treatment variant', async function () { - mockUseAssignment.returns({ - assignment: { - assignmentData: { - variant: 'control', - }, - }, - }); - - await renderCollectionHeaderWithExperimentation( + it('should not show Mock Data Generator button when schema analysis has not run', async function () { + await renderCollectionHeaderWithSchemaAnalysis( { isAtlas: true, isReadonly: false, @@ -574,13 +545,7 @@ describe('CollectionHeader [Component]', function () { {}, { schemaAnalysis: { - status: SCHEMA_ANALYSIS_STATE_COMPLETE, - processedSchema: { - field1: { type: 'String', sample_values: ['value1'] }, - }, - schemaMetadata: { - maxNestingDepth: 2, - }, + status: SCHEMA_ANALYSIS_STATE_INITIAL, // No schema analysis has run }, }, atlasConnectionInfo From c23b7d79805a89d98ac99f4b0696e89d466f36da Mon Sep 17 00:00:00 2001 From: Jacob Samuel Lu Date: Tue, 9 Sep 2025 10:35:41 -0400 Subject: [PATCH 2/7] Consolidate helper functions in test file --- .../collection-header.spec.tsx | 121 +++++++----------- 1 file changed, 47 insertions(+), 74 deletions(-) diff --git a/packages/compass-collection/src/components/collection-header/collection-header.spec.tsx b/packages/compass-collection/src/components/collection-header/collection-header.spec.tsx index 40b72080fc2..2136a6236bd 100644 --- a/packages/compass-collection/src/components/collection-header/collection-header.spec.tsx +++ b/packages/compass-collection/src/components/collection-header/collection-header.spec.tsx @@ -28,7 +28,8 @@ import Sinon from 'sinon'; function renderCollectionHeader( props: Partial> = {}, workspaceService: Partial = {}, - stateOverrides: any = {} + stateOverrides: Record = {}, + connectionInfo?: ConnectionInfo ) { const defaultState = { mockDataGenerator: { @@ -40,7 +41,11 @@ function renderCollectionHeader( const mockStore = createStore(() => defaultState); - return renderWithConnections( + const renderMethod = connectionInfo + ? renderWithActiveConnection + : renderWithConnections; + + return renderMethod( - + , + connectionInfo ); } @@ -61,8 +67,8 @@ describe('CollectionHeader [Component]', function () { afterEach(cleanup); context('when the collection is not readonly', function () { - beforeEach(function () { - renderCollectionHeader(); + beforeEach(async function () { + await renderCollectionHeader(); }); it('renders the correct root classname', function () { @@ -91,8 +97,11 @@ describe('CollectionHeader [Component]', function () { }); context('when the collection is readonly', function () { - beforeEach(function () { - renderCollectionHeader({ isReadonly: true, sourceName: 'orig.coll' }); + beforeEach(async function () { + await renderCollectionHeader({ + isReadonly: true, + sourceName: 'orig.coll', + }); }); afterEach(cleanup); @@ -115,8 +124,8 @@ describe('CollectionHeader [Component]', function () { }); context('when the collection is readonly but not a view', function () { - beforeEach(function () { - renderCollectionHeader({ isReadonly: true, sourceName: undefined }); + beforeEach(async function () { + await renderCollectionHeader({ isReadonly: true, sourceName: undefined }); }); it('renders the readonly badge', function () { @@ -129,8 +138,8 @@ describe('CollectionHeader [Component]', function () { }); context('when the collection is a time-series collection', function () { - beforeEach(function () { - renderCollectionHeader({ isTimeSeries: true }); + beforeEach(async function () { + await renderCollectionHeader({ isTimeSeries: true }); }); it('does not render the readonly badge', function () { @@ -143,8 +152,8 @@ describe('CollectionHeader [Component]', function () { }); context('when the collection is a clustered collection', function () { - beforeEach(function () { - renderCollectionHeader({ isClustered: true }); + beforeEach(async function () { + await renderCollectionHeader({ isClustered: true }); }); it('does not render the readonly badge', function () { @@ -161,8 +170,8 @@ describe('CollectionHeader [Component]', function () { }); context('when the collection is a fle collection', function () { - beforeEach(function () { - renderCollectionHeader({ isFLE: true }); + beforeEach(async function () { + await renderCollectionHeader({ isFLE: true }); }); it('renders the fle badge', function () { @@ -171,8 +180,8 @@ describe('CollectionHeader [Component]', function () { }); describe('insights', function () { - it('should show an insight when $text is used in the pipeline source', function () { - renderCollectionHeader({ + it('should show an insight when $text is used in the pipeline source', async function () { + await renderCollectionHeader({ sourcePipeline: [{ $match: { $text: {} } }], }); expect(screen.getByTestId('insight-badge-button')).to.exist; @@ -181,8 +190,8 @@ describe('CollectionHeader [Component]', function () { .exist; }); - it('should show an insight when $regex is used in the pipeline source', function () { - renderCollectionHeader({ + it('should show an insight when $regex is used in the pipeline source', async function () { + await renderCollectionHeader({ sourcePipeline: [{ $match: { $regex: {} } }], }); expect(screen.getByTestId('insight-badge-button')).to.exist; @@ -191,8 +200,8 @@ describe('CollectionHeader [Component]', function () { .exist; }); - it('should show an insight when $lookup is used in the pipeline source', function () { - renderCollectionHeader({ + it('should show an insight when $lookup is used in the pipeline source', async function () { + await renderCollectionHeader({ sourcePipeline: [{ $lookup: {} }], }); expect(screen.getByTestId('insight-badge-button')).to.exist; @@ -211,7 +220,7 @@ describe('CollectionHeader [Component]', function () { }); function assertBreadcrumbText(items: string[]) { - const crumbs: any[] = []; + const crumbs: (string | null)[] = []; screen.getByTestId('breadcrumbs').childNodes.forEach((item) => { crumbs.push(item.textContent); }); @@ -232,13 +241,13 @@ describe('CollectionHeader [Component]', function () { } context('renders correclty', function () { - it('for a collection', function () { - renderCollectionHeader({ namespace: 'db.coll1' }); + it('for a collection', async function () { + await renderCollectionHeader({ namespace: 'db.coll1' }); assertBreadcrumbText(['db', 'coll1']); }); - it('for a view', function () { - renderCollectionHeader({ + it('for a view', async function () { + await renderCollectionHeader({ namespace: 'db.coll1', sourceName: 'db.coll2', }); @@ -246,8 +255,8 @@ describe('CollectionHeader [Component]', function () { assertBreadcrumbText(['db', 'coll2', 'coll1']); }); - it('for a view when its being edited', function () { - renderCollectionHeader({ + it('for a view when its being edited', async function () { + await renderCollectionHeader({ namespace: 'db.coll3', editViewName: 'db.coll1', }); @@ -257,10 +266,10 @@ describe('CollectionHeader [Component]', function () { }); context('calls onClick correclty', function () { - it('for a collection', function () { + it('for a collection', async function () { const openCollectionsWorkspaceStub = sandbox.stub(); const openCollectionWorkspaceStub = sandbox.stub(); - renderCollectionHeader( + await renderCollectionHeader( { namespace: 'db.coll1' }, { openCollectionsWorkspace: openCollectionsWorkspaceStub, @@ -281,9 +290,9 @@ describe('CollectionHeader [Component]', function () { ]); }); - it('for a view, opens source collection', function () { + it('for a view, opens source collection', async function () { const openCollectionWorkspaceStub = sandbox.stub(); - renderCollectionHeader( + await renderCollectionHeader( { namespace: 'db.coll1', sourceName: 'db.coll2' }, { openCollectionWorkspace: openCollectionWorkspaceStub, @@ -360,44 +369,8 @@ describe('CollectionHeader [Component]', function () { }, }; - function renderCollectionHeaderWithSchemaAnalysis( - props: Partial> = {}, - workspaceService: Partial = {}, - stateOverrides: any = {}, - connectionInfo?: ConnectionInfo - ) { - const defaultState = { - mockDataGenerator: { - isModalOpen: false, - currentStep: MockDataGeneratorStep.SCHEMA_CONFIRMATION, - }, - ...stateOverrides, - }; - - const mockStore = createStore(() => defaultState); - - return renderWithActiveConnection( - - - - - , - connectionInfo - ); - } - it('should show Mock Data Generator button when all conditions are met', async function () { - await renderCollectionHeaderWithSchemaAnalysis( + await renderCollectionHeader( { isAtlas: true, // Atlas environment isReadonly: false, // Not readonly @@ -426,7 +399,7 @@ describe('CollectionHeader [Component]', function () { }); it('should disable Mock Data Generator button when collection has no schema analysis data', async function () { - await renderCollectionHeaderWithSchemaAnalysis( + await renderCollectionHeader( { isAtlas: true, isReadonly: false, @@ -453,7 +426,7 @@ describe('CollectionHeader [Component]', function () { }); it('should disable Mock Data Generator button for collections with excessive nesting depth', async function () { - await renderCollectionHeaderWithSchemaAnalysis( + await renderCollectionHeader( { isAtlas: true, isReadonly: false, @@ -482,7 +455,7 @@ describe('CollectionHeader [Component]', function () { }); it('should not show Mock Data Generator button for readonly collections (views)', async function () { - await renderCollectionHeaderWithSchemaAnalysis( + await renderCollectionHeader( { isAtlas: true, isReadonly: true, // Readonly (view) @@ -509,7 +482,7 @@ describe('CollectionHeader [Component]', function () { }); it('should not show Mock Data Generator button in non-Atlas environments', async function () { - await renderCollectionHeaderWithSchemaAnalysis( + await renderCollectionHeader( { isAtlas: false, // Not Atlas isReadonly: false, @@ -536,7 +509,7 @@ describe('CollectionHeader [Component]', function () { }); it('should not show Mock Data Generator button when schema analysis has not run', async function () { - await renderCollectionHeaderWithSchemaAnalysis( + await renderCollectionHeader( { isAtlas: true, isReadonly: false, From f7a0f3504e250d17e2191f5bfd73c352ffae6b0f Mon Sep 17 00:00:00 2001 From: Jacob Samuel Lu Date: Tue, 9 Sep 2025 10:40:49 -0400 Subject: [PATCH 3/7] Remove useAssignment hook --- .../src/experimentation-provider.tsx | 30 ++----------------- packages/compass-telemetry/src/provider.tsx | 1 - 2 files changed, 2 insertions(+), 29 deletions(-) diff --git a/packages/compass-telemetry/src/experimentation-provider.tsx b/packages/compass-telemetry/src/experimentation-provider.tsx index 6bdbda73647..474b6be7f12 100644 --- a/packages/compass-telemetry/src/experimentation-provider.tsx +++ b/packages/compass-telemetry/src/experimentation-provider.tsx @@ -1,14 +1,7 @@ -import React, { createContext, useContext, useRef } from 'react'; +import React, { createContext, useRef } from 'react'; import type { types } from '@mongodb-js/mdb-experiment-js'; -import type { typesReact } from '@mongodb-js/mdb-experiment-js/react'; import type { ExperimentTestName } from './growth-experiments'; -type UseAssignmentHook = ( - experimentName: ExperimentTestName, - trackIsInSample: boolean, - options?: typesReact.UseAssignmentOptions -) => typesReact.UseAssignmentResponse; - type AssignExperimentFn = ( experimentName: ExperimentTestName, options?: types.AssignOptions @@ -21,22 +14,11 @@ type GetAssignmentFn = ( ) => Promise | null>; interface CompassExperimentationProviderContextValue { - useAssignment: UseAssignmentHook; assignExperiment: AssignExperimentFn; getAssignment: GetAssignmentFn; } const initialContext: CompassExperimentationProviderContextValue = { - useAssignment() { - return { - assignment: null, - asyncStatus: null, - error: null, - isLoading: false, - isError: false, - isSuccess: true, - }; - }, assignExperiment() { return Promise.resolve(null); }, @@ -51,18 +33,15 @@ export const ExperimentationContext = // Provider component that accepts MMS experiment utils as props export const CompassExperimentationProvider: React.FC<{ children: React.ReactNode; - useAssignment: UseAssignmentHook; assignExperiment: AssignExperimentFn; getAssignment: GetAssignmentFn; -}> = ({ children, useAssignment, assignExperiment, getAssignment }) => { +}> = ({ children, assignExperiment, getAssignment }) => { // Use useRef to keep the functions up-to-date; Use mutation pattern to maintain the // same object reference to prevent unnecessary re-renders of consuming components const { current: contextValue } = useRef({ - useAssignment, assignExperiment, getAssignment, }); - contextValue.useAssignment = useAssignment; contextValue.assignExperiment = assignExperiment; contextValue.getAssignment = getAssignment; @@ -72,8 +51,3 @@ export const CompassExperimentationProvider: React.FC<{ ); }; - -// Hook for components to access experiment assignment -export const useAssignment = (...args: Parameters) => { - return useContext(ExperimentationContext).useAssignment(...args); -}; diff --git a/packages/compass-telemetry/src/provider.tsx b/packages/compass-telemetry/src/provider.tsx index 4446dbbfb03..ba2d6f1fe3a 100644 --- a/packages/compass-telemetry/src/provider.tsx +++ b/packages/compass-telemetry/src/provider.tsx @@ -162,4 +162,3 @@ export const useFireExperimentViewed = ({ export type { TrackFunction }; export { ExperimentTestName, ExperimentTestGroup } from './growth-experiments'; -export { useAssignment } from './experimentation-provider'; From 65480184a71c4942f66789a2d22340a88573580f Mon Sep 17 00:00:00 2001 From: Jacob Lu <43422771+jcobis@users.noreply.github.com> Date: Tue, 9 Sep 2025 10:46:50 -0400 Subject: [PATCH 4/7] typo Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .../collection-header-actions/collection-header-actions.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 aaed671215f..c078c220731 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 @@ -80,7 +80,7 @@ const CollectionHeaderActions: React.FunctionComponent< const { database, collection } = toNS(namespace); - // Show Mock Data Generator button if schema analysis has bee initiated (indicating user is in treatment variant) + // Show Mock Data Generator button if schema analysis has been initiated (indicating user is in treatment variant) // Schema analysis only runs for users in the treatment variant const shouldShowMockDataButton = (schemaAnalysisStatus === SCHEMA_ANALYSIS_STATE_ANALYZING || From b1daccc4a8b164b6b1830d3f7dc3b62e65b4e7c4 Mon Sep 17 00:00:00 2001 From: Jacob Samuel Lu Date: Tue, 9 Sep 2025 11:03:46 -0400 Subject: [PATCH 5/7] Change action to not dispatch error for empty collection --- .../src/modules/collection-tab.ts | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/packages/compass-collection/src/modules/collection-tab.ts b/packages/compass-collection/src/modules/collection-tab.ts index e1f3afa2eac..82e913d4865 100644 --- a/packages/compass-collection/src/modules/collection-tab.ts +++ b/packages/compass-collection/src/modules/collection-tab.ts @@ -39,8 +39,6 @@ import type { MockDataGeneratorState } from '../components/mock-data-generator-m const DEFAULT_SAMPLE_SIZE = 100; -const NO_DOCUMENTS_ERROR = 'No documents found in the collection to analyze.'; - function isAction( action: AnyAction, type: A['type'] @@ -590,10 +588,17 @@ export const analyzeCollectionSchema = (): CollectionThunkAction< return; } if (sampleDocuments.length === 0) { - logger.debug(NO_DOCUMENTS_ERROR); + logger.debug( + 'Collection is empty, completing schema analysis with empty schema' + ); dispatch({ - type: CollectionActions.SchemaAnalysisFailed, - error: new Error(NO_DOCUMENTS_ERROR), + type: CollectionActions.SchemaAnalysisFinished, + processedSchema: {}, + sampleDocument: {}, + schemaMetadata: { + maxNestingDepth: 0, + validationRules: null, + }, }); return; } From ebe4412d4f3ba681593ad31b9184fd9e7e5144b7 Mon Sep 17 00:00:00 2001 From: Jacob Samuel Lu Date: Tue, 9 Sep 2025 11:19:19 -0400 Subject: [PATCH 6/7] Make test method constant --- .../components/collection-header/collection-header.spec.tsx | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/packages/compass-collection/src/components/collection-header/collection-header.spec.tsx b/packages/compass-collection/src/components/collection-header/collection-header.spec.tsx index 2136a6236bd..890bda8467e 100644 --- a/packages/compass-collection/src/components/collection-header/collection-header.spec.tsx +++ b/packages/compass-collection/src/components/collection-header/collection-header.spec.tsx @@ -41,11 +41,7 @@ function renderCollectionHeader( const mockStore = createStore(() => defaultState); - const renderMethod = connectionInfo - ? renderWithActiveConnection - : renderWithConnections; - - return renderMethod( + return renderWithActiveConnection( Date: Tue, 9 Sep 2025 11:23:54 -0400 Subject: [PATCH 7/7] Restore useAssignment hook --- .../src/experimentation-provider.tsx | 30 +++++++++++++++++-- packages/compass-telemetry/src/provider.tsx | 1 + 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/packages/compass-telemetry/src/experimentation-provider.tsx b/packages/compass-telemetry/src/experimentation-provider.tsx index 474b6be7f12..6bdbda73647 100644 --- a/packages/compass-telemetry/src/experimentation-provider.tsx +++ b/packages/compass-telemetry/src/experimentation-provider.tsx @@ -1,7 +1,14 @@ -import React, { createContext, useRef } from 'react'; +import React, { createContext, useContext, useRef } from 'react'; import type { types } from '@mongodb-js/mdb-experiment-js'; +import type { typesReact } from '@mongodb-js/mdb-experiment-js/react'; import type { ExperimentTestName } from './growth-experiments'; +type UseAssignmentHook = ( + experimentName: ExperimentTestName, + trackIsInSample: boolean, + options?: typesReact.UseAssignmentOptions +) => typesReact.UseAssignmentResponse; + type AssignExperimentFn = ( experimentName: ExperimentTestName, options?: types.AssignOptions @@ -14,11 +21,22 @@ type GetAssignmentFn = ( ) => Promise | null>; interface CompassExperimentationProviderContextValue { + useAssignment: UseAssignmentHook; assignExperiment: AssignExperimentFn; getAssignment: GetAssignmentFn; } const initialContext: CompassExperimentationProviderContextValue = { + useAssignment() { + return { + assignment: null, + asyncStatus: null, + error: null, + isLoading: false, + isError: false, + isSuccess: true, + }; + }, assignExperiment() { return Promise.resolve(null); }, @@ -33,15 +51,18 @@ export const ExperimentationContext = // Provider component that accepts MMS experiment utils as props export const CompassExperimentationProvider: React.FC<{ children: React.ReactNode; + useAssignment: UseAssignmentHook; assignExperiment: AssignExperimentFn; getAssignment: GetAssignmentFn; -}> = ({ children, assignExperiment, getAssignment }) => { +}> = ({ children, useAssignment, assignExperiment, getAssignment }) => { // Use useRef to keep the functions up-to-date; Use mutation pattern to maintain the // same object reference to prevent unnecessary re-renders of consuming components const { current: contextValue } = useRef({ + useAssignment, assignExperiment, getAssignment, }); + contextValue.useAssignment = useAssignment; contextValue.assignExperiment = assignExperiment; contextValue.getAssignment = getAssignment; @@ -51,3 +72,8 @@ export const CompassExperimentationProvider: React.FC<{ ); }; + +// Hook for components to access experiment assignment +export const useAssignment = (...args: Parameters) => { + return useContext(ExperimentationContext).useAssignment(...args); +}; diff --git a/packages/compass-telemetry/src/provider.tsx b/packages/compass-telemetry/src/provider.tsx index ba2d6f1fe3a..4446dbbfb03 100644 --- a/packages/compass-telemetry/src/provider.tsx +++ b/packages/compass-telemetry/src/provider.tsx @@ -162,3 +162,4 @@ export const useFireExperimentViewed = ({ export type { TrackFunction }; export { ExperimentTestName, ExperimentTestGroup } from './growth-experiments'; +export { useAssignment } from './experimentation-provider';