diff --git a/packages/compass-indexes/src/components/create-index-form/create-index-form.spec.tsx b/packages/compass-indexes/src/components/create-index-form/create-index-form.spec.tsx new file mode 100644 index 00000000000..4475b03f517 --- /dev/null +++ b/packages/compass-indexes/src/components/create-index-form/create-index-form.spec.tsx @@ -0,0 +1,67 @@ +import React from 'react'; +import { render, screen, fireEvent } from '@mongodb-js/testing-library-compass'; +import { CreateIndexForm } from './create-index-form'; +import type { Field } from '../../modules/create-index'; +import { expect } from 'chai'; +import type { SinonSpy } from 'sinon'; + +import sinon from 'sinon'; + +describe('CreateIndexForm', () => { + let onTabClickSpy: SinonSpy; + + beforeEach(function () { + onTabClickSpy = sinon.spy(); + }); + + const renderComponent = ({ + showIndexesGuidanceVariant, + }: { + showIndexesGuidanceVariant?: boolean; + }) => { + render( + {}} + onSelectFieldTypeClick={() => {}} + onAddFieldClick={() => {}} + onRemoveFieldClick={() => {}} + onTabClick={onTabClickSpy} + showIndexesGuidanceVariant={showIndexesGuidanceVariant || false} + /> + ); + }; + + it('renders the create index form', () => { + renderComponent({}); + expect(screen.getByTestId('create-index-form')).to.exist; + }); + + describe('when showIndexesGuidanceVariant is false', () => { + it('renders the RadioBoxGroup', () => { + renderComponent({}); + expect(screen.queryByTestId('create-index-form-flows')).not.to.exist; + }); + }); + + describe('when showIndexesGuidanceVariant is true', () => { + it('renders the RadioBoxGroup', () => { + renderComponent({ showIndexesGuidanceVariant: true }); + expect(screen.getByTestId('create-index-form-flows')).to.exist; + }); + it('calls onTabClick when a RadioBox is selected', () => { + renderComponent({ showIndexesGuidanceVariant: true }); + const radioBox = screen.getByLabelText('Start with a Query'); + fireEvent.click(radioBox); + expect(onTabClickSpy).to.be.calledWith('QueryFlow'); + }); + }); +}); diff --git a/packages/compass-indexes/src/components/create-index-form/create-index-form.tsx b/packages/compass-indexes/src/components/create-index-form/create-index-form.tsx index 111f3442a12..6d319270f04 100644 --- a/packages/compass-indexes/src/components/create-index-form/create-index-form.tsx +++ b/packages/compass-indexes/src/components/create-index-form/create-index-form.tsx @@ -1,6 +1,13 @@ import React, { useMemo } from 'react'; -import { css, spacing, Accordion, Body } from '@mongodb-js/compass-components'; -import type { Field } from '../../modules/create-index'; +import { + css, + spacing, + Accordion, + Body, + RadioBoxGroup, + RadioBox, +} from '@mongodb-js/compass-components'; +import type { Field, Tab } from '../../modules/create-index'; import { useAutocompleteFields } from '@mongodb-js/compass-field-store'; import { CreateIndexFields } from '../create-index-fields'; import { hasColumnstoreIndexesSupport } from '../../utils/columnstore-indexes'; @@ -24,24 +31,34 @@ const createIndexModalOptionStyles = css({ paddingLeft: spacing[1] + 2, }); -type CreateIndexFormProps = { +const createIndexModalFlowsStyles = css({ + marginBottom: spacing[600], +}); + +export type CreateIndexFormProps = { namespace: string; fields: Field[]; serverVersion: string; + currentTab: Tab; onSelectFieldNameClick: (idx: number, name: string) => void; onSelectFieldTypeClick: (idx: number, fType: string) => void; onAddFieldClick: () => void; // Plus icon. onRemoveFieldClick: (idx: number) => void; // Minus icon. + onTabClick: (tab: Tab) => void; + showIndexesGuidanceVariant?: boolean; }; function CreateIndexForm({ namespace, fields, serverVersion, + currentTab, onSelectFieldNameClick, onSelectFieldTypeClick, onAddFieldClick, onRemoveFieldClick, + onTabClick, + showIndexesGuidanceVariant, }: CreateIndexFormProps) { const { id: connectionId } = useConnectionInfo(); const rollingIndexesFeatureEnabled = !!usePreference('enableRollingIndexes'); @@ -68,10 +85,33 @@ function CreateIndexForm({ className={createIndexModalFieldsStyles} data-testid="create-index-form" > - - Index fields - - {fields.length > 0 ? ( + {showIndexesGuidanceVariant ? ( + { + onTabClick(e.target.value as Tab); + }} + value={currentTab} + className={createIndexModalFlowsStyles} + > + + Start with an Index + + + Start with a Query + + + ) : ( + + Index fields + + )} + + {/* Only show the fields if user is in the Start with an index flow or if they're in the control */} + {fields.length > 0 && + (!showIndexesGuidanceVariant || currentTab === 'IndexFlow') ? ( & { isVisible: boolean; namespace: string; error: string | null; + currentTab: Tab; onErrorBannerCloseClick: () => void; onCreateIndexClick: () => void; onCancelCreateIndexClick: () => void; + onTabClick: (tab: Tab) => void; }; function CreateIndexModal({ isVisible, namespace, error, + currentTab, onErrorBannerCloseClick, onCreateIndexClick, onCancelCreateIndexClick, @@ -98,7 +103,12 @@ function CreateIndexModal({ )} - + @@ -114,13 +124,14 @@ function CreateIndexModal({ } const mapState = ({ namespace, serverVersion, createIndex }: RootState) => { - const { fields, error, isVisible } = createIndex; + const { fields, error, isVisible, currentTab } = createIndex; return { fields, error, isVisible, namespace, serverVersion, + currentTab, }; }; @@ -132,6 +143,7 @@ const mapDispatch = { onRemoveFieldClick: fieldRemoved, onSelectFieldNameClick: updateFieldName, onSelectFieldTypeClick: fieldTypeUpdated, + onTabClick: tabUpdated, }; export default connect(mapState, mapDispatch)(CreateIndexModal); diff --git a/packages/compass-indexes/src/modules/create-index.tsx b/packages/compass-indexes/src/modules/create-index.tsx index ba723067276..89eab255407 100644 --- a/packages/compass-indexes/src/modules/create-index.tsx +++ b/packages/compass-indexes/src/modules/create-index.tsx @@ -25,11 +25,14 @@ export enum ActionTypes { CreateIndexClosed = 'compass-indexes/create-index/create-index-hidden', CreateIndexFormSubmitted = 'compass-indexes/create-index/create-index-form-submitted', + + TabUpdated = 'compass-indexes/create-index/tab-updated', } // fields export type Field = { name: string; type: string }; +export type Tab = 'QueryFlow' | 'IndexFlow'; const INITIAL_FIELDS_STATE = [{ name: '', type: '' }]; @@ -82,6 +85,11 @@ type CreateIndexFormSubmittedAction = { type: ActionTypes.CreateIndexFormSubmitted; }; +type TabUpdatedAction = { + type: ActionTypes.TabUpdated; + currentTab: Tab; +}; + export const fieldAdded = () => ({ type: ActionTypes.FieldAdded, }); @@ -97,6 +105,11 @@ export const fieldTypeUpdated = (idx: number, fType: string) => ({ fType, }); +export const tabUpdated = (tab: Tab) => ({ + type: ActionTypes.TabUpdated, + currentTab: tab, +}); + const fieldsChanged = (fields: Field[]) => ({ type: ActionTypes.FieldsChanged, fields: fields, @@ -280,6 +293,9 @@ export type State = { // index options options: Options; + + // current tab that user is on (Query Flow or Index Flow) + currentTab: Tab; }; export const INITIAL_STATE: State = { @@ -288,6 +304,7 @@ export const INITIAL_STATE: State = { error: null, fields: INITIAL_FIELDS_STATE, options: INITIAL_OPTIONS_STATE, + currentTab: 'IndexFlow', }; function getInitialState(): State { @@ -590,6 +607,13 @@ const reducer: Reducer = (state = INITIAL_STATE, action) => { }; } + if (isAction(action, ActionTypes.TabUpdated)) { + return { + ...state, + currentTab: action.currentTab, + }; + } + return state; };