@@ -18,14 +18,14 @@ import {
1818 Banner ,
1919 Body ,
2020 CancelLoader ,
21- Tooltip ,
2221 WorkspaceContainer ,
2322 css ,
2423 spacing ,
2524 Button ,
2625 palette ,
2726 ErrorSummary ,
2827 useDarkMode ,
28+ InlineDefinition ,
2929} from '@mongodb-js/compass-components' ;
3030import { CodemirrorMultilineEditor } from '@mongodb-js/compass-editor' ;
3131import { cancelAnalysis , retryAnalysis } from '../store/analysis-process' ;
@@ -41,7 +41,6 @@ import { UUID } from 'bson';
4141import DiagramEditorToolbar from './diagram-editor-toolbar' ;
4242import ExportDiagramModal from './export-diagram-modal' ;
4343import { useLogger } from '@mongodb-js/compass-logging/provider' ;
44- import type { MongoDBJSONSchema } from 'mongodb-schema' ;
4544
4645const loadingContainerStyles = css ( {
4746 width : '100%' ,
@@ -87,27 +86,90 @@ const ErrorBannerWithRetry: React.FunctionComponent<{
8786 ) ;
8887} ;
8988
90- function getFieldTypeDisplay ( field : MongoDBJSONSchema ) {
91- if ( field . bsonType === undefined ) {
89+ function getBsonTypeName ( bsonType : string ) {
90+ switch ( bsonType ) {
91+ case 'array' :
92+ return '[]' ;
93+ default :
94+ return bsonType ;
95+ }
96+ }
97+
98+ function getFieldTypeDisplay ( bsonTypes : string [ ] ) {
99+ if ( bsonTypes . length === 0 ) {
92100 return 'unknown' ;
93101 }
94102
95- if ( typeof field . bsonType === 'string' ) {
96- return field . bsonType ;
103+ if ( bsonTypes . length === 1 ) {
104+ return getBsonTypeName ( bsonTypes [ 0 ] ) ;
97105 }
98106
99- const typesString = field . bsonType . join ( ', ' ) ;
107+ const typesString = bsonTypes
108+ . map ( ( bsonType ) => getBsonTypeName ( bsonType ) )
109+ . join ( ', ' ) ;
100110
101111 // We show `mixed` with a tooltip when multiple bsonTypes were found.
102112 return (
103- < Tooltip justify = "end" spacing = { 5 } trigger = { < div > (mixed)</ div > } >
104- < Body className = { mixedTypeTooltipContentStyles } >
105- Multiple types found in sample: { typesString }
106- </ Body >
107- </ Tooltip >
113+ < InlineDefinition
114+ definition = {
115+ < Body className = { mixedTypeTooltipContentStyles } >
116+ Multiple types found in sample: { typesString }
117+ </ Body >
118+ }
119+ >
120+ < div > (mixed)</ div >
121+ </ InlineDefinition >
108122 ) ;
109123}
110124
125+ const getFieldsFromSchema = (
126+ jsonSchema : MongoDBJSONSchema ,
127+ depth = 0
128+ ) : NodeProps [ 'fields' ] => {
129+ if ( ! jsonSchema || ! jsonSchema . properties ) {
130+ return [ ] ;
131+ }
132+ let fields : NodeProps [ 'fields' ] = [ ] ;
133+ for ( const [ name , field ] of Object . entries ( jsonSchema . properties ) ) {
134+ // field has types, properties and (optional) children
135+ // types are either direct, or from anyof
136+ // children are either direct (properties), from anyOf, items or items.anyOf
137+ const types : ( string | string [ ] ) [ ] = [ ] ;
138+ const children = [ ] ;
139+ if ( field . bsonType ) types . push ( field . bsonType ) ;
140+ if ( field . properties ) children . push ( field ) ;
141+ if ( field . items )
142+ children . push ( ( field . items as MongoDBJSONSchema ) . anyOf || field . items ) ;
143+ if ( field . anyOf ) {
144+ for ( const variant of field . anyOf ) {
145+ if ( variant . bsonType ) types . push ( variant . bsonType ) ;
146+ if ( variant . properties ) {
147+ children . push ( variant ) ;
148+ }
149+ if ( variant . items ) children . push ( variant . items ) ;
150+ }
151+ }
152+
153+ fields . push ( {
154+ name,
155+ type : getFieldTypeDisplay ( types . flat ( ) ) ,
156+ depth : depth ,
157+ glyphs : types . length === 1 && types [ 0 ] === 'objectId' ? [ 'key' ] : [ ] ,
158+ } ) ;
159+
160+ if ( children . length > 0 ) {
161+ fields = [
162+ ...fields ,
163+ ...children
164+ . flat ( )
165+ . flatMap ( ( child ) => getFieldsFromSchema ( child , depth + 1 ) ) ,
166+ ] ;
167+ }
168+ }
169+
170+ return fields ;
171+ } ;
172+
111173const modelPreviewContainerStyles = css ( {
112174 display : 'grid' ,
113175 gridTemplateColumns : '100%' ,
@@ -145,33 +207,6 @@ const editorContainerPlaceholderButtonStyles = css({
145207 paddingTop : spacing [ 200 ] ,
146208} ) ;
147209
148- const getFieldsFromSchema = (
149- jsonSchema : MongoDBJSONSchema ,
150- depth = 0
151- ) : NodeProps [ 'fields' ] => {
152- let fields = [ ] as NodeProps [ 'fields' ] ;
153- if ( jsonSchema . anyOf ) {
154- for ( const variant of jsonSchema . anyOf ) {
155- fields = [ ...fields , ...getFieldsFromSchema ( variant , depth + 1 ) ] ;
156- }
157- }
158- if ( ! jsonSchema . properties ) return [ ] ;
159- for ( const [ name , field ] of Object . entries ( jsonSchema . properties ) ) {
160- const type = getFieldTypeDisplay ( field ) ;
161- fields . push ( {
162- name,
163- type,
164- depth : depth ,
165- glyphs : type === 'objectId' ? [ 'key' ] : [ ] ,
166- } ) ;
167- if ( field . properties ) {
168- fields = [ ...fields , ...getFieldsFromSchema ( field , depth + 1 ) ] ;
169- }
170- }
171-
172- return fields ;
173- } ;
174-
175210const DiagramEditor : React . FunctionComponent < {
176211 diagramLabel : string ;
177212 step : DataModelingState [ 'step' ] ;
0 commit comments