diff --git a/packages/compass-indexes/src/components/create-index-modal/create-index-modal-header.spec.tsx b/packages/compass-indexes/src/components/create-index-modal/create-index-modal-header.spec.tsx new file mode 100644 index 00000000000..35867c87797 --- /dev/null +++ b/packages/compass-indexes/src/components/create-index-modal/create-index-modal-header.spec.tsx @@ -0,0 +1,27 @@ +import React from 'react'; +import { render, screen } from '@mongodb-js/testing-library-compass'; +import CreateIndexModalHeader from './create-index-modal-header'; +import { expect } from 'chai'; + +describe('CreateIndexModalHeader', () => { + it('renders the modal title', () => { + render(); + const title = screen.getByTestId('create-index-modal-header-title'); + + expect(title.textContent).to.be.equal('Create Index'); + }); + + it('renders the subtitle text', () => { + render(); + const subtitle = screen.getByTestId('create-index-modal-header-subtitle'); + expect(subtitle).to.exist; + }); + + it('renders the link to the Index Strategies Documentation', () => { + render(); + const link = screen.getByRole('link', { + name: /Index Strategies Documentation/i, + }); + expect(link).to.exist; + }); +}); diff --git a/packages/compass-indexes/src/components/create-index-modal/create-index-modal-header.tsx b/packages/compass-indexes/src/components/create-index-modal/create-index-modal-header.tsx new file mode 100644 index 00000000000..16472de7b70 --- /dev/null +++ b/packages/compass-indexes/src/components/create-index-modal/create-index-modal-header.tsx @@ -0,0 +1,45 @@ +import { + H3, + Body, + spacing, + css, + palette, + Link, +} from '@mongodb-js/compass-components'; +import React from 'react'; + +const headerStyle = css({ + padding: spacing[800], + paddingBottom: 0, +}); + +const subtitleStyle = css({ + color: palette.gray.dark1, +}); + +const CreateIndexModalHeader = () => { + return ( +
+

Create Index

+ + + The best indexes for your application should consider a number of + factors, such as your data model, and the queries you use most often. To + learn more about indexing best practices, read the{' '} + + Index Strategies Documentation + + . + +
+ ); +}; + +export default CreateIndexModalHeader; diff --git a/packages/compass-indexes/src/components/create-index-modal/create-index-modal.tsx b/packages/compass-indexes/src/components/create-index-modal/create-index-modal.tsx index 2f4e744bc66..a37b1a85ab9 100644 --- a/packages/compass-indexes/src/components/create-index-modal/create-index-modal.tsx +++ b/packages/compass-indexes/src/components/create-index-modal/create-index-modal.tsx @@ -21,8 +21,12 @@ import type { RootState } from '../../modules'; import { useTrackOnChange, type TrackFunction, + useFireExperimentViewed, + TestName, } from '@mongodb-js/compass-telemetry/provider'; import { useConnectionInfoRef } from '@mongodb-js/compass-connections/provider'; +import { usePreference } from 'compass-preferences-model/provider'; +import CreateIndexModalHeader from './create-index-modal-header'; type CreateIndexModalProps = React.ComponentProps & { isVisible: boolean; @@ -70,13 +74,28 @@ function CreateIndexModal({ undefined ); + // @experiment Early Journey Indexes Guidance & Awareness | Jira Epic: CLOUDP-239367 + const enableInIndexesGuidanceExp = usePreference('enableIndexesGuidanceExp'); + const showIndexesGuidanceVariant = + usePreference('showIndexesGuidanceVariant') && enableInIndexesGuidanceExp; + + useFireExperimentViewed({ + testName: TestName.earlyJourneyIndexesGuidance, + shouldFire: enableInIndexesGuidanceExp && isVisible, + }); + return ( - + {showIndexesGuidanceVariant ? ( + + ) : ( + + )} diff --git a/packages/compass-preferences-model/src/feature-flags.ts b/packages/compass-preferences-model/src/feature-flags.ts index 99a438f6455..f16ed69ed35 100644 --- a/packages/compass-preferences-model/src/feature-flags.ts +++ b/packages/compass-preferences-model/src/feature-flags.ts @@ -24,6 +24,8 @@ export type FeatureFlags = { enableRollingIndexes: boolean; enableGlobalWrites: boolean; enableDataModeling: boolean; + enableIndexesGuidanceExp: boolean; + showIndexesGuidanceVariant: boolean; }; export const featureFlags: Required<{ @@ -122,4 +124,23 @@ export const featureFlags: Required<{ short: 'Design, Visualize, and Evolve your Data Model', }, }, + + /** + * Feature flags for Early Journey Indexes Guidance & Awareness | Jira Epic: CLOUDP-239367 + * These are passed from MMS and not editable by user + */ + enableIndexesGuidanceExp: { + stage: 'development', + description: { + short: 'Enable Indexes Guidance Experiment', + }, + }, + + showIndexesGuidanceVariant: { + stage: 'development', + description: { + short: + 'Used to check if user is in the Indexes Guidance Experiment Variant', + }, + }, }; diff --git a/packages/compass-telemetry/src/growth-experiments.ts b/packages/compass-telemetry/src/growth-experiments.ts new file mode 100644 index 00000000000..dfe4d52cd11 --- /dev/null +++ b/packages/compass-telemetry/src/growth-experiments.ts @@ -0,0 +1,3 @@ +export enum TestName { + earlyJourneyIndexesGuidance = 'EARLY_JOURNEY_INDEXES_GUIDANCE_20250328', +} diff --git a/packages/compass-telemetry/src/provider.tsx b/packages/compass-telemetry/src/provider.tsx index 4773ad67db0..5cf4b56917c 100644 --- a/packages/compass-telemetry/src/provider.tsx +++ b/packages/compass-telemetry/src/provider.tsx @@ -3,6 +3,7 @@ import { createServiceLocator } from 'hadron-app-registry'; import { createTrack, type TelemetryServiceOptions } from './generic-track'; import { useLogger } from '@mongodb-js/compass-logging/provider'; import type { TrackFunction } from './types'; +import { TestName } from './growth-experiments'; const noop = () => { // noop @@ -101,4 +102,38 @@ export function useTrackOnChange( }, [...dependencies, track, options.skipOnMount]); } +/** + * Hook that fires Experiment Viewed if user is in an experiment + * + * @param testName - The name of the experiment to track. + * @param shouldFire - A boolean indicating whether to fire the event. Defaults to true. + * + * @example + * useFireExperimentViewed({ + * testName: TestName.earlyJourneyIndexesGuidance, + * shouldFire: enableInIndexesGuidanceExp , + * }); + */ +export const useFireExperimentViewed = ({ + testName, + shouldFire = true, +}: { + testName: TestName; + shouldFire?: boolean; +}) => { + useTrackOnChange( + (track: TrackFunction) => { + if (!shouldFire) { + return; + } + track('Experiment Viewed', { + test_name: testName, + }); + }, + [shouldFire, testName], + undefined + ); +}; + export type { TrackFunction }; +export { TestName }; diff --git a/packages/compass-telemetry/src/telemetry-events.ts b/packages/compass-telemetry/src/telemetry-events.ts index c669db82c73..c6e01aaf1e0 100644 --- a/packages/compass-telemetry/src/telemetry-events.ts +++ b/packages/compass-telemetry/src/telemetry-events.ts @@ -2673,6 +2673,11 @@ type SecretStorageNotAvailableEvent = CommonEvent<{ payload: Record; }>; +type ExperimentViewedEvent = CommonEvent<{ + name: 'Experiment Viewed'; + payload: { test_name: string }; +}>; + export type TelemetryEvent = | AggregationCanceledEvent | AggregationCopiedEvent @@ -2793,4 +2798,5 @@ export type TelemetryEvent = | LargestContentfulPaintEvent | FirstInputDelayEvent | CumulativeLayoutShiftEvent - | TimeToFirstByteEvent; + | TimeToFirstByteEvent + | ExperimentViewedEvent;