Skip to content

Commit 6aad6f0

Browse files
committed
1 parent 42660a7 commit 6aad6f0

File tree

11 files changed

+634
-7
lines changed

11 files changed

+634
-7
lines changed

package-lock.json

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

packages/compass-collection/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@
4848
"reformat": "npm run eslint . -- --fix && npm run prettier -- --write ."
4949
},
5050
"dependencies": {
51+
"@faker-js/faker": "^10.0.0",
5152
"@mongodb-js/compass-app-registry": "^9.4.21",
5253
"@mongodb-js/compass-app-stores": "^7.58.1",
5354
"@mongodb-js/compass-components": "^1.50.1",

packages/compass-collection/src/components/mock-data-generator-modal/faker-schema-editor.tsx

Lines changed: 114 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,120 @@
1+
import {
2+
Body,
3+
Button,
4+
ButtonVariant,
5+
css,
6+
H3,
7+
Link,
8+
spacing,
9+
VerticalRule,
10+
} from '@mongodb-js/compass-components';
111
import React from 'react';
12+
import FieldSelector from './schema-field-selector';
13+
import FakerMappingSelector from './field-mapping-selectors';
14+
import { FakerMapping } from './types';
15+
16+
const containerStyles = css({
17+
display: 'flex',
18+
flexDirection: 'column',
19+
gap: spacing[400],
20+
});
21+
22+
const innerEditorStyles = css({
23+
display: 'flex',
24+
flexDirection: 'row',
25+
justifyContent: 'space-between',
26+
maxHeight: '500px',
27+
overflow: 'auto',
28+
});
29+
30+
const confirmMappingsButtonStyles = css({
31+
width: '200px',
32+
});
33+
34+
const FakerSchemaEditor = ({
35+
fakerSchema,
36+
}: {
37+
fakerSchema: Array<FakerMapping>;
38+
}) => {
39+
const [fakerSchemaFormValues, setFakerSchemaFormValues] =
40+
React.useState<Array<FakerMapping>>(fakerSchema);
41+
const [activeField, setActiveField] = React.useState<string>(
42+
fakerSchemaFormValues[0].fieldPath
43+
);
44+
45+
const activeJsonType = fakerSchemaFormValues.find(
46+
(mapping) => mapping.fieldPath === activeField
47+
)?.mongoType;
48+
const activeFakerFunction = fakerSchemaFormValues.find(
49+
(mapping) => mapping.fieldPath === activeField
50+
)?.fakerMethod;
51+
52+
const onJsonTypeSelect = (newJsonType: string) => {
53+
const updatedFakerFieldMapping = fakerSchemaFormValues.find(
54+
(mapping) => mapping.fieldPath === activeField
55+
);
56+
if (updatedFakerFieldMapping) {
57+
updatedFakerFieldMapping.mongoType = newJsonType;
58+
setFakerSchemaFormValues(
59+
fakerSchemaFormValues.map((mapping) =>
60+
mapping.fieldPath === activeField ? updatedFakerFieldMapping : mapping
61+
)
62+
);
63+
}
64+
};
65+
66+
const onFakerFunctionSelect = (newFakerFunction: string) => {
67+
const updatedFakerFieldMapping = fakerSchemaFormValues.find(
68+
(mapping) => mapping.fieldPath === activeField
69+
);
70+
if (updatedFakerFieldMapping) {
71+
updatedFakerFieldMapping.fakerMethod = newFakerFunction;
72+
setFakerSchemaFormValues(
73+
fakerSchemaFormValues.map((mapping) =>
74+
mapping.fieldPath === activeField ? updatedFakerFieldMapping : mapping
75+
)
76+
);
77+
}
78+
};
79+
80+
const onConfirmMappings = () => {
81+
console.log('Clicked confirm mappings');
82+
};
283

3-
// TODO: More to come from CLOUDP-333853, CLOUDP-333854
4-
const FakerSchemaEditor = () => {
584
return (
6-
<div data-testid="faker-schema-editor">
7-
Schema Editor Content Placeholder
85+
<div data-testid="faker-schema-editor" className={containerStyles}>
86+
<div>
87+
<H3>Confirm Field to Faker Function Mappings</H3>
88+
<Body>
89+
We have sampled your collection and created a schema based on your
90+
documents. That schema has been sent to an LLM and it has returned the
91+
following mapping between your schema fields and{' '}
92+
<Link href="TODO">faker functions</Link>.
93+
</Body>
94+
</div>
95+
<div className={innerEditorStyles}>
96+
<FieldSelector
97+
activeField={activeField}
98+
fields={fakerSchemaFormValues.map((mapping) => mapping.fieldPath)}
99+
onFieldSelect={setActiveField}
100+
/>
101+
<VerticalRule />
102+
{activeJsonType && activeFakerFunction && (
103+
<FakerMappingSelector
104+
activeJsonType={activeJsonType}
105+
activeFakerFunction={activeFakerFunction}
106+
onJsonTypeSelect={onJsonTypeSelect}
107+
onFakerFunctionSelect={onFakerFunctionSelect}
108+
/>
109+
)}
110+
</div>
111+
<Button
112+
className={confirmMappingsButtonStyles}
113+
variant={ButtonVariant.Primary}
114+
onClick={onConfirmMappings}
115+
>
116+
Confirm mappings
117+
</Button>
8118
</div>
9119
);
10120
};
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
import {
2+
Body,
3+
css,
4+
Option,
5+
Select,
6+
spacing,
7+
} from '@mongodb-js/compass-components';
8+
import React from 'react';
9+
10+
const fieldMappingSelectorsStyles = css({
11+
width: '50%',
12+
display: 'flex',
13+
flexDirection: 'column',
14+
gap: spacing[100],
15+
});
16+
17+
interface Props {
18+
activeJsonType: string;
19+
activeFakerFunction: string;
20+
onJsonTypeSelect: (jsonType: string) => void;
21+
onFakerFunctionSelect: (fakerFunction: string) => void;
22+
}
23+
24+
const FakerMappingSelector = ({
25+
activeJsonType,
26+
activeFakerFunction,
27+
onJsonTypeSelect,
28+
onFakerFunctionSelect,
29+
}: Props) => {
30+
return (
31+
<div
32+
className={fieldMappingSelectorsStyles}
33+
data-testid="field-mapping-selectors"
34+
>
35+
<Body>Mapping</Body>
36+
<Select
37+
data-testid="document-field-type-select"
38+
label="JSON Type"
39+
value={activeJsonType}
40+
onChange={onJsonTypeSelect}
41+
>
42+
{[activeJsonType].map((type) => (
43+
<Option key={type} value={type}>
44+
{type}
45+
</Option>
46+
))}
47+
</Select>
48+
<Select
49+
data-testid="faker-funtion-select"
50+
label="Faker Function"
51+
value={activeFakerFunction}
52+
onChange={onFakerFunctionSelect}
53+
>
54+
{[activeFakerFunction].map((field) => (
55+
<Option key={field} value={field}>
56+
{field}
57+
</Option>
58+
))}
59+
</Select>
60+
</div>
61+
);
62+
};
63+
64+
export default FakerMappingSelector;

packages/compass-collection/src/components/mock-data-generator-modal/mock-data-generator-modal.tsx

Lines changed: 38 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import React from 'react';
1+
import React, { useEffect, useState } from 'react';
22
import { connect } from 'react-redux';
33

44
import {
@@ -10,9 +10,10 @@ import {
1010
Modal,
1111
ModalFooter,
1212
spacing,
13+
SpinLoaderWithLabel,
1314
} from '@mongodb-js/compass-components';
1415

15-
import { MockDataGeneratorStep } from './types';
16+
import { type FakerMapping, MockDataGeneratorStep } from './types';
1617
import { StepButtonLabelMap } from './constants';
1718
import type { CollectionState } from '../../modules/collection-tab';
1819
import {
@@ -23,6 +24,8 @@ import {
2324
} from '../../modules/collection-tab';
2425
import { default as SchemaConfirmationScreen } from './raw-schema-confirmation';
2526
import FakerSchemaEditor from './faker-schema-editor';
27+
import type { MockDataSchemaResponse } from '@mongodb-js/compass-generative-ai';
28+
import { validateFakerSchema } from './validate-faker-schema';
2629

2730
const footerStyles = css`
2831
flex-direction: row;
@@ -35,13 +38,20 @@ const rightButtonsStyles = css`
3538
flex-direction: row;
3639
`;
3740

41+
const schemaEditorLoaderStyles = css({
42+
display: 'flex',
43+
alignItems: 'center',
44+
justifyContent: 'center',
45+
});
46+
3847
interface Props {
3948
isOpen: boolean;
4049
onClose: () => void;
4150
currentStep: MockDataGeneratorStep;
4251
onNextStep: () => void;
4352
onConfirmSchema: () => Promise<void>;
4453
onPreviousStep: () => void;
54+
fakerSchema?: MockDataSchemaResponse;
4555
}
4656

4757
const MockDataGeneratorModal = ({
@@ -51,7 +61,11 @@ const MockDataGeneratorModal = ({
5161
onNextStep,
5262
onConfirmSchema,
5363
onPreviousStep,
64+
fakerSchema,
5465
}: Props) => {
66+
const [validatedFakerSchema, setValidatedFakerSchema] = useState<
67+
Array<FakerMapping> | undefined
68+
>(undefined);
5569
const handleNextClick = () => {
5670
if (currentStep === MockDataGeneratorStep.GENERATE_DATA) {
5771
onClose();
@@ -69,9 +83,26 @@ const MockDataGeneratorModal = ({
6983
}
7084

7185
if (currentStep === MockDataGeneratorStep.SCHEMA_EDITOR) {
72-
stepContent = <FakerSchemaEditor />;
86+
stepContent =
87+
validatedFakerSchema === undefined ? (
88+
<SpinLoaderWithLabel
89+
className={schemaEditorLoaderStyles}
90+
progressText="Processing Documents..."
91+
/>
92+
) : (
93+
<FakerSchemaEditor fakerSchema={validatedFakerSchema} />
94+
);
7395
}
7496

97+
useEffect(() => {
98+
if (fakerSchema) {
99+
void (async () => {
100+
const validatedSchema = await validateFakerSchema(fakerSchema);
101+
setValidatedFakerSchema(validatedSchema);
102+
})();
103+
}
104+
}, [fakerSchema]);
105+
75106
return (
76107
<Modal
77108
open={isOpen}
@@ -112,6 +143,10 @@ const MockDataGeneratorModal = ({
112143
const mapStateToProps = (state: CollectionState) => ({
113144
isOpen: state.mockDataGenerator.isModalOpen,
114145
currentStep: state.mockDataGenerator.currentStep,
146+
fakerSchema:
147+
state.fakerSchemaGeneration.status === 'completed'
148+
? state.fakerSchemaGeneration.fakerSchema
149+
: undefined,
115150
});
116151

117152
const ConnectedMockDataGeneratorModal = connect(mapStateToProps, {

0 commit comments

Comments
 (0)