Skip to content
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
266 changes: 167 additions & 99 deletions package-lock.json

Large diffs are not rendered by default.

4 changes: 4 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -103,5 +103,9 @@
"chai-enzyme": {
"cheerio": "1.0.0-rc.10"
}
},
"dependencies": {
"@leafygreen-ui/skeleton-loader": "^2.0.11",
"mongodb-mql-engines": "^0.0.4"
}
}
1 change: 1 addition & 0 deletions packages/compass-components/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -211,3 +211,4 @@ export {
type ItemRenderer as VirtualListItemRenderer,
} from './components/virtual-list';
export { SelectTable } from './components/select-table';
export { ParagraphSkeleton } from '@leafygreen-ui/skeleton-loader';
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,15 @@ const generateCode = ({
}: {
dbName: string;
collectionName: string;
indexNameTypeMap: { [key: string]: string };
indexNameTypeMap: Record<string, string | number>;
}) => {
let codeStr = `db.getSiblingDB("${dbName}").getCollection("${escapeText(
collectionName
)}").createIndex({\n`;

Object.entries(indexNameTypeMap).forEach(([name, type], index) => {
// Replacing everything inside the parenthesis i.e. (asc)
let parsedType = escapeText(type.replace(/\(.*?\)/g, '')).trim();
let parsedType = escapeText(`${type}`.replace(/\(.*?\)/g, '')).trim();
if (!NUMERIC_INDEX_TYPES.includes(Number(parsedType))) {
parsedType = `"${parsedType}"`;
}
Expand All @@ -59,7 +59,7 @@ const MDBCodeViewer = ({
}: {
dbName: string;
collectionName: string;
indexNameTypeMap: { [key: string]: string };
indexNameTypeMap: Record<string, string | number>;
dataTestId?: string;
}) => {
const GeneratedCode = generateCode({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,35 +2,85 @@ import React from 'react';
import { render, screen } from '@mongodb-js/testing-library-compass';
import QueryFlowSection from './query-flow-section';
import { expect } from 'chai';
import { Provider } from 'react-redux';
import { setupStore } from '../../../test/setup-store';
import { ActionTypes } from '../../modules/create-index';

describe('QueryFlowSection', () => {
let store;
const dbName = 'fakeDBName';
const collectionName = 'fakeCollectionName';
const renderComponent = () => {
const store = setupStore();

render(
<QueryFlowSection
schemaFields={[]}
serverVersion="5.0.0"
dbName={'fakeDBName'}
collectionName={'fakeCollectionName'}
/>
<Provider store={store}>
<QueryFlowSection
schemaFields={[]}
serverVersion="5.0.0"
dbName={dbName}
collectionName={collectionName}
/>
</Provider>
);
};
it('renders the input query section with a code editor', () => {
renderComponent();
const codeEditor = screen.getByTestId('query-flow-section-code-editor');
expect(codeEditor).to.be.visible;

describe('in the initial state', () => {
beforeEach(() => {
renderComponent();
});
it('renders the input query section with a code editor', () => {
const codeEditor = screen.getByTestId('query-flow-section-code-editor');
expect(codeEditor).to.be.visible;
});

it('renders the "Show suggested index" button', () => {
const buttonElement = screen.getByText('Show suggested index');
expect(buttonElement).to.be.visible;
});
it('does not render the suggested index section with formatted index code', () => {
const codeElement = screen.queryByTestId(
'query-flow-section-suggested-index'
);
expect(codeElement).to.be.null;
});
});

it('renders the "Show suggested index" button', () => {
renderComponent();
const buttonElement = screen.getByText('Show suggested index');
expect(buttonElement).to.be.visible;
describe('when fetching for index suggestions', () => {
beforeEach(() => {
renderComponent();

store.dispatch({
type: ActionTypes.SuggestedIndexesRequested,
});
});
it('renders a loader for the code section', () => {
const loader = screen.getByTestId('query-flow-section-code-loader');
expect(loader).to.be.visible;
});
});

it('renders the suggested index section with formatted index code', () => {
renderComponent();
const codeElement = screen.getByTestId(
'query-flow-section-suggested-index'
);
expect(codeElement).to.be.visible;
describe('when index suggestions is fetched', () => {
beforeEach(async () => {
renderComponent();

await store.dispatch({
type: ActionTypes.SuggestedIndexesFetched,
sampleDocs: [],
indexSuggestions: { a: 1, b: 2 },
fetchingSuggestionsError: null,
indexSuggestionsState: 'success',
});
});

it('renders the suggested index section with formatted index code', () => {
const codeElement = screen.getByTestId(
'query-flow-section-suggested-index'
);
expect(codeElement).to.be.visible;
expect(codeElement).to.have.text(
`db.getSiblingDB("${dbName}").getCollection("${collectionName}").createIndex({ "a": 1, "b": "2"});`
);
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,24 @@ import {
Body,
cx,
useFocusRing,
ParagraphSkeleton,
} from '@mongodb-js/compass-components';
import React, { useMemo } from 'react';
import React, { useMemo, useCallback } from 'react';
import { css, spacing } from '@mongodb-js/compass-components';
import {
CodemirrorMultilineEditor,
createQueryAutocompleter,
} from '@mongodb-js/compass-editor';
import MDBCodeViewer from './mdb-code-viewer';
import type { RootState } from '../../modules';
import { fetchIndexSuggestions } from '../../modules/create-index';
import type {
IndexSuggestionState,
SuggestedIndexFetchedProps,
} from '../../modules/create-index';
import { connect } from 'react-redux';

const inputQueryContainerStyles = css({
marginBottom: spacing[600],
display: 'flex',
flexDirection: 'column',
});
Expand Down Expand Up @@ -60,16 +67,34 @@ const codeEditorStyles = css({
},
});

const indexSuggestionsLoaderStyles = css({
marginBottom: spacing[600],
padding: spacing[600],
background: palette.gray.light3,
border: `1px solid ${palette.gray.light2}`,
borderRadius: editorContainerRadius,
});

const QueryFlowSection = ({
schemaFields,
serverVersion,
dbName,
collectionName,
onSuggestedIndexButtonClick,
indexSuggestions,
fetchingSuggestionsState,
}: {
schemaFields: { name: string; description?: string }[];
serverVersion: string;
dbName: string;
collectionName: string;
onSuggestedIndexButtonClick: ({
dbName,
collectionName,
inputQuery,
}: SuggestedIndexFetchedProps) => Promise<void>;
indexSuggestions: Record<string, number> | null;
fetchingSuggestionsState: IndexSuggestionState;
}) => {
const [inputQuery, setInputQuery] = React.useState('');
const completer = useMemo(
Expand All @@ -88,6 +113,18 @@ const QueryFlowSection = ({
radius: editorContainerRadius,
});

const handleSuggestedIndexButtonClick = useCallback(async () => {
const sanitizedInputQuery = inputQuery.trim();

await onSuggestedIndexButtonClick({
dbName,
collectionName,
inputQuery: sanitizedInputQuery,
});
}, [inputQuery, dbName, collectionName, onSuggestedIndexButtonClick]);

const isFetchingIndexSuggestions = fetchingSuggestionsState === 'fetching';

return (
<>
<Body baseFontSize={16} weight="medium" className={headerStyles}>
Expand Down Expand Up @@ -117,7 +154,7 @@ const QueryFlowSection = ({
<div className={editorActionContainerStyles}>
<Button
onClick={() => {
// TODO in CLOUDP-311786
void handleSuggestedIndexButtonClick();
}}
className={suggestedIndexButtonStyles}
size="small"
Expand All @@ -126,20 +163,48 @@ const QueryFlowSection = ({
</Button>
</div>
</div>
<Body baseFontSize={16} weight="medium" className={headerStyles}>
Suggested Index
</Body>{' '}
<div className={suggestedIndexContainerStyles}>
{/* TODO in CLOUDP-311786, replace hardcoded values with actual data */}
<MDBCodeViewer
dataTestId="query-flow-section-suggested-index"
dbName={dbName}
collectionName={collectionName}
indexNameTypeMap={{ 'awards.win': '1', 'imdb.rating': '1' }}

{(isFetchingIndexSuggestions || indexSuggestions) && (
<Body baseFontSize={16} weight="medium" className={headerStyles}>
Suggested Index
</Body>
)}

{isFetchingIndexSuggestions ? (
<ParagraphSkeleton
data-testid="query-flow-section-code-loader"
className={indexSuggestionsLoaderStyles}
/>
</div>
) : (
indexSuggestions && (
<>
<div className={suggestedIndexContainerStyles}>
<MDBCodeViewer
dataTestId="query-flow-section-suggested-index"
dbName={dbName}
collectionName={collectionName}
indexNameTypeMap={indexSuggestions}
/>
</div>
</>
)
)}
</>
);
};

export default QueryFlowSection;
const mapState = ({ createIndex }: RootState) => {
const { indexSuggestions, sampleDocs, fetchingSuggestionsState } =
createIndex;
return {
indexSuggestions,
sampleDocs,
fetchingSuggestionsState,
};
};

const mapDispatch = {
onSuggestedIndexButtonClick: fetchIndexSuggestions,
};

export default connect(mapState, mapDispatch)(QueryFlowSection);
Loading
Loading