Skip to content

Commit 0a28c5a

Browse files
rubydonggribnoysup
andauthored
feat: Create actual indexes and fix up state + error logic CLOUDP-317945 (#6933)
* add index from index suggestions * disable the create index button when data is not complete * add disable show suggested index button logic * disable covered queries button if there's no changes to fields * adjusting error message and added analytics for error parsing * finished adding error and segment event for covered queries * fix lint issues for opening from nudge * fix more typing and clear error when there's new changes * more linting + error handling * fixed initialQuery typing, wrapped validation inside useMemo, and added comments for cleaning * fixed up typing more * fixed index flow section test by wrapping it in provider * changed document to use mongodb one * added provider to create-index-form.spec.tsx too * fix tests for create-index-actions.spec.tsx * add typing for the spys --------- Co-authored-by: Sergey Petushkov <[email protected]>
1 parent be2f774 commit 0a28c5a

File tree

13 files changed

+268
-149
lines changed

13 files changed

+268
-149
lines changed

packages/compass-crud/src/stores/crud-store.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1852,7 +1852,7 @@ class CrudStoreImpl
18521852

18531853
openCreateIndexModal() {
18541854
this.localAppRegistry.emit('open-create-index-modal', {
1855-
query: EJSON.serialize(this.queryBar.getLastAppliedQuery('crud')),
1855+
query: EJSON.serialize(this.queryBar.getLastAppliedQuery('crud')?.filter),
18561856
});
18571857
}
18581858

packages/compass-indexes/src/components/create-index-actions/create-index-actions.spec.jsx renamed to packages/compass-indexes/src/components/create-index-actions/create-index-actions.spec.tsx

Lines changed: 26 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,16 @@ import {
88
userEvent,
99
within,
1010
} from '@mongodb-js/testing-library-compass';
11+
import { setupStore } from '../../../test/setup-store';
12+
import { Provider } from 'react-redux';
1113

12-
import CreateIndexActions from '../create-index-actions';
14+
import CreateIndexActions from '.';
1315

1416
describe('CreateIndexActions Component', function () {
15-
let clearErrorSpy;
16-
let onCreateIndexClickSpy;
17-
let closeCreateIndexModalSpy;
17+
let clearErrorSpy: any;
18+
let onCreateIndexClickSpy: any;
19+
let closeCreateIndexModalSpy: any;
20+
const store = setupStore();
1821

1922
beforeEach(function () {
2023
clearErrorSpy = sinon.spy();
@@ -28,30 +31,29 @@ describe('CreateIndexActions Component', function () {
2831
closeCreateIndexModalSpy = null;
2932
});
3033

31-
it('renders a cancel button', function () {
34+
const renderComponent = (error?: string) => {
3235
render(
33-
<CreateIndexActions
34-
error={null}
35-
onErrorBannerCloseClick={clearErrorSpy}
36-
onCreateIndexClick={onCreateIndexClickSpy}
37-
onCancelCreateIndexClick={closeCreateIndexModalSpy}
38-
/>
36+
<Provider store={store}>
37+
<CreateIndexActions
38+
error={error || null}
39+
onErrorBannerCloseClick={clearErrorSpy}
40+
onCreateIndexClick={onCreateIndexClickSpy}
41+
onCancelCreateIndexClick={closeCreateIndexModalSpy}
42+
showIndexesGuidanceVariant={false}
43+
/>
44+
</Provider>
3945
);
46+
};
47+
it('renders a cancel button', function () {
48+
renderComponent();
4049

4150
const button = screen.getByTestId('create-index-actions-cancel-button');
4251
expect(button.textContent).to.be.equal('Cancel');
4352
});
4453

4554
context('onCancel', function () {
4655
it('calls the closeCreateIndexModal function', function () {
47-
render(
48-
<CreateIndexActions
49-
error={null}
50-
onErrorBannerCloseClick={clearErrorSpy}
51-
onCreateIndexClick={onCreateIndexClickSpy}
52-
onCancelCreateIndexClick={closeCreateIndexModalSpy}
53-
/>
54-
);
56+
renderComponent();
5557

5658
const button = screen.getByTestId('create-index-actions-cancel-button');
5759
userEvent.click(button);
@@ -61,14 +63,7 @@ describe('CreateIndexActions Component', function () {
6163

6264
context('onConfirm', function () {
6365
it('calls the onCreateIndexClick function', function () {
64-
render(
65-
<CreateIndexActions
66-
error={null}
67-
onErrorBannerCloseClick={clearErrorSpy}
68-
onCreateIndexClick={onCreateIndexClickSpy}
69-
onCancelCreateIndexClick={closeCreateIndexModalSpy}
70-
/>
71-
);
66+
renderComponent();
7267

7368
const button = screen.getByTestId(
7469
'create-index-actions-create-index-button'
@@ -79,15 +74,7 @@ describe('CreateIndexActions Component', function () {
7974
});
8075

8176
it('renders a create index button', function () {
82-
render(
83-
<CreateIndexActions
84-
error={null}
85-
onErrorBannerCloseClick={clearErrorSpy}
86-
onCreateIndexClick={onCreateIndexClickSpy}
87-
onCancelCreateIndexClick={closeCreateIndexModalSpy}
88-
/>
89-
);
90-
77+
renderComponent();
9178
const button = screen.getByTestId(
9279
'create-index-actions-create-index-button'
9380
);
@@ -96,14 +83,7 @@ describe('CreateIndexActions Component', function () {
9683

9784
context('with error', function () {
9885
it('renders error banner', function () {
99-
render(
100-
<CreateIndexActions
101-
error={'Some error happened!'}
102-
onErrorBannerCloseClick={clearErrorSpy}
103-
onCreateIndexClick={onCreateIndexClickSpy}
104-
onCancelCreateIndexClick={closeCreateIndexModalSpy}
105-
/>
106-
);
86+
renderComponent('Some error happened!');
10787

10888
const errorBanner = screen.getByTestId(
10989
'create-index-actions-error-banner-wrapper'
@@ -112,14 +92,7 @@ describe('CreateIndexActions Component', function () {
11292
});
11393

11494
it('closes error banner', function () {
115-
render(
116-
<CreateIndexActions
117-
error={'Some error happened!'}
118-
onErrorBannerCloseClick={clearErrorSpy}
119-
onCreateIndexClick={onCreateIndexClickSpy}
120-
onCancelCreateIndexClick={closeCreateIndexModalSpy}
121-
/>
122-
);
95+
renderComponent('Some error happened!');
12396

12497
const errorBanner = screen.getByTestId(
12598
'create-index-actions-error-banner-wrapper'
@@ -133,14 +106,7 @@ describe('CreateIndexActions Component', function () {
133106

134107
context('without error', function () {
135108
it('does not render error banner', function () {
136-
render(
137-
<CreateIndexActions
138-
error={null}
139-
onErrorBannerCloseClick={clearErrorSpy}
140-
onCreateIndexClick={onCreateIndexClickSpy}
141-
onCancelCreateIndexClick={closeCreateIndexModalSpy}
142-
/>
143-
);
109+
renderComponent();
144110

145111
const errorBanner = screen.queryByTestId(
146112
'create-index-actions-error-banner-wrapper'

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

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
import React from 'react';
22
import { css, Banner, spacing, Button } from '@mongodb-js/compass-components';
3+
import { connect } from 'react-redux';
4+
import { areAllFieldsFilledIn } from '../../utils/create-index-modal-validation';
5+
import type { Field, Tab } from '../../modules/create-index';
6+
import type { RootState } from '../../modules';
37

48
const containerStyles = css({
59
display: 'flex',
@@ -27,12 +31,37 @@ function CreateIndexActions({
2731
onErrorBannerCloseClick,
2832
onCreateIndexClick,
2933
onCancelCreateIndexClick,
34+
fields,
35+
currentTab,
36+
showIndexesGuidanceVariant,
37+
indexSuggestions,
3038
}: {
3139
error: string | null;
3240
onErrorBannerCloseClick: () => void;
3341
onCreateIndexClick: () => void;
3442
onCancelCreateIndexClick: () => void;
43+
fields: Field[];
44+
currentTab: Tab;
45+
showIndexesGuidanceVariant: boolean;
46+
indexSuggestions: Record<string, number> | null;
3547
}) {
48+
let isCreateIndexButtonDisabled = false;
49+
50+
if (showIndexesGuidanceVariant) {
51+
// Disable create index button if the user is in Query Flow and has no suggestions
52+
if (currentTab === 'QueryFlow') {
53+
if (indexSuggestions === null) {
54+
isCreateIndexButtonDisabled = true;
55+
}
56+
}
57+
// Or if they are in the Index Flow but have not completed the fields
58+
else {
59+
if (!areAllFieldsFilledIn(fields)) {
60+
isCreateIndexButtonDisabled = true;
61+
}
62+
}
63+
}
64+
3665
return (
3766
<div className={containerStyles}>
3867
{error && (
@@ -61,11 +90,21 @@ function CreateIndexActions({
6190
onClick={onCreateIndexClick}
6291
variant="primary"
6392
className={createIndexButtonStyles}
93+
disabled={isCreateIndexButtonDisabled}
6494
>
6595
Create Index
6696
</Button>
6797
</div>
6898
);
6999
}
70100

71-
export default CreateIndexActions;
101+
const mapState = ({ createIndex }: RootState) => {
102+
const { fields, currentTab, indexSuggestions } = createIndex;
103+
return {
104+
fields,
105+
currentTab,
106+
indexSuggestions,
107+
};
108+
};
109+
110+
export default connect(mapState)(CreateIndexActions);

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

Lines changed: 23 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,13 @@ import type { Field } from '../../modules/create-index';
55
import { expect } from 'chai';
66
import type { SinonSpy } from 'sinon';
77

8+
import { setupStore } from '../../../test/setup-store';
89
import sinon from 'sinon';
10+
import { Provider } from 'react-redux';
911

1012
describe('CreateIndexForm', () => {
1113
let onTabClickSpy: SinonSpy;
14+
const store = setupStore();
1215

1316
beforeEach(function () {
1417
onTabClickSpy = sinon.spy();
@@ -20,24 +23,26 @@ describe('CreateIndexForm', () => {
2023
showIndexesGuidanceVariant?: boolean;
2124
}) => {
2225
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-
query={null}
40-
/>
26+
<Provider store={store}>
27+
<CreateIndexForm
28+
namespace="testNamespace"
29+
fields={
30+
[
31+
{ name: 'field1', type: 'string' },
32+
{ name: 'field2', type: 'number' },
33+
] as Field[]
34+
}
35+
serverVersion="5.0.0"
36+
currentTab="IndexFlow"
37+
onSelectFieldNameClick={() => {}}
38+
onSelectFieldTypeClick={() => {}}
39+
onAddFieldClick={() => {}}
40+
onRemoveFieldClick={() => {}}
41+
onTabClick={onTabClickSpy}
42+
showIndexesGuidanceVariant={showIndexesGuidanceVariant || false}
43+
query={null}
44+
/>
45+
</Provider>
4146
);
4247
};
4348

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ import { usePreference } from 'compass-preferences-model/provider';
2121
import IndexFlowSection from './index-flow-section';
2222
import QueryFlowSection from './query-flow-section';
2323
import toNS from 'mongodb-ns';
24-
import type { Document } from 'bson';
24+
import type { Document } from 'mongodb';
2525

2626
const createIndexModalFieldsStyles = css({
2727
margin: `${spacing[600]}px 0 ${spacing[800]}px 0`,

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

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,11 @@ import { render, screen } from '@mongodb-js/testing-library-compass';
33
import IndexFlowSection from './index-flow-section';
44
import { expect } from 'chai';
55
import type { Field } from '../../modules/create-index';
6+
import { Provider } from 'react-redux';
7+
import { setupStore } from '../../../test/setup-store';
68

79
describe('IndexFlowSection', () => {
10+
const store = setupStore();
811
const renderComponent = ({
912
createIndexFieldsComponent,
1013
fields,
@@ -13,12 +16,14 @@ describe('IndexFlowSection', () => {
1316
fields?: Field[];
1417
}) => {
1518
render(
16-
<IndexFlowSection
17-
createIndexFieldsComponent={createIndexFieldsComponent ?? null}
18-
fields={fields || []}
19-
dbName={'fakeDBName'}
20-
collectionName={'fakeCollectionName'}
21-
/>
19+
<Provider store={store}>
20+
<IndexFlowSection
21+
createIndexFieldsComponent={createIndexFieldsComponent ?? null}
22+
fields={fields || []}
23+
dbName={'fakeDBName'}
24+
collectionName={'fakeCollectionName'}
25+
/>
26+
</Provider>
2227
);
2328
};
2429

0 commit comments

Comments
 (0)