Skip to content

Commit dd31ce6

Browse files
authored
feat: Add radio boxes for the two flows in create index modal CLOUDP-311780 (#6873)
* added query and index tabs * added tests * only show indexes in the index flow * make showIndexesGuidanceVariant optional * update the condition to be reversed * fix typing for onTabClickSpy
1 parent 63d7a66 commit dd31ce6

File tree

4 files changed

+152
-9
lines changed

4 files changed

+152
-9
lines changed
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
import React from 'react';
2+
import { render, screen, fireEvent } from '@mongodb-js/testing-library-compass';
3+
import { CreateIndexForm } from './create-index-form';
4+
import type { Field } from '../../modules/create-index';
5+
import { expect } from 'chai';
6+
import type { SinonSpy } from 'sinon';
7+
8+
import sinon from 'sinon';
9+
10+
describe('CreateIndexForm', () => {
11+
let onTabClickSpy: SinonSpy;
12+
13+
beforeEach(function () {
14+
onTabClickSpy = sinon.spy();
15+
});
16+
17+
const renderComponent = ({
18+
showIndexesGuidanceVariant,
19+
}: {
20+
showIndexesGuidanceVariant?: boolean;
21+
}) => {
22+
render(
23+
<CreateIndexForm
24+
namespace="testNamespace"
25+
fields={
26+
[
27+
{ name: 'field1', type: 'string' },
28+
{ name: 'field2', type: 'number' },
29+
] as Field[]
30+
}
31+
serverVersion="5.0.0"
32+
currentTab="IndexFlow"
33+
onSelectFieldNameClick={() => {}}
34+
onSelectFieldTypeClick={() => {}}
35+
onAddFieldClick={() => {}}
36+
onRemoveFieldClick={() => {}}
37+
onTabClick={onTabClickSpy}
38+
showIndexesGuidanceVariant={showIndexesGuidanceVariant || false}
39+
/>
40+
);
41+
};
42+
43+
it('renders the create index form', () => {
44+
renderComponent({});
45+
expect(screen.getByTestId('create-index-form')).to.exist;
46+
});
47+
48+
describe('when showIndexesGuidanceVariant is false', () => {
49+
it('renders the RadioBoxGroup', () => {
50+
renderComponent({});
51+
expect(screen.queryByTestId('create-index-form-flows')).not.to.exist;
52+
});
53+
});
54+
55+
describe('when showIndexesGuidanceVariant is true', () => {
56+
it('renders the RadioBoxGroup', () => {
57+
renderComponent({ showIndexesGuidanceVariant: true });
58+
expect(screen.getByTestId('create-index-form-flows')).to.exist;
59+
});
60+
it('calls onTabClick when a RadioBox is selected', () => {
61+
renderComponent({ showIndexesGuidanceVariant: true });
62+
const radioBox = screen.getByLabelText('Start with a Query');
63+
fireEvent.click(radioBox);
64+
expect(onTabClickSpy).to.be.calledWith('QueryFlow');
65+
});
66+
});
67+
});

packages/compass-indexes/src/components/create-index-form/create-index-form.tsx

Lines changed: 47 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,13 @@
11
import React, { useMemo } from 'react';
2-
import { css, spacing, Accordion, Body } from '@mongodb-js/compass-components';
3-
import type { Field } from '../../modules/create-index';
2+
import {
3+
css,
4+
spacing,
5+
Accordion,
6+
Body,
7+
RadioBoxGroup,
8+
RadioBox,
9+
} from '@mongodb-js/compass-components';
10+
import type { Field, Tab } from '../../modules/create-index';
411
import { useAutocompleteFields } from '@mongodb-js/compass-field-store';
512
import { CreateIndexFields } from '../create-index-fields';
613
import { hasColumnstoreIndexesSupport } from '../../utils/columnstore-indexes';
@@ -24,24 +31,34 @@ const createIndexModalOptionStyles = css({
2431
paddingLeft: spacing[100] + 2,
2532
});
2633

27-
type CreateIndexFormProps = {
34+
const createIndexModalFlowsStyles = css({
35+
marginBottom: spacing[600],
36+
});
37+
38+
export type CreateIndexFormProps = {
2839
namespace: string;
2940
fields: Field[];
3041
serverVersion: string;
42+
currentTab: Tab;
3143
onSelectFieldNameClick: (idx: number, name: string) => void;
3244
onSelectFieldTypeClick: (idx: number, fType: string) => void;
3345
onAddFieldClick: () => void; // Plus icon.
3446
onRemoveFieldClick: (idx: number) => void; // Minus icon.
47+
onTabClick: (tab: Tab) => void;
48+
showIndexesGuidanceVariant?: boolean;
3549
};
3650

3751
function CreateIndexForm({
3852
namespace,
3953
fields,
4054
serverVersion,
55+
currentTab,
4156
onSelectFieldNameClick,
4257
onSelectFieldTypeClick,
4358
onAddFieldClick,
4459
onRemoveFieldClick,
60+
onTabClick,
61+
showIndexesGuidanceVariant,
4562
}: CreateIndexFormProps) {
4663
const { id: connectionId } = useConnectionInfo();
4764
const rollingIndexesFeatureEnabled = !!usePreference('enableRollingIndexes');
@@ -68,10 +85,33 @@ function CreateIndexForm({
6885
className={createIndexModalFieldsStyles}
6986
data-testid="create-index-form"
7087
>
71-
<Body weight="medium" className={indexFieldsHeaderStyles}>
72-
Index fields
73-
</Body>
74-
{fields.length > 0 ? (
88+
{showIndexesGuidanceVariant ? (
89+
<RadioBoxGroup
90+
aria-labelledby="index-flows"
91+
data-testid="create-index-form-flows"
92+
id="create-index-form-flows"
93+
onChange={(e) => {
94+
onTabClick(e.target.value as Tab);
95+
}}
96+
value={currentTab}
97+
className={createIndexModalFlowsStyles}
98+
>
99+
<RadioBox id="index-flow" value={'IndexFlow'}>
100+
Start with an Index
101+
</RadioBox>
102+
<RadioBox id="query-flow" value={'QueryFlow'}>
103+
Start with a Query
104+
</RadioBox>
105+
</RadioBoxGroup>
106+
) : (
107+
<Body weight="medium" className={indexFieldsHeaderStyles}>
108+
Index fields
109+
</Body>
110+
)}
111+
112+
{/* Only show the fields if user is in the Start with an index flow or if they're in the control */}
113+
{fields.length > 0 &&
114+
(!showIndexesGuidanceVariant || currentTab === 'IndexFlow') ? (
75115
<CreateIndexFields
76116
schemaFields={schemaFieldNames}
77117
fields={fields}

packages/compass-indexes/src/components/create-index-modal/create-index-modal.tsx

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import {
66
ModalHeader,
77
ModalBody,
88
} from '@mongodb-js/compass-components';
9+
import type { Tab } from '../../modules/create-index';
910
import {
1011
fieldAdded,
1112
fieldRemoved,
@@ -14,6 +15,7 @@ import {
1415
errorCleared,
1516
createIndexFormSubmitted,
1617
createIndexClosed,
18+
tabUpdated,
1719
} from '../../modules/create-index';
1820
import { CreateIndexForm } from '../create-index-form/create-index-form';
1921
import CreateIndexActions from '../create-index-actions';
@@ -32,15 +34,18 @@ type CreateIndexModalProps = React.ComponentProps<typeof CreateIndexForm> & {
3234
isVisible: boolean;
3335
namespace: string;
3436
error: string | null;
37+
currentTab: Tab;
3538
onErrorBannerCloseClick: () => void;
3639
onCreateIndexClick: () => void;
3740
onCancelCreateIndexClick: () => void;
41+
onTabClick: (tab: Tab) => void;
3842
};
3943

4044
function CreateIndexModal({
4145
isVisible,
4246
namespace,
4347
error,
48+
currentTab,
4449
onErrorBannerCloseClick,
4550
onCreateIndexClick,
4651
onCancelCreateIndexClick,
@@ -98,7 +103,12 @@ function CreateIndexModal({
98103
)}
99104

100105
<ModalBody>
101-
<CreateIndexForm namespace={namespace} {...props} />
106+
<CreateIndexForm
107+
{...props}
108+
namespace={namespace}
109+
showIndexesGuidanceVariant={showIndexesGuidanceVariant}
110+
currentTab={currentTab}
111+
/>
102112
</ModalBody>
103113

104114
<ModalFooter>
@@ -114,13 +124,14 @@ function CreateIndexModal({
114124
}
115125

116126
const mapState = ({ namespace, serverVersion, createIndex }: RootState) => {
117-
const { fields, error, isVisible } = createIndex;
127+
const { fields, error, isVisible, currentTab } = createIndex;
118128
return {
119129
fields,
120130
error,
121131
isVisible,
122132
namespace,
123133
serverVersion,
134+
currentTab,
124135
};
125136
};
126137

@@ -132,6 +143,7 @@ const mapDispatch = {
132143
onRemoveFieldClick: fieldRemoved,
133144
onSelectFieldNameClick: updateFieldName,
134145
onSelectFieldTypeClick: fieldTypeUpdated,
146+
onTabClick: tabUpdated,
135147
};
136148

137149
export default connect(mapState, mapDispatch)(CreateIndexModal);

packages/compass-indexes/src/modules/create-index.tsx

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,14 @@ export enum ActionTypes {
2525
CreateIndexClosed = 'compass-indexes/create-index/create-index-hidden',
2626

2727
CreateIndexFormSubmitted = 'compass-indexes/create-index/create-index-form-submitted',
28+
29+
TabUpdated = 'compass-indexes/create-index/tab-updated',
2830
}
2931

3032
// fields
3133

3234
export type Field = { name: string; type: string };
35+
export type Tab = 'QueryFlow' | 'IndexFlow';
3336

3437
const INITIAL_FIELDS_STATE = [{ name: '', type: '' }];
3538

@@ -82,6 +85,11 @@ type CreateIndexFormSubmittedAction = {
8285
type: ActionTypes.CreateIndexFormSubmitted;
8386
};
8487

88+
type TabUpdatedAction = {
89+
type: ActionTypes.TabUpdated;
90+
currentTab: Tab;
91+
};
92+
8593
export const fieldAdded = () => ({
8694
type: ActionTypes.FieldAdded,
8795
});
@@ -97,6 +105,11 @@ export const fieldTypeUpdated = (idx: number, fType: string) => ({
97105
fType,
98106
});
99107

108+
export const tabUpdated = (tab: Tab) => ({
109+
type: ActionTypes.TabUpdated,
110+
currentTab: tab,
111+
});
112+
100113
const fieldsChanged = (fields: Field[]) => ({
101114
type: ActionTypes.FieldsChanged,
102115
fields: fields,
@@ -280,6 +293,9 @@ export type State = {
280293

281294
// index options
282295
options: Options;
296+
297+
// current tab that user is on (Query Flow or Index Flow)
298+
currentTab: Tab;
283299
};
284300

285301
export const INITIAL_STATE: State = {
@@ -288,6 +304,7 @@ export const INITIAL_STATE: State = {
288304
error: null,
289305
fields: INITIAL_FIELDS_STATE,
290306
options: INITIAL_OPTIONS_STATE,
307+
currentTab: 'IndexFlow',
291308
};
292309

293310
function getInitialState(): State {
@@ -590,6 +607,13 @@ const reducer: Reducer<State, Action> = (state = INITIAL_STATE, action) => {
590607
};
591608
}
592609

610+
if (isAction<TabUpdatedAction>(action, ActionTypes.TabUpdated)) {
611+
return {
612+
...state,
613+
currentTab: action.currentTab,
614+
};
615+
}
616+
593617
return state;
594618
};
595619

0 commit comments

Comments
 (0)