Skip to content

Commit 2e115df

Browse files
authored
feat: Fetching index suggestions and dealing with the states CLOUDP-311786 (#6887)
* use mql wip * wip with setting up some actions * fetch sample + cleaned up index suggestions, added loader * fixed sample docs fetching bug * update mql versino * added testing for the three states * finished adding test for success state * address pr comments * show error message * fixing up error msg * alphabetize dependencies and use parseShellBSON * fix query flow section tests * put sample in setup-store.ts test
1 parent 525e56a commit 2e115df

File tree

10 files changed

+478
-140
lines changed

10 files changed

+478
-140
lines changed

package-lock.json

Lines changed: 167 additions & 99 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/compass-components/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@
6363
"@leafygreen-ui/search-input": "^5.0.2",
6464
"@leafygreen-ui/segmented-control": "^10.0.2",
6565
"@leafygreen-ui/select": "^14.0.2",
66+
"@leafygreen-ui/skeleton-loader": "^2.0.11",
6667
"@leafygreen-ui/split-button": "^4.1.5",
6768
"@leafygreen-ui/table": "^13.0.1",
6869
"@leafygreen-ui/tabs": "^14.0.2",

packages/compass-components/src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,3 +211,4 @@ export {
211211
type ItemRenderer as VirtualListItemRenderer,
212212
} from './components/virtual-list';
213213
export { SelectTable } from './components/select-table';
214+
export { ParagraphSkeleton } from '@leafygreen-ui/skeleton-loader';

packages/compass-indexes/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@
8484
"mongodb": "^6.16.0",
8585
"mongodb-collection-model": "^5.26.0",
8686
"mongodb-data-service": "^22.25.8",
87+
"mongodb-mql-engines": "^0.0.4",
8788
"mongodb-query-parser": "^4.3.0",
8889
"mongodb-ns": "^2.4.2",
8990
"numeral": "^2.0.6",

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,15 +24,15 @@ const generateCode = ({
2424
}: {
2525
dbName: string;
2626
collectionName: string;
27-
indexNameTypeMap: { [key: string]: string };
27+
indexNameTypeMap: Record<string, string | number>;
2828
}) => {
2929
let codeStr = `db.getSiblingDB("${dbName}").getCollection("${escapeText(
3030
collectionName
3131
)}").createIndex({\n`;
3232

3333
Object.entries(indexNameTypeMap).forEach(([name, type], index) => {
3434
// Replacing everything inside the parenthesis i.e. (asc)
35-
let parsedType = escapeText(type.replace(/\(.*?\)/g, '')).trim();
35+
let parsedType = escapeText(`${type}`.replace(/\(.*?\)/g, '')).trim();
3636
if (!NUMERIC_INDEX_TYPES.includes(Number(parsedType))) {
3737
parsedType = `"${parsedType}"`;
3838
}
@@ -59,7 +59,7 @@ const MDBCodeViewer = ({
5959
}: {
6060
dbName: string;
6161
collectionName: string;
62-
indexNameTypeMap: { [key: string]: string };
62+
indexNameTypeMap: Record<string, string | number>;
6363
dataTestId?: string;
6464
}) => {
6565
const GeneratedCode = generateCode({

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

Lines changed: 68 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -2,35 +2,83 @@ import React from 'react';
22
import { render, screen } from '@mongodb-js/testing-library-compass';
33
import QueryFlowSection from './query-flow-section';
44
import { expect } from 'chai';
5+
import { Provider } from 'react-redux';
6+
import { setupStore } from '../../../test/setup-store';
7+
import { ActionTypes } from '../../modules/create-index';
58

69
describe('QueryFlowSection', () => {
10+
const store = setupStore();
11+
const dbName = 'fakeDBName';
12+
const collectionName = 'fakeCollectionName';
713
const renderComponent = () => {
814
render(
9-
<QueryFlowSection
10-
schemaFields={[]}
11-
serverVersion="5.0.0"
12-
dbName={'fakeDBName'}
13-
collectionName={'fakeCollectionName'}
14-
/>
15+
<Provider store={store}>
16+
<QueryFlowSection
17+
schemaFields={[]}
18+
serverVersion="5.0.0"
19+
dbName={dbName}
20+
collectionName={collectionName}
21+
/>
22+
</Provider>
1523
);
1624
};
17-
it('renders the input query section with a code editor', () => {
18-
renderComponent();
19-
const codeEditor = screen.getByTestId('query-flow-section-code-editor');
20-
expect(codeEditor).to.be.visible;
25+
26+
describe('in the initial state', () => {
27+
beforeEach(() => {
28+
renderComponent();
29+
});
30+
it('renders the input query section with a code editor', () => {
31+
const codeEditor = screen.getByTestId('query-flow-section-code-editor');
32+
expect(codeEditor).to.be.visible;
33+
});
34+
35+
it('renders the "Show suggested index" button', () => {
36+
const buttonElement = screen.getByText('Show suggested index');
37+
expect(buttonElement).to.be.visible;
38+
});
39+
it('does not render the suggested index section with formatted index code', () => {
40+
const codeElement = screen.queryByTestId(
41+
'query-flow-section-suggested-index'
42+
);
43+
expect(codeElement).to.be.null;
44+
});
2145
});
2246

23-
it('renders the "Show suggested index" button', () => {
24-
renderComponent();
25-
const buttonElement = screen.getByText('Show suggested index');
26-
expect(buttonElement).to.be.visible;
47+
describe('when fetching for index suggestions', () => {
48+
beforeEach(() => {
49+
renderComponent();
50+
51+
store.dispatch({
52+
type: ActionTypes.SuggestedIndexesRequested,
53+
});
54+
});
55+
it('renders a loader for the code section', () => {
56+
const loader = screen.getByTestId('query-flow-section-code-loader');
57+
expect(loader).to.be.visible;
58+
});
2759
});
2860

29-
it('renders the suggested index section with formatted index code', () => {
30-
renderComponent();
31-
const codeElement = screen.getByTestId(
32-
'query-flow-section-suggested-index'
33-
);
34-
expect(codeElement).to.be.visible;
61+
describe('when index suggestions is fetched', () => {
62+
beforeEach(() => {
63+
renderComponent();
64+
65+
store.dispatch({
66+
type: ActionTypes.SuggestedIndexesFetched,
67+
sampleDocs: [],
68+
indexSuggestions: { a: 1, b: 2 },
69+
fetchingSuggestionsError: null,
70+
indexSuggestionsState: 'success',
71+
});
72+
});
73+
74+
it('renders the suggested index section with formatted index code', () => {
75+
const codeElement = screen.getByTestId(
76+
'query-flow-section-suggested-index'
77+
);
78+
expect(codeElement).to.be.visible;
79+
expect(codeElement).to.have.text(
80+
`db.getSiblingDB("${dbName}").getCollection("${collectionName}").createIndex({ "a": 1, "b": "2"});`
81+
);
82+
});
3583
});
3684
});

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

Lines changed: 80 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,24 @@ import {
44
Body,
55
cx,
66
useFocusRing,
7+
ParagraphSkeleton,
78
} from '@mongodb-js/compass-components';
8-
import React, { useMemo } from 'react';
9+
import React, { useMemo, useCallback } from 'react';
910
import { css, spacing } from '@mongodb-js/compass-components';
1011
import {
1112
CodemirrorMultilineEditor,
1213
createQueryAutocompleter,
1314
} from '@mongodb-js/compass-editor';
1415
import MDBCodeViewer from './mdb-code-viewer';
16+
import type { RootState } from '../../modules';
17+
import { fetchIndexSuggestions } from '../../modules/create-index';
18+
import type {
19+
IndexSuggestionState,
20+
SuggestedIndexFetchedProps,
21+
} from '../../modules/create-index';
22+
import { connect } from 'react-redux';
1523

1624
const inputQueryContainerStyles = css({
17-
marginBottom: spacing[600],
1825
display: 'flex',
1926
flexDirection: 'column',
2027
});
@@ -60,16 +67,34 @@ const codeEditorStyles = css({
6067
},
6168
});
6269

70+
const indexSuggestionsLoaderStyles = css({
71+
marginBottom: spacing[600],
72+
padding: spacing[600],
73+
background: palette.gray.light3,
74+
border: `1px solid ${palette.gray.light2}`,
75+
borderRadius: editorContainerRadius,
76+
});
77+
6378
const QueryFlowSection = ({
6479
schemaFields,
6580
serverVersion,
6681
dbName,
6782
collectionName,
83+
onSuggestedIndexButtonClick,
84+
indexSuggestions,
85+
fetchingSuggestionsState,
6886
}: {
6987
schemaFields: { name: string; description?: string }[];
7088
serverVersion: string;
7189
dbName: string;
7290
collectionName: string;
91+
onSuggestedIndexButtonClick: ({
92+
dbName,
93+
collectionName,
94+
inputQuery,
95+
}: SuggestedIndexFetchedProps) => Promise<void>;
96+
indexSuggestions: Record<string, number> | null;
97+
fetchingSuggestionsState: IndexSuggestionState;
7398
}) => {
7499
const [inputQuery, setInputQuery] = React.useState('');
75100
const completer = useMemo(
@@ -88,6 +113,18 @@ const QueryFlowSection = ({
88113
radius: editorContainerRadius,
89114
});
90115

116+
const handleSuggestedIndexButtonClick = useCallback(() => {
117+
const sanitizedInputQuery = inputQuery.trim();
118+
119+
void onSuggestedIndexButtonClick({
120+
dbName,
121+
collectionName,
122+
inputQuery: sanitizedInputQuery,
123+
});
124+
}, [inputQuery, dbName, collectionName, onSuggestedIndexButtonClick]);
125+
126+
const isFetchingIndexSuggestions = fetchingSuggestionsState === 'fetching';
127+
91128
return (
92129
<>
93130
<Body baseFontSize={16} weight="medium" className={headerStyles}>
@@ -116,30 +153,56 @@ const QueryFlowSection = ({
116153

117154
<div className={editorActionContainerStyles}>
118155
<Button
119-
onClick={() => {
120-
// TODO in CLOUDP-311786
121-
}}
156+
onClick={handleSuggestedIndexButtonClick}
122157
className={suggestedIndexButtonStyles}
123158
size="small"
124159
>
125160
Show suggested index
126161
</Button>
127162
</div>
128163
</div>
129-
<Body baseFontSize={16} weight="medium" className={headerStyles}>
130-
Suggested Index
131-
</Body>{' '}
132-
<div className={suggestedIndexContainerStyles}>
133-
{/* TODO in CLOUDP-311786, replace hardcoded values with actual data */}
134-
<MDBCodeViewer
135-
dataTestId="query-flow-section-suggested-index"
136-
dbName={dbName}
137-
collectionName={collectionName}
138-
indexNameTypeMap={{ 'awards.win': '1', 'imdb.rating': '1' }}
164+
165+
{(isFetchingIndexSuggestions || indexSuggestions) && (
166+
<Body baseFontSize={16} weight="medium" className={headerStyles}>
167+
Suggested Index
168+
</Body>
169+
)}
170+
171+
{isFetchingIndexSuggestions ? (
172+
<ParagraphSkeleton
173+
data-testid="query-flow-section-code-loader"
174+
className={indexSuggestionsLoaderStyles}
139175
/>
140-
</div>
176+
) : (
177+
indexSuggestions && (
178+
<>
179+
<div className={suggestedIndexContainerStyles}>
180+
<MDBCodeViewer
181+
dataTestId="query-flow-section-suggested-index"
182+
dbName={dbName}
183+
collectionName={collectionName}
184+
indexNameTypeMap={indexSuggestions}
185+
/>
186+
</div>
187+
</>
188+
)
189+
)}
141190
</>
142191
);
143192
};
144193

145-
export default QueryFlowSection;
194+
const mapState = ({ createIndex }: RootState) => {
195+
const { indexSuggestions, sampleDocs, fetchingSuggestionsState } =
196+
createIndex;
197+
return {
198+
indexSuggestions,
199+
sampleDocs,
200+
fetchingSuggestionsState,
201+
};
202+
};
203+
204+
const mapDispatch = {
205+
onSuggestedIndexButtonClick: fetchIndexSuggestions,
206+
};
207+
208+
export default connect(mapState, mapDispatch)(QueryFlowSection);

0 commit comments

Comments
 (0)