Skip to content

Commit d57efe3

Browse files
authored
feat(compass-collection): Preview Screen for Mock Data Generator CLOUDP-333857 (#7433)
* WIP * WIP * fix(compass-collection): Fix field name mismatch in Mock Data Generator API - Change 'sample_values' to 'sampleValues' in FieldInfo interface to match backend API expectations - Update all test files to use the new field name - Resolves 400 Bad Request error when generating faker mappings The backend API expects 'sampleValues' (camelCase) but frontend was sending 'sample_values' (snake_case), causing the LLM request to fail with 'Invalid request' error. Fixes CLOUDP-350280 * Revert comment * fix(compass-collection): Fix field name mismatch in Mock Data Generator API - Change 'sample_values' to 'sampleValues' in FieldInfo interface to match backend API expectations - Update all test files to use the new field name - Resolves 400 Bad Request error when generating faker mappings The backend API expects 'sampleValues' (camelCase) but frontend was sending 'sample_values' (snake_case), causing the LLM request to fail with 'Invalid request' error. Fixes CLOUDP-350280 * Revert comment * For of instead of foreach * Remove undefined check * Refactor for readability * EJSON * Refactor * Preview Screen DocumentList instead of EJSON
1 parent 54d7c77 commit d57efe3

File tree

4 files changed

+393
-2
lines changed

4 files changed

+393
-2
lines changed

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

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ import RawSchemaConfirmationScreen from './raw-schema-confirmation-screen';
3131
import FakerSchemaEditorScreen from './faker-schema-editor-screen';
3232
import ScriptScreen from './script-screen';
3333
import DocumentCountScreen from './document-count-screen';
34+
import PreviewScreen from './preview-screen';
3435

3536
const footerStyles = css`
3637
flex-direction: row;
@@ -95,7 +96,15 @@ const MockDataGeneratorModal = ({
9596
/>
9697
);
9798
case MockDataGeneratorStep.PREVIEW_DATA:
98-
return <></>; // TODO: CLOUDP-333857
99+
return (
100+
<PreviewScreen
101+
confirmedFakerSchema={
102+
fakerSchemaGenerationState.status === 'completed'
103+
? fakerSchemaGenerationState.fakerSchema
104+
: {}
105+
}
106+
/>
107+
);
99108
case MockDataGeneratorStep.GENERATE_DATA:
100109
return <ScriptScreen />;
101110
}
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
import React, { useMemo } from 'react';
2+
import {
3+
css,
4+
spacing,
5+
Body,
6+
DocumentList,
7+
} from '@mongodb-js/compass-components';
8+
import HadronDocument from 'hadron-document';
9+
import type { FakerSchema } from './types';
10+
import { generateDocument } from './script-generation-utils';
11+
12+
const descriptionStyles = css({
13+
marginBottom: spacing[200],
14+
});
15+
16+
const documentContainerStyles = css({
17+
display: 'flex',
18+
flexDirection: 'column',
19+
gap: spacing[300],
20+
});
21+
22+
const documentWrapperStyles = css({
23+
border: '1px solid #E8EDEB',
24+
borderRadius: '6px',
25+
padding: spacing[200],
26+
});
27+
28+
interface PreviewScreenProps {
29+
confirmedFakerSchema: FakerSchema;
30+
}
31+
32+
const NUM_SAMPLE_DOCUMENTS = 3;
33+
34+
function PreviewScreen({ confirmedFakerSchema }: PreviewScreenProps) {
35+
const sampleDocuments = useMemo(() => {
36+
const documents = [];
37+
for (let i = 0; i < NUM_SAMPLE_DOCUMENTS; i++) {
38+
const plainDoc = generateDocument(confirmedFakerSchema);
39+
const hadronDoc = new HadronDocument(plainDoc);
40+
hadronDoc.expand(); // Expand by default for better preview
41+
documents.push(hadronDoc);
42+
}
43+
44+
return documents;
45+
}, [confirmedFakerSchema]);
46+
47+
return (
48+
<div data-testid="preview-screen">
49+
<Body as="h2" baseFontSize={16} weight="medium">
50+
Preview Mock Data
51+
</Body>
52+
<Body className={descriptionStyles}>
53+
Below is a sample of documents that will be generated based on your
54+
script
55+
</Body>
56+
<div className={documentContainerStyles}>
57+
{sampleDocuments.map((doc, index) => (
58+
<div key={index} className={documentWrapperStyles}>
59+
<DocumentList.Document value={doc} />
60+
</div>
61+
))}
62+
</div>
63+
</div>
64+
);
65+
}
66+
67+
export default PreviewScreen;

packages/compass-collection/src/components/mock-data-generator-modal/script-generation-utils.spec.ts

Lines changed: 148 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { expect } from 'chai';
22
import { faker } from '@faker-js/faker/locale/en';
3-
import { generateScript } from './script-generation-utils';
3+
import { generateScript, generateDocument } from './script-generation-utils';
44
import type { FakerFieldMapping } from './types';
55

66
/**
@@ -1421,4 +1421,151 @@ describe('Script Generation', () => {
14211421
}
14221422
});
14231423
});
1424+
1425+
describe('generateDocument', () => {
1426+
it('should generate document with simple flat fields', () => {
1427+
const schema = {
1428+
name: {
1429+
mongoType: 'String' as const,
1430+
fakerMethod: 'person.fullName',
1431+
fakerArgs: [],
1432+
probability: 1.0,
1433+
},
1434+
age: {
1435+
mongoType: 'Number' as const,
1436+
fakerMethod: 'number.int',
1437+
fakerArgs: [{ json: '{"min": 18, "max": 65}' }],
1438+
probability: 1.0,
1439+
},
1440+
};
1441+
1442+
const document = generateDocument(schema);
1443+
1444+
expect(document).to.be.an('object');
1445+
expect(document).to.have.property('name');
1446+
expect(document.name).to.be.a('string').and.not.be.empty;
1447+
expect(document).to.have.property('age');
1448+
expect(document.age).to.be.a('number');
1449+
expect(document.age).to.be.at.least(18).and.at.most(65);
1450+
});
1451+
1452+
it('should generate document with arrays', () => {
1453+
const schema = {
1454+
'tags[]': {
1455+
mongoType: 'String' as const,
1456+
fakerMethod: 'lorem.word',
1457+
fakerArgs: [],
1458+
probability: 1.0,
1459+
},
1460+
};
1461+
1462+
const document = generateDocument(schema, { 'tags[]': 2 });
1463+
1464+
expect(document).to.be.an('object');
1465+
expect(document).to.have.property('tags');
1466+
expect(document.tags).to.be.an('array').with.length(2);
1467+
for (const tag of document.tags as string[]) {
1468+
expect(tag).to.be.a('string').and.not.be.empty;
1469+
}
1470+
});
1471+
1472+
it('should generate document with complex nested arrays and custom lengths', () => {
1473+
const schema = {
1474+
'users[].posts[].tags[]': {
1475+
mongoType: 'String' as const,
1476+
fakerMethod: 'lorem.word',
1477+
fakerArgs: [],
1478+
probability: 1.0,
1479+
},
1480+
'matrix[][]': {
1481+
mongoType: 'Number' as const,
1482+
fakerMethod: 'number.int',
1483+
fakerArgs: [{ json: '{"min": 1, "max": 10}' }],
1484+
probability: 1.0,
1485+
},
1486+
};
1487+
1488+
const arrayLengthMap = {
1489+
'users[]': 2,
1490+
'users[].posts[]': 3,
1491+
'users[].posts[].tags[]': 4,
1492+
'matrix[]': 2,
1493+
'matrix[][]': 3,
1494+
};
1495+
1496+
const document = generateDocument(schema, arrayLengthMap);
1497+
1498+
expect(document).to.be.an('object');
1499+
1500+
// Check users array structure
1501+
expect(document).to.have.property('users');
1502+
expect(document.users).to.be.an('array').with.length(2);
1503+
1504+
// Check nested structure with proper types
1505+
const users = document.users as Array<{
1506+
posts: Array<{ tags: string[] }>;
1507+
}>;
1508+
1509+
for (const user of users) {
1510+
expect(user).to.be.an('object');
1511+
expect(user).to.have.property('posts');
1512+
expect(user.posts).to.be.an('array').with.length(3);
1513+
1514+
for (const post of user.posts) {
1515+
expect(post).to.be.an('object');
1516+
expect(post).to.have.property('tags');
1517+
expect(post.tags).to.be.an('array').with.length(4);
1518+
1519+
for (const tag of post.tags) {
1520+
expect(tag).to.be.a('string').and.not.be.empty;
1521+
}
1522+
}
1523+
}
1524+
1525+
// Check matrix (2D array)
1526+
expect(document).to.have.property('matrix');
1527+
expect(document.matrix).to.be.an('array').with.length(2);
1528+
1529+
const matrix = document.matrix as number[][];
1530+
for (const row of matrix) {
1531+
expect(row).to.be.an('array').with.length(3);
1532+
for (const cell of row) {
1533+
expect(cell).to.be.a('number').and.be.at.least(1).and.at.most(10);
1534+
}
1535+
}
1536+
});
1537+
1538+
it('should handle probability fields correctly', () => {
1539+
const schema = {
1540+
name: {
1541+
mongoType: 'String' as const,
1542+
fakerMethod: 'person.fullName',
1543+
fakerArgs: [],
1544+
probability: 1.0,
1545+
},
1546+
optionalField: {
1547+
mongoType: 'String' as const,
1548+
fakerMethod: 'lorem.word',
1549+
fakerArgs: [],
1550+
probability: 0.0, // Should never appear
1551+
},
1552+
alwaysPresent: {
1553+
mongoType: 'Number' as const,
1554+
fakerMethod: 'number.int',
1555+
fakerArgs: [],
1556+
probability: 1.0,
1557+
},
1558+
};
1559+
1560+
const document = generateDocument(schema);
1561+
1562+
expect(document).to.be.an('object');
1563+
expect(document).to.have.property('name');
1564+
expect(document.name).to.be.a('string').and.not.be.empty;
1565+
expect(document).to.have.property('alwaysPresent');
1566+
expect(document.alwaysPresent).to.be.a('number');
1567+
// optionalField should not be present due to 0.0 probability
1568+
expect(document).to.not.have.property('optionalField');
1569+
});
1570+
});
14241571
});

0 commit comments

Comments
 (0)