Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import React, { type ComponentProps } from 'react';
import {
renderWithActiveConnection,
screen,
waitFor,
} from '@mongodb-js/testing-library-compass';
import sinon from 'sinon';
import {
Expand All @@ -14,6 +15,7 @@ import { CompassExperimentationProvider } from '@mongodb-js/compass-telemetry';
import type { ConnectionInfo } from '@mongodb-js/compass-connections/provider';

import CollectionHeaderActions from '../collection-header-actions';
import { MAX_COLLECTION_NESTING_DEPTH } from '../mock-data-generator-modal/utils';

describe('CollectionHeaderActions [Component]', function () {
let mockUseAssignment: sinon.SinonStub;
Expand Down Expand Up @@ -229,94 +231,132 @@ describe('CollectionHeaderActions [Component]', function () {
);
});

it('should call onOpenMockDataModal when CTA button is clicked', async function () {
const onOpenMockDataModal = sinon.stub();
context('when in the mock data generator treatment variant', function () {
beforeEach(function () {
mockUseAssignment.returns({
assignment: {
assignmentData: {
variant: 'mockDataGeneratorVariant',
},
},
});
});

mockUseAssignment.returns({
assignment: {
assignmentData: {
variant: 'mockDataGeneratorVariant',
it('should send a track event when the button is viewed', async function () {
const result = await renderCollectionHeaderActions(
{
namespace: 'test.collection',
isReadonly: false,
},
},
{},
atlasConnectionInfo
);

await waitFor(() => {
expect(result.track).to.have.been.calledWith(
'Mock Data Generator CTA Button Viewed',
{
button_enabled: true,
gen_ai_features_enabled: false,
send_sample_values_enabled: false,
}
);
});
});

await renderCollectionHeaderActions(
{
namespace: 'test.collection',
isReadonly: false,
onOpenMockDataModal,
},
{},
atlasConnectionInfo
);
it('should call onOpenMockDataModal when CTA button is clicked', async function () {
const onOpenMockDataModal = sinon.stub();
await renderCollectionHeaderActions(
{
namespace: 'test.collection',
isReadonly: false,
onOpenMockDataModal,
},
{},
atlasConnectionInfo
);

const button = screen.getByTestId(
'collection-header-generate-mock-data-button'
);
button.click();
const button = screen.getByTestId(
'collection-header-generate-mock-data-button'
);
button.click();

expect(onOpenMockDataModal).to.have.been.calledOnce;
});
expect(onOpenMockDataModal).to.have.been.calledOnce;
});

it('should disable button for deeply nested collections', async function () {
mockUseAssignment.returns({
assignment: {
assignmentData: {
variant: 'mockDataGeneratorVariant', // Treatment variant
it('sends a track event when CTA button is clicked', async function () {
const onOpenMockDataModal = sinon.stub();

const result = await renderCollectionHeaderActions(
{
namespace: 'test.collection',
isReadonly: false,
onOpenMockDataModal,
},
},
});
{},
atlasConnectionInfo
);

await renderCollectionHeaderActions(
{
namespace: 'test.collection',
isReadonly: false,
hasSchemaAnalysisData: true,
analyzedSchemaDepth: 8, // Exceeds MAX_COLLECTION_NESTING_DEPTH (7)
schemaAnalysisStatus: 'complete',
onOpenMockDataModal: sinon.stub(),
},
{},
atlasConnectionInfo
);
const button = screen.getByTestId(
'collection-header-generate-mock-data-button'
);
button.click();

const button = screen.getByTestId(
'collection-header-generate-mock-data-button'
);
expect(button).to.exist;
expect(button).to.have.attribute('aria-disabled', 'true');
});
await waitFor(() => {
expect(result.track).to.have.been.calledWith(
'Mock Data Generator Opened',
{
gen_ai_features_enabled: false,
send_sample_values_enabled: false,
}
);
});
});

it('should show an error banner when the schema is in an unsupported state', async function () {
mockUseAssignment.returns({
assignment: {
assignmentData: {
variant: 'mockDataGeneratorVariant',
it('should disable button for deeply nested collections', async function () {
await renderCollectionHeaderActions(
{
namespace: 'test.collection',
isReadonly: false,
hasSchemaAnalysisData: true,
analyzedSchemaDepth: MAX_COLLECTION_NESTING_DEPTH + 1,
schemaAnalysisStatus: 'complete',
onOpenMockDataModal: sinon.stub(),
},
},
{},
atlasConnectionInfo
);

const button = screen.getByTestId(
'collection-header-generate-mock-data-button'
);
expect(button).to.exist;
expect(button).to.have.attribute('aria-disabled', 'true');
});

await renderCollectionHeaderActions(
{
namespace: 'test.collection',
isReadonly: false,
hasSchemaAnalysisData: false,
schemaAnalysisStatus: 'error',
schemaAnalysisError: {
errorType: 'unsupportedState',
errorMessage: 'Unsupported state',
it('should show an error banner when the schema is in an unsupported state', async function () {
await renderCollectionHeaderActions(
{
namespace: 'test.collection',
isReadonly: false,
hasSchemaAnalysisData: false,
schemaAnalysisStatus: 'error',
schemaAnalysisError: {
errorType: 'unsupportedState',
errorMessage: 'Unsupported state',
},
onOpenMockDataModal: sinon.stub(),
},
onOpenMockDataModal: sinon.stub(),
},
{},
atlasConnectionInfo
);
{},
atlasConnectionInfo
);

const button = screen.getByTestId(
'collection-header-generate-mock-data-button'
);
expect(button).to.exist;
expect(button).to.have.attribute('aria-disabled', 'true');
const button = screen.getByTestId(
'collection-header-generate-mock-data-button'
);
expect(button).to.exist;
expect(button).to.have.attribute('aria-disabled', 'true');
});
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,12 @@ import {
} from '@mongodb-js/compass-components';
import { useConnectionInfo } from '@mongodb-js/compass-connections/provider';
import { useOpenWorkspace } from '@mongodb-js/compass-workspaces/provider';
import React from 'react';
import { usePreferences } from 'compass-preferences-model/provider';
import React, { useCallback, useEffect } from 'react';
import {
useIsAIFeatureEnabled,
usePreference,
usePreferences,
} from 'compass-preferences-model/provider';
import toNS from 'mongodb-ns';
import { wrapField } from '@mongodb-js/mongodb-constants';
import {
Expand All @@ -23,11 +27,7 @@ import {
type SchemaAnalysisStatus,
type SchemaAnalysisError,
} from '../../schema-analysis-types';

/**
* Maximum allowed nesting depth for collections to show Mock Data Generator
*/
const MAX_COLLECTION_NESTING_DEPTH = 7;
import { MAX_COLLECTION_NESTING_DEPTH } from '../mock-data-generator-modal/utils';

const collectionHeaderActionsStyles = css({
display: 'flex',
Expand Down Expand Up @@ -92,6 +92,10 @@ const CollectionHeaderActions: React.FunctionComponent<
const { readWrite: preferencesReadWrite, enableShell: showOpenShellButton } =
usePreferences(['readWrite', 'enableShell']);
const track = useTelemetry();
const isAIFeatureEnabled = useIsAIFeatureEnabled();
const isSampleDocumentPassingEnabled = usePreference(
'enableGenAISampleDocumentPassing'
);

// Get experiment assignment for Mock Data Generator
const mockDataGeneratorAssignment = useAssignment(
Expand Down Expand Up @@ -122,6 +126,37 @@ const CollectionHeaderActions: React.FunctionComponent<
const isView = isReadonly && sourceName && !editViewName;

const showViewEdit = isView && !preferencesReadWrite;
const shouldDisableMockDataButton =
!hasSchemaAnalysisData || exceedsMaxNestingDepth;

const onMockDataGeneratorCtaButtonClicked = useCallback(() => {
track('Mock Data Generator Opened', {
gen_ai_features_enabled: isAIFeatureEnabled,
send_sample_values_enabled: isSampleDocumentPassingEnabled,
});
onOpenMockDataModal();
}, [
track,
isAIFeatureEnabled,
isSampleDocumentPassingEnabled,
onOpenMockDataModal,
]);

useEffect(() => {
if (shouldShowMockDataButton) {
track('Mock Data Generator CTA Button Viewed', {
button_enabled: !shouldDisableMockDataButton,
gen_ai_features_enabled: isAIFeatureEnabled,
send_sample_values_enabled: isSampleDocumentPassingEnabled,
});
}
}, [
track,
isAIFeatureEnabled,
isSampleDocumentPassingEnabled,
shouldDisableMockDataButton,
shouldShowMockDataButton,
]);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here you can use useTrackOnChange hook that '@mongodb-js/compass-telemetry/provider' exports

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh this is awesome, will use useTrackOnChange!


return (
<div
Expand Down Expand Up @@ -151,8 +186,8 @@ const CollectionHeaderActions: React.FunctionComponent<
<Button
data-testid="collection-header-generate-mock-data-button"
size={ButtonSize.Small}
disabled={!hasSchemaAnalysisData || exceedsMaxNestingDepth}
onClick={onOpenMockDataModal}
disabled={shouldDisableMockDataButton}
onClick={onMockDataGeneratorCtaButtonClicked}
leftGlyph={<Icon glyph="Sparkle" />}
>
Generate Mock Data
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,20 @@ export const StepButtonLabelMap = {
[MockDataGeneratorStep.GENERATE_DATA]: 'Done',
} as const;

// Map of the current mock data generator step to the next step or 'finish' if the user is on the last step.
// For the purposes of telemetry tracking the step progression in the modal.
export const MOCK_DATA_GENERATOR_STEP_TO_NEXT_STEP_MAP: Record<
MockDataGeneratorStep,
MockDataGeneratorStep | 'finish'
> = {
[MockDataGeneratorStep.SCHEMA_CONFIRMATION]:
MockDataGeneratorStep.SCHEMA_EDITOR,
[MockDataGeneratorStep.SCHEMA_EDITOR]: MockDataGeneratorStep.DOCUMENT_COUNT,
[MockDataGeneratorStep.DOCUMENT_COUNT]: MockDataGeneratorStep.PREVIEW_DATA,
[MockDataGeneratorStep.PREVIEW_DATA]: MockDataGeneratorStep.GENERATE_DATA,
[MockDataGeneratorStep.GENERATE_DATA]: 'finish',
};

export const DEFAULT_DOCUMENT_COUNT = 1000;
export const MAX_DOCUMENT_COUNT = 100000;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { connect } from 'react-redux';
import type { CollectionState } from '../../modules/collection-tab';
import type { SchemaAnalysisState } from '../../schema-analysis-types';
import { DEFAULT_DOCUMENT_COUNT, MAX_DOCUMENT_COUNT } from './constants';
import { useTelemetry } from '@mongodb-js/compass-telemetry/provider';

const BYTE_PRECISION_THRESHOLD = 1000;

Expand Down Expand Up @@ -67,6 +68,7 @@ const DocumentCountScreen = ({
onDocumentCountChange,
schemaAnalysisState,
}: Props) => {
const track = useTelemetry();
const estimatedDiskSize = useMemo(
() =>
schemaAnalysisState.status === 'complete' &&
Expand Down Expand Up @@ -98,6 +100,9 @@ const DocumentCountScreen = ({
const value = parseInt(event.target.value, 10);
if (!isNaN(value)) {
onDocumentCountChange(value);
track('Mock Data Document Count Changed', {
document_count: value,
});
}
};

Expand Down
Loading