Skip to content

Commit c3f2adc

Browse files
committed
WIP
1 parent 920df5f commit c3f2adc

File tree

3 files changed

+155
-4
lines changed

3 files changed

+155
-4
lines changed
Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
import React, { useMemo } from 'react';
2+
import { Body, Code, css, spacing, H3 } from '@mongodb-js/compass-components';
3+
import { usePreference } from 'compass-preferences-model/provider';
4+
import type { Document } from 'mongodb';
5+
import type {
6+
Schema,
7+
SchemaField,
8+
DocumentSchemaType,
9+
ArraySchemaType,
10+
} from 'mongodb-schema';
11+
12+
const containerStyles = css({
13+
padding: spacing[400],
14+
display: 'flex',
15+
flexDirection: 'column',
16+
gap: spacing[300],
17+
});
18+
19+
const sectionStyles = css({
20+
display: 'flex',
21+
flexDirection: 'column',
22+
gap: spacing[200],
23+
});
24+
25+
const codeContainerStyles = css({
26+
maxHeight: '300px',
27+
overflow: 'auto',
28+
});
29+
30+
interface ConfirmationScreenProps {
31+
namespace: string;
32+
schema: Schema;
33+
sampleDocument: Document;
34+
}
35+
36+
/**
37+
* Formats a schema to show only field types (no real values)
38+
*/
39+
function formatSchemaTypesOnly(schema: Schema): string {
40+
const result: Record<string, string> = {};
41+
42+
const processField = (field: SchemaField, path = ''): void => {
43+
const fieldPath = path ? `${path}.${field.name}` : field.name;
44+
const primaryType = field.types?.[0];
45+
46+
if (!primaryType) return;
47+
48+
switch (primaryType.bsonType) {
49+
case 'Document': {
50+
result[fieldPath] = 'Object';
51+
(primaryType as DocumentSchemaType).fields?.forEach((f: SchemaField) =>
52+
processField(f, fieldPath)
53+
);
54+
break;
55+
}
56+
case 'Array': {
57+
const elementType = (primaryType as ArraySchemaType).types?.[0];
58+
if (elementType?.bsonType === 'Document') {
59+
result[fieldPath] = 'Array<Object>';
60+
(elementType as DocumentSchemaType).fields?.forEach(
61+
(f: SchemaField) => processField(f, fieldPath)
62+
);
63+
} else {
64+
result[fieldPath] = `Array<${elementType?.bsonType || 'Mixed'}>`;
65+
}
66+
break;
67+
}
68+
default:
69+
result[fieldPath] = primaryType.bsonType || 'Mixed';
70+
}
71+
};
72+
73+
schema.fields?.forEach((field) => processField(field));
74+
return JSON.stringify(result, null, 2);
75+
}
76+
77+
/**
78+
* Formats a sample document for display
79+
*/
80+
function formatSampleDocument(sampleDocument: Document): string {
81+
return JSON.stringify(sampleDocument, null, 2);
82+
}
83+
84+
export const ConfirmationScreen: React.FunctionComponent<
85+
ConfirmationScreenProps
86+
> = ({ namespace, schema, sampleDocument }) => {
87+
const enableSampleDocumentPassing = usePreference(
88+
'enableGenAISampleDocumentPassingOnAtlasProject'
89+
);
90+
91+
const displayContent = useMemo(() => {
92+
return enableSampleDocumentPassing
93+
? formatSampleDocument(sampleDocument)
94+
: formatSchemaTypesOnly(schema);
95+
}, [enableSampleDocumentPassing, sampleDocument, schema]);
96+
97+
const sectionTitle = enableSampleDocumentPassing
98+
? 'Sample Documents Collected'
99+
: 'Document Schema Identified';
100+
101+
const sectionDescription = enableSampleDocumentPassing
102+
? 'A sample of document values from your collection will be sent to an LLM for processing.'
103+
: 'We have identified the following schema from your documents. This schema will be sent to an LLM for processing.';
104+
105+
return (
106+
<div className={containerStyles}>
107+
<Body>{namespace}</Body>
108+
109+
<div className={sectionStyles}>
110+
<H3>{sectionTitle}</H3>
111+
<Body>{sectionDescription}</Body>
112+
113+
<div className={codeContainerStyles}>
114+
<Code language="json" copyable={false}>
115+
{displayContent}
116+
</Code>
117+
</div>
118+
</div>
119+
</div>
120+
);
121+
};

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import Sinon from 'sinon';
55
import { UnconnectedMockDataGeneratorModal as MockDataGeneratorModal } from './mock-data-generator-modal';
66
import { MockDataGeneratorStep } from './types';
77
import { StepButtonLabelMap } from './constants';
8+
import { SCHEMA_ANALYSIS_STATE_INITIAL } from '../../schema-analysis-types';
89

910
describe('MockDataGeneratorModal', () => {
1011
const sandbox = Sinon.createSandbox();
@@ -32,6 +33,8 @@ describe('MockDataGeneratorModal', () => {
3233
currentStep={currentStep}
3334
onNextStep={onNextStep}
3435
onPreviousStep={onPreviousStep}
36+
namespace="test.collection"
37+
schemaAnalysis={{ status: SCHEMA_ANALYSIS_STATE_INITIAL }}
3538
/>
3639
);
3740
}

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

Lines changed: 31 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@ import {
2222
mockDataGeneratorNextButtonClicked,
2323
mockDataGeneratorPreviousButtonClicked,
2424
} from '../../modules/collection-tab';
25+
import { ConfirmationScreen } from './confirmation-screen';
26+
import type { SchemaAnalysisState } from '../../schema-analysis-types';
27+
import { SCHEMA_ANALYSIS_STATE_COMPLETE } from '../../schema-analysis-types';
2528

2629
const footerStyles = css`
2730
flex-direction: row;
@@ -40,6 +43,8 @@ interface Props {
4043
currentStep: MockDataGeneratorStep;
4144
onNextStep: () => void;
4245
onPreviousStep: () => void;
46+
namespace: string; // "database.collection"
47+
schemaAnalysis: SchemaAnalysisState;
4348
}
4449

4550
const MockDataGeneratorModal = ({
@@ -48,10 +53,33 @@ const MockDataGeneratorModal = ({
4853
currentStep,
4954
onNextStep,
5055
onPreviousStep,
56+
namespace,
57+
schemaAnalysis,
5158
}: Props) => {
5259
const handleNextClick =
5360
currentStep === MockDataGeneratorStep.GENERATE_DATA ? onClose : onNextStep;
5461

62+
const renderStepContent = () => {
63+
switch (currentStep) {
64+
case MockDataGeneratorStep.SCHEMA_CONFIRMATION:
65+
if (schemaAnalysis.status === SCHEMA_ANALYSIS_STATE_COMPLETE) {
66+
return (
67+
<ConfirmationScreen
68+
namespace={namespace}
69+
schema={schemaAnalysis.schema}
70+
sampleDocument={schemaAnalysis.sampleDocument}
71+
/>
72+
);
73+
}
74+
// TODO: Fallback if schema analysis is not complete
75+
return <div>Loading schema analysis...</div>;
76+
77+
default:
78+
// TODO: Render other step content here based on currentStep
79+
return <div data-testid={`generate-mock-data-step-${currentStep}`} />;
80+
}
81+
};
82+
5583
return (
5684
<Modal
5785
open={isOpen}
@@ -63,10 +91,7 @@ const MockDataGeneratorModal = ({
6391
data-testid="generate-mock-data-modal"
6492
>
6593
<ModalHeader title="Generate Mock Data" />
66-
<ModalBody>
67-
{/* TODO: Render actual step content here based on currentStep. (CLOUDP-333851) */}
68-
<div data-testid={`generate-mock-data-step-${currentStep}`} />
69-
</ModalBody>
94+
<ModalBody>{renderStepContent()}</ModalBody>
7095
<ModalFooter className={footerStyles}>
7196
<Button
7297
onClick={onPreviousStep}
@@ -92,6 +117,8 @@ const MockDataGeneratorModal = ({
92117
const mapStateToProps = (state: CollectionState) => ({
93118
isOpen: state.mockDataGenerator.isModalOpen,
94119
currentStep: state.mockDataGenerator.currentStep,
120+
namespace: state.namespace,
121+
schemaAnalysis: state.schemaAnalysis,
95122
});
96123

97124
const ConnectedMockDataGeneratorModal = connect(mapStateToProps, {

0 commit comments

Comments
 (0)