Skip to content

Commit 762fb43

Browse files
jcobiskylelai1
andauthored
feat(compass-collection): Mock Data Generator QA Items Batch 1 - CLOUDP-356788 (#7541)
* Defaults for unrecognized (eg. _id) * Persist selections * Null instead of empty function * Remove code for unrecognized * Remove unrecognized icon * Handle restoring original LLM mapping in reducer --------- Co-authored-by: Kyle W Lai <[email protected]>
1 parent daab7eb commit 762fb43

File tree

7 files changed

+261
-221
lines changed

7 files changed

+261
-221
lines changed

packages/compass-collection/src/components/mock-data-generator-modal/faker-mapping-selector.spec.tsx

Lines changed: 31 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ import {
99
} from '@mongodb-js/testing-library-compass';
1010
import sinon from 'sinon';
1111
import FakerMappingSelector from './faker-mapping-selector';
12-
import { UNRECOGNIZED_FAKER_METHOD } from '../../modules/collection-tab';
1312
import type { MongoDBFieldType } from '../../schema-analysis-types';
1413
import {
1514
MONGO_TYPE_TO_FAKER_METHODS,
@@ -122,39 +121,52 @@ describe('FakerMappingSelector', () => {
122121
);
123122
});
124123

125-
it('should show warning banner when faker method is unrecognized', () => {
124+
it('should always include the original LLM faker method in the dropdown', () => {
125+
const originalLlmMethod = 'custom.llmMethod';
126+
126127
render(
127128
<FakerMappingSelector
128-
activeJsonType={mockActiveJsonType}
129-
activeFakerFunction={UNRECOGNIZED_FAKER_METHOD}
130-
activeFakerArgs={mockActiveFakerArgs}
129+
activeJsonType="String"
130+
activeFakerFunction="lorem.word"
131+
activeFakerArgs={[]}
131132
onJsonTypeSelect={onJsonTypeSelectStub}
132133
onFakerFunctionSelect={onFakerFunctionSelectStub}
134+
originalLlmFakerMethod={originalLlmMethod}
133135
/>
134136
);
135137

136-
expect(
137-
screen.getByText(
138-
/Please select a function or we will default fill this field/
139-
)
140-
).to.exist;
138+
const fakerFunctionSelect = screen.getByLabelText('Faker Function');
139+
userEvent.click(fakerFunctionSelect);
140+
141+
// Should include the original LLM method even though it's not in MONGO_TYPE_TO_FAKER_METHODS
142+
expect(screen.getByRole('option', { name: originalLlmMethod })).to.exist;
143+
144+
// Should also include standard methods for String type
145+
expect(screen.getByRole('option', { name: 'lorem.word' })).to.exist;
146+
expect(screen.getByRole('option', { name: 'lorem.sentence' })).to.exist;
141147
});
142148

143-
it('should not show warning banner when faker method is recognized', () => {
149+
it('should not duplicate the original LLM method if it is already in the standard methods', () => {
150+
const originalLlmMethod = 'lorem.word';
151+
144152
render(
145153
<FakerMappingSelector
146-
activeJsonType={mockActiveJsonType}
147-
activeFakerFunction={mockActiveFakerFunction}
148-
activeFakerArgs={mockActiveFakerArgs}
154+
activeJsonType="String"
155+
activeFakerFunction="lorem.sentence"
156+
activeFakerArgs={[]}
149157
onJsonTypeSelect={onJsonTypeSelectStub}
150158
onFakerFunctionSelect={onFakerFunctionSelectStub}
159+
originalLlmFakerMethod={originalLlmMethod}
151160
/>
152161
);
153162

154-
expect(
155-
screen.queryByText(
156-
/Please select a function or we will default fill this field/
157-
)
158-
).to.not.exist;
163+
const fakerFunctionSelect = screen.getByLabelText('Faker Function');
164+
userEvent.click(fakerFunctionSelect);
165+
166+
// Should only have one instance of 'lorem.word'
167+
const loremWordOptions = screen.getAllByRole('option', {
168+
name: 'lorem.word',
169+
});
170+
expect(loremWordOptions).to.have.length(1);
159171
});
160172
});

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

Lines changed: 18 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
11
import {
2-
Banner,
3-
BannerVariant,
42
Body,
53
Code,
64
css,
@@ -10,7 +8,6 @@ import {
108
spacing,
119
} from '@mongodb-js/compass-components';
1210
import React, { useMemo } from 'react';
13-
import { UNRECOGNIZED_FAKER_METHOD } from '../../modules/collection-tab';
1411
import {
1512
MONGO_TYPE_TO_FAKER_METHODS,
1613
MongoDBFieldTypeValues,
@@ -65,6 +62,7 @@ interface Props {
6562
onJsonTypeSelect: (jsonType: MongoDBFieldType) => void;
6663
activeFakerArgs: FakerArg[];
6764
onFakerFunctionSelect: (fakerFunction: string) => void;
65+
originalLlmFakerMethod?: string;
6866
}
6967

7068
const FakerMappingSelector = ({
@@ -73,16 +71,18 @@ const FakerMappingSelector = ({
7371
activeFakerArgs,
7472
onJsonTypeSelect,
7573
onFakerFunctionSelect,
74+
originalLlmFakerMethod,
7675
}: Props) => {
7776
const fakerMethodOptions = useMemo(() => {
7877
const methods = MONGO_TYPE_TO_FAKER_METHODS[activeJsonType] || [];
7978

80-
if (methods.includes(activeFakerFunction)) {
81-
return methods;
79+
// Include original LLM method if it's not already in the list of methods
80+
if (originalLlmFakerMethod && !methods.includes(originalLlmFakerMethod)) {
81+
return [originalLlmFakerMethod, ...methods];
8282
}
8383

84-
return [activeFakerFunction, ...methods];
85-
}, [activeJsonType, activeFakerFunction]);
84+
return methods;
85+
}, [activeJsonType, originalLlmFakerMethod]);
8686

8787
return (
8888
<div className={fieldMappingSelectorsStyles}>
@@ -111,29 +111,17 @@ const FakerMappingSelector = ({
111111
</Option>
112112
))}
113113
</Select>
114-
{activeFakerFunction === UNRECOGNIZED_FAKER_METHOD ? (
115-
<Banner variant={BannerVariant.Warning}>
116-
Please select a function or we will default fill this field with the
117-
string &quot;Unrecognized&quot;
118-
</Banner>
119-
) : (
120-
<>
121-
<Label htmlFor="faker-function-call-preview">
122-
Preview Faker Function Call
123-
</Label>
124-
<Code
125-
id="faker-function-call-preview"
126-
data-testid="faker-function-call-preview"
127-
language="javascript"
128-
copyButtonAppearance="none"
129-
>
130-
{formatFakerFunctionCallWithArgs(
131-
activeFakerFunction,
132-
activeFakerArgs
133-
)}
134-
</Code>
135-
</>
136-
)}
114+
<Label htmlFor="faker-function-call-preview">
115+
Preview Faker Function Call
116+
</Label>
117+
<Code
118+
id="faker-function-call-preview"
119+
data-testid="faker-function-call-preview"
120+
language="javascript"
121+
copyButtonAppearance="none"
122+
>
123+
{formatFakerFunctionCallWithArgs(activeFakerFunction, activeFakerArgs)}
124+
</Code>
137125
</div>
138126
);
139127
};

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

Lines changed: 46 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,17 @@ import {
88
} from '@mongodb-js/compass-components';
99
import React from 'react';
1010
import { connect } from 'react-redux';
11+
import type { Dispatch } from 'redux';
1112
import FieldSelector from './schema-field-selector';
1213
import FakerMappingSelector from './faker-mapping-selector';
1314
import { getDefaultFakerMethod } from './script-generation-utils';
14-
import type {
15-
FakerSchema,
16-
FakerFieldMapping,
17-
MockDataGeneratorState,
18-
} from './types';
15+
import type { FakerSchema, MockDataGeneratorState } from './types';
1916
import type { MongoDBFieldType } from '../../schema-analysis-types';
2017
import { useTelemetry } from '@mongodb-js/compass-telemetry/provider';
18+
import {
19+
fakerFieldTypeChanged,
20+
fakerFieldMethodChanged,
21+
} from '../../modules/collection-tab';
2122

2223
const containerStyles = css({
2324
display: 'flex',
@@ -46,53 +47,39 @@ const schemaEditorLoaderStyles = css({
4647

4748
const FakerSchemaEditorContent = ({
4849
fakerSchema,
50+
originalLlmResponse,
51+
onFieldTypeChanged,
52+
onFieldMethodChanged,
4953
}: {
5054
fakerSchema: FakerSchema;
55+
originalLlmResponse: FakerSchema;
56+
onFieldTypeChanged: (fieldPath: string, mongoType: MongoDBFieldType) => void;
57+
onFieldMethodChanged: (fieldPath: string, fakerMethod: string) => void;
5158
}) => {
5259
const track = useTelemetry();
53-
const [fakerSchemaFormValues, setFakerSchemaFormValues] =
54-
React.useState<FakerSchema>(fakerSchema);
55-
56-
// Store original LLM mappings to restore when reselecting original methods
57-
const originalLlmMappings = React.useRef<Record<string, FakerFieldMapping>>(
58-
Object.fromEntries(
59-
Object.entries(fakerSchema).map(([field, mapping]) => [
60-
field,
61-
{
62-
...mapping,
63-
},
64-
])
65-
)
66-
);
6760

68-
const fieldPaths = Object.keys(fakerSchemaFormValues);
61+
const fieldPaths = Object.keys(fakerSchema);
6962
const [activeField, setActiveField] = React.useState<string>(fieldPaths[0]);
7063

71-
const activeJsonType = fakerSchemaFormValues[activeField]?.mongoType;
72-
const activeFakerFunction = fakerSchemaFormValues[activeField]?.fakerMethod;
73-
const activeFakerArgs = fakerSchemaFormValues[activeField]?.fakerArgs;
64+
const activeJsonType = fakerSchema[activeField]?.mongoType;
65+
const activeFakerFunction = fakerSchema[activeField]?.fakerMethod;
66+
const activeFakerArgs = fakerSchema[activeField]?.fakerArgs;
7467

7568
const onJsonTypeSelect = (newJsonType: MongoDBFieldType) => {
76-
const currentMapping = fakerSchemaFormValues[activeField];
77-
const originalLlmMapping = originalLlmMappings.current[activeField];
69+
const currentMapping = fakerSchema[activeField];
70+
const originalLlmMapping = originalLlmResponse[activeField];
7871

7972
if (currentMapping) {
8073
const previousJsonType = currentMapping.mongoType;
8174
const previousFakerMethod = currentMapping.fakerMethod;
8275

83-
const isSwitchingToOriginalType =
84-
originalLlmMapping && newJsonType === originalLlmMapping.mongoType;
85-
86-
const newMapping = isSwitchingToOriginalType
87-
? { ...originalLlmMapping }
88-
: {
89-
...currentMapping,
90-
mongoType: newJsonType,
91-
fakerMethod: getDefaultFakerMethod(newJsonType),
92-
fakerArgs: [],
93-
};
76+
const newFakerMethod =
77+
originalLlmMapping && newJsonType === originalLlmMapping.mongoType
78+
? originalLlmMapping.fakerMethod
79+
: getDefaultFakerMethod(newJsonType);
9480

95-
const newFakerMethod = newMapping.fakerMethod;
81+
onFieldTypeChanged(activeField, newJsonType);
82+
onFieldMethodChanged(activeField, newFakerMethod);
9683

9784
track('Mock Data JSON Type Changed', {
9885
field_name: activeField,
@@ -101,45 +88,23 @@ const FakerSchemaEditorContent = ({
10188
previous_faker_method: previousFakerMethod,
10289
new_faker_method: newFakerMethod,
10390
});
104-
105-
setFakerSchemaFormValues({
106-
...fakerSchemaFormValues,
107-
[activeField]: newMapping,
108-
});
10991
}
11092
};
11193

11294
const onFakerFunctionSelect = (newFakerFunction: string) => {
113-
const currentMapping = fakerSchemaFormValues[activeField];
114-
const originalLlmMapping = originalLlmMappings.current[activeField];
95+
const currentMapping = fakerSchema[activeField];
11596

11697
if (currentMapping) {
11798
const previousFakerMethod = currentMapping.fakerMethod;
11899

119-
const isSwitchingToLlmSuggestion =
120-
originalLlmMapping &&
121-
currentMapping.mongoType === originalLlmMapping.mongoType &&
122-
newFakerFunction === originalLlmMapping.fakerMethod;
123-
124-
const newMapping = isSwitchingToLlmSuggestion
125-
? { ...originalLlmMapping }
126-
: {
127-
...currentMapping,
128-
fakerMethod: newFakerFunction,
129-
fakerArgs: [],
130-
};
100+
onFieldMethodChanged(activeField, newFakerFunction);
131101

132102
track('Mock Data Faker Method Changed', {
133103
field_name: activeField,
134104
json_type: currentMapping.mongoType,
135105
previous_faker_method: previousFakerMethod,
136106
new_faker_method: newFakerFunction,
137107
});
138-
139-
setFakerSchemaFormValues({
140-
...fakerSchemaFormValues,
141-
[activeField]: newMapping,
142-
});
143108
}
144109
};
145110

@@ -150,7 +115,6 @@ const FakerSchemaEditorContent = ({
150115
activeField={activeField}
151116
fields={fieldPaths}
152117
onFieldSelect={setActiveField}
153-
fakerSchema={fakerSchemaFormValues}
154118
/>
155119
{activeJsonType && activeFakerFunction && (
156120
<FakerMappingSelector
@@ -159,6 +123,11 @@ const FakerSchemaEditorContent = ({
159123
activeFakerArgs={activeFakerArgs}
160124
onJsonTypeSelect={onJsonTypeSelect}
161125
onFakerFunctionSelect={onFakerFunctionSelect}
126+
originalLlmFakerMethod={
127+
originalLlmResponse[activeField]?.mongoType === activeJsonType
128+
? originalLlmResponse[activeField]?.fakerMethod
129+
: undefined
130+
}
162131
/>
163132
)}
164133
</div>
@@ -168,8 +137,12 @@ const FakerSchemaEditorContent = ({
168137

169138
const FakerSchemaEditorScreen = ({
170139
fakerSchemaGenerationState,
140+
onFieldTypeChanged,
141+
onFieldMethodChanged,
171142
}: {
172143
fakerSchemaGenerationState: MockDataGeneratorState;
144+
onFieldTypeChanged: (fieldPath: string, mongoType: MongoDBFieldType) => void;
145+
onFieldMethodChanged: (fieldPath: string, fakerMethod: string) => void;
173146
}) => {
174147
return (
175148
<div data-testid="faker-schema-editor" className={containerStyles}>
@@ -197,10 +170,20 @@ const FakerSchemaEditorScreen = ({
197170
{fakerSchemaGenerationState.status === 'completed' && (
198171
<FakerSchemaEditorContent
199172
fakerSchema={fakerSchemaGenerationState.editedFakerSchema}
173+
originalLlmResponse={fakerSchemaGenerationState.originalLlmResponse}
174+
onFieldTypeChanged={onFieldTypeChanged}
175+
onFieldMethodChanged={onFieldMethodChanged}
200176
/>
201177
)}
202178
</div>
203179
);
204180
};
205181

206-
export default connect()(FakerSchemaEditorScreen);
182+
const mapDispatchToProps = (dispatch: Dispatch) => ({
183+
onFieldTypeChanged: (fieldPath: string, mongoType: MongoDBFieldType) =>
184+
dispatch(fakerFieldTypeChanged(fieldPath, mongoType)),
185+
onFieldMethodChanged: (fieldPath: string, fakerMethod: string) =>
186+
dispatch(fakerFieldMethodChanged(fieldPath, fakerMethod)),
187+
});
188+
189+
export default connect(null, mapDispatchToProps)(FakerSchemaEditorScreen);

0 commit comments

Comments
 (0)