From e61dc7268fdad8249d303d63e79d78483bba12f4 Mon Sep 17 00:00:00 2001 From: Ruby Dong Date: Wed, 16 Apr 2025 14:03:08 -0400 Subject: [PATCH 1/6] added query and index tabs --- .../create-index-form/create-index-form.tsx | 41 ++++++++++++++++++- .../create-index-modal/create-index-modal.tsx | 16 +++++++- .../src/modules/create-index.tsx | 24 +++++++++++ 3 files changed, 77 insertions(+), 4 deletions(-) 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..13fd8e08dfd 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, }); +const createIndexModalFlowsStyles = css({ + marginBottom: spacing[600], +}); + 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,6 +85,26 @@ function CreateIndexForm({ className={createIndexModalFieldsStyles} data-testid="create-index-form" > + {showIndexesGuidanceVariant && ( + { + onTabClick(e.target.value as Tab); + }} + value={currentTab} + className={createIndexModalFlowsStyles} + > + + Start with an Index + + + Start with a Query + + + )} + Index fields 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 a37b1a85ab9..70b8aba6318 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 @@ -6,6 +6,7 @@ import { ModalHeader, ModalBody, } from '@mongodb-js/compass-components'; +import type { Tab } from '../../modules/create-index'; import { fieldAdded, fieldRemoved, @@ -14,6 +15,7 @@ import { errorCleared, createIndexFormSubmitted, createIndexClosed, + tabUpdated, } from '../../modules/create-index'; import { CreateIndexForm } from '../create-index-form/create-index-form'; import CreateIndexActions from '../create-index-actions'; @@ -32,15 +34,18 @@ type CreateIndexModalProps = React.ComponentProps & { 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; }; From 7e6218c6a9bb24db20db23d4a5dd30ab40f10915 Mon Sep 17 00:00:00 2001 From: Ruby Dong Date: Wed, 16 Apr 2025 16:10:55 -0400 Subject: [PATCH 2/6] added tests --- .../create-index-form.spec.tsx | 70 +++++++++++++++++++ .../create-index-form/create-index-form.tsx | 2 +- 2 files changed, 71 insertions(+), 1 deletion(-) create mode 100644 packages/compass-indexes/src/components/create-index-form/create-index-form.spec.tsx 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..aa1d1d060ec --- /dev/null +++ b/packages/compass-indexes/src/components/create-index-form/create-index-form.spec.tsx @@ -0,0 +1,70 @@ +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 sinon from 'sinon'; + +describe('CreateIndexForm', () => { + let onTabClickSpy; + + beforeEach(function () { + onTabClickSpy = sinon.spy(); + }); + + afterEach(function () { + onTabClickSpy = null; + }); + + 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 13fd8e08dfd..28b783cda34 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 @@ -35,7 +35,7 @@ const createIndexModalFlowsStyles = css({ marginBottom: spacing[600], }); -type CreateIndexFormProps = { +export type CreateIndexFormProps = { namespace: string; fields: Field[]; serverVersion: string; From fef8475273ada9fa0c3ee6d9112445d429337ba0 Mon Sep 17 00:00:00 2001 From: Ruby Dong Date: Fri, 18 Apr 2025 12:30:59 -0400 Subject: [PATCH 3/6] only show indexes in the index flow --- .../create-index-form/create-index-form.tsx | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) 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 28b783cda34..37c2d81d954 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 @@ -85,7 +85,7 @@ function CreateIndexForm({ className={createIndexModalFieldsStyles} data-testid="create-index-form" > - {showIndexesGuidanceVariant && ( + {showIndexesGuidanceVariant ? ( + ) : ( + + Index fields + )} - - Index fields - - {fields.length > 0 ? ( + {/* 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' : true) ? ( Date: Fri, 18 Apr 2025 13:22:06 -0400 Subject: [PATCH 4/6] make showIndexesGuidanceVariant optional --- .../src/components/create-index-form/create-index-form.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 37c2d81d954..e14c318839d 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 @@ -45,7 +45,7 @@ export type CreateIndexFormProps = { onAddFieldClick: () => void; // Plus icon. onRemoveFieldClick: (idx: number) => void; // Minus icon. onTabClick: (tab: Tab) => void; - showIndexesGuidanceVariant: boolean; + showIndexesGuidanceVariant?: boolean; }; function CreateIndexForm({ From 097527401c491dfdd67d20f1a2d99a6114b10252 Mon Sep 17 00:00:00 2001 From: Ruby Dong Date: Fri, 18 Apr 2025 13:35:20 -0400 Subject: [PATCH 5/6] update the condition to be reversed --- .../src/components/create-index-form/create-index-form.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 e14c318839d..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 @@ -111,7 +111,7 @@ function CreateIndexForm({ {/* 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' : true) ? ( + (!showIndexesGuidanceVariant || currentTab === 'IndexFlow') ? ( Date: Fri, 18 Apr 2025 13:49:49 -0400 Subject: [PATCH 6/6] fix typing for onTabClickSpy --- .../create-index-form/create-index-form.spec.tsx | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) 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 index aa1d1d060ec..4475b03f517 100644 --- 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 @@ -3,20 +3,17 @@ 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; + let onTabClickSpy: SinonSpy; beforeEach(function () { onTabClickSpy = sinon.spy(); }); - afterEach(function () { - onTabClickSpy = null; - }); - const renderComponent = ({ showIndexesGuidanceVariant, }: {