diff --git a/package-lock.json b/package-lock.json index 22b26e04282..174f42cd301 100644 --- a/package-lock.json +++ b/package-lock.json @@ -26,6 +26,12 @@ "npm": ">=10.2.4" } }, + "@mongodb-js/diagramming": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@mongodb-js/diagramming/-/diagramming-1.8.0.tgz", + "integrity": "sha512-ABg9MVNUm4wD5UijQHf3Il6WSrHPqchmMFHJMJ1OAgMEDXXKJNzUvK1Zhz5iDEEO5uIHOYSQRcCY8MeC9bo+fA==", + "extraneous": true + }, "configs/eslint-config-compass": { "name": "@mongodb-js/eslint-config-compass", "version": "1.4.11", @@ -7025,19 +7031,40 @@ } }, "node_modules/@leafygreen-ui/inline-definition": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/@leafygreen-ui/inline-definition/-/inline-definition-8.0.2.tgz", - "integrity": "sha512-Rg0AsMOtxI1EveQ1zGBgUD9yGifVcxzEwHYz3Rm3BvawCzo+Ynk2OIosOzo3VYL5uuq/pN9bpgq/bFuS1KczbA==", + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/@leafygreen-ui/inline-definition/-/inline-definition-9.0.5.tgz", + "integrity": "sha512-GVxxefMclIgUSWJClGIMb//jp2JWRyCLJJ28FsXl80U8LBGmYzt8VvlH9o0nFOcTd9r6Nk1tRsEgJBpuvTo+3w==", "license": "Apache-2.0", "dependencies": { - "@leafygreen-ui/emotion": "^4.0.9", - "@leafygreen-ui/lib": "^14.0.2", - "@leafygreen-ui/palette": "^4.1.3", - "@leafygreen-ui/tokens": "^2.11.3", - "@leafygreen-ui/tooltip": "^13.0.2" + "@leafygreen-ui/emotion": "^5.0.2", + "@leafygreen-ui/lib": "^15.3.0", + "@leafygreen-ui/palette": "^5.0.2", + "@leafygreen-ui/tokens": "^3.2.4", + "@leafygreen-ui/tooltip": "^14.1.3" }, "peerDependencies": { - "@leafygreen-ui/leafygreen-provider": "^4.0.2" + "@leafygreen-ui/leafygreen-provider": "^5.0.4" + } + }, + "node_modules/@leafygreen-ui/inline-definition/node_modules/@leafygreen-ui/tooltip": { + "version": "14.1.4", + "resolved": "https://registry.npmjs.org/@leafygreen-ui/tooltip/-/tooltip-14.1.4.tgz", + "integrity": "sha512-OHuWYuwL6PEMt8fLs8bVhqrEZR4zmvBuKli01bLffxBwQZXhsLg5fsBfY/iqeoIVUd6NR0FlCfNebcqYrP2ccQ==", + "license": "Apache-2.0", + "dependencies": { + "@leafygreen-ui/emotion": "^5.0.3", + "@leafygreen-ui/hooks": "^9.1.4", + "@leafygreen-ui/icon": "^14.5.1", + "@leafygreen-ui/lib": "^15.4.0", + "@leafygreen-ui/palette": "^5.0.2", + "@leafygreen-ui/popover": "^14.0.6", + "@leafygreen-ui/tokens": "^3.2.4", + "@leafygreen-ui/typography": "^22.1.3", + "lodash": "^4.17.21", + "polished": "^4.2.2" + }, + "peerDependencies": { + "@leafygreen-ui/leafygreen-provider": "^5.0.4" } }, "node_modules/@leafygreen-ui/input-option": { @@ -10156,14 +10183,15 @@ } }, "node_modules/@mongodb-js/diagramming": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/@mongodb-js/diagramming/-/diagramming-1.5.1.tgz", - "integrity": "sha512-lyF8VIh+hwFEmou980K4gB9f+PegMaXgFlgQijur4oRZlsIrlmvQ4Gg5r0C/SqVyMn7MQIDiADgZr+NJJ8sd6Q==", + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@mongodb-js/diagramming/-/diagramming-1.8.0.tgz", + "integrity": "sha512-ABg9MVNUm4wD5UijQHf3Il6WSrHPqchmMFHJMJ1OAgMEDXXKJNzUvK1Zhz5iDEEO5uIHOYSQRcCY8MeC9bo+fA==", "license": "MIT", "dependencies": { "@emotion/react": "^11.14.0", "@emotion/styled": "^11.14.0", "@leafygreen-ui/icon": "^14.3.0", + "@leafygreen-ui/inline-definition": "^9.0.5", "@leafygreen-ui/leafygreen-provider": "^5.0.2", "@leafygreen-ui/palette": "^5.0.0", "@leafygreen-ui/tokens": "^3.2.1", @@ -49116,7 +49144,7 @@ "@mongodb-js/compass-user-data": "^0.10.2", "@mongodb-js/compass-utils": "^0.9.17", "@mongodb-js/compass-workspaces": "^0.59.1", - "@mongodb-js/diagramming": "^1.5.1", + "@mongodb-js/diagramming": "^1.8.0", "bson": "^6.10.4", "compass-preferences-model": "^2.57.1", "html-to-image": "1.11.11", @@ -58907,7 +58935,7 @@ "requires": { "@leafygreen-ui/emotion": "^4.0.9", "@leafygreen-ui/icon": "^13.1.2", - "@leafygreen-ui/inline-definition": "^8.0.2", + "@leafygreen-ui/inline-definition": "^9.0.5", "@leafygreen-ui/lib": "^15.3.0", "@leafygreen-ui/palette": "^4.1.3", "@leafygreen-ui/tokens": "^3.2.4" @@ -59210,15 +59238,34 @@ } }, "@leafygreen-ui/inline-definition": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/@leafygreen-ui/inline-definition/-/inline-definition-8.0.2.tgz", - "integrity": "sha512-Rg0AsMOtxI1EveQ1zGBgUD9yGifVcxzEwHYz3Rm3BvawCzo+Ynk2OIosOzo3VYL5uuq/pN9bpgq/bFuS1KczbA==", + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/@leafygreen-ui/inline-definition/-/inline-definition-9.0.5.tgz", + "integrity": "sha512-GVxxefMclIgUSWJClGIMb//jp2JWRyCLJJ28FsXl80U8LBGmYzt8VvlH9o0nFOcTd9r6Nk1tRsEgJBpuvTo+3w==", "requires": { "@leafygreen-ui/emotion": "^4.0.9", "@leafygreen-ui/lib": "^15.3.0", "@leafygreen-ui/palette": "^4.1.3", "@leafygreen-ui/tokens": "^3.2.4", - "@leafygreen-ui/tooltip": "^13.0.2" + "@leafygreen-ui/tooltip": "^14.1.3" + }, + "dependencies": { + "@leafygreen-ui/tooltip": { + "version": "14.1.4", + "resolved": "https://registry.npmjs.org/@leafygreen-ui/tooltip/-/tooltip-14.1.4.tgz", + "integrity": "sha512-OHuWYuwL6PEMt8fLs8bVhqrEZR4zmvBuKli01bLffxBwQZXhsLg5fsBfY/iqeoIVUd6NR0FlCfNebcqYrP2ccQ==", + "requires": { + "@leafygreen-ui/emotion": "^4.0.9", + "@leafygreen-ui/hooks": "^8.3.4", + "@leafygreen-ui/icon": "^13.1.2", + "@leafygreen-ui/lib": "^15.3.0", + "@leafygreen-ui/palette": "^4.1.3", + "@leafygreen-ui/popover": "^13.0.11", + "@leafygreen-ui/tokens": "^3.2.4", + "@leafygreen-ui/typography": "^20.0.2", + "lodash": "^4.17.21", + "polished": "^4.2.2" + } + } } }, "@leafygreen-ui/input-option": { @@ -62780,7 +62827,7 @@ "@mongodb-js/compass-user-data": "^0.10.2", "@mongodb-js/compass-utils": "^0.9.17", "@mongodb-js/compass-workspaces": "^0.59.1", - "@mongodb-js/diagramming": "^1.5.1", + "@mongodb-js/diagramming": "^1.8.0", "@mongodb-js/eslint-config-compass": "^1.4.11", "@mongodb-js/mocha-config-compass": "^1.7.2", "@mongodb-js/prettier-config-compass": "^1.2.9", @@ -65760,13 +65807,14 @@ } }, "@mongodb-js/diagramming": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/@mongodb-js/diagramming/-/diagramming-1.5.1.tgz", - "integrity": "sha512-lyF8VIh+hwFEmou980K4gB9f+PegMaXgFlgQijur4oRZlsIrlmvQ4Gg5r0C/SqVyMn7MQIDiADgZr+NJJ8sd6Q==", + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@mongodb-js/diagramming/-/diagramming-1.8.0.tgz", + "integrity": "sha512-ABg9MVNUm4wD5UijQHf3Il6WSrHPqchmMFHJMJ1OAgMEDXXKJNzUvK1Zhz5iDEEO5uIHOYSQRcCY8MeC9bo+fA==", "requires": { "@emotion/react": "^11.14.0", "@emotion/styled": "^11.14.0", "@leafygreen-ui/icon": "^13.1.2", + "@leafygreen-ui/inline-definition": "^9.0.5", "@leafygreen-ui/leafygreen-provider": "^4.0.2", "@leafygreen-ui/palette": "^4.1.3", "@leafygreen-ui/tokens": "^3.2.4", diff --git a/package.json b/package.json index 6c84e549a17..d2b042f92dc 100644 --- a/package.json +++ b/package.json @@ -119,6 +119,7 @@ "@leafygreen-ui/marketing-modal": "^5.0.2", "@leafygreen-ui/typography": "^20.0.2", "@leafygreen-ui/icon": "^13.1.2", + "@leafygreen-ui/inline-definition": "^9.0.5", "@leafygreen-ui/popover": "^13.0.11", "@leafygreen-ui/badge": "^9.0.2", "@leafygreen-ui/banner": "^10.1.0", diff --git a/packages/compass-data-modeling/package.json b/packages/compass-data-modeling/package.json index af79c5b620b..42e7292da3c 100644 --- a/packages/compass-data-modeling/package.json +++ b/packages/compass-data-modeling/package.json @@ -63,7 +63,7 @@ "@mongodb-js/compass-user-data": "^0.10.2", "@mongodb-js/compass-utils": "^0.9.17", "@mongodb-js/compass-workspaces": "^0.59.1", - "@mongodb-js/diagramming": "^1.5.1", + "@mongodb-js/diagramming": "^1.8.0", "bson": "^6.10.4", "compass-preferences-model": "^2.57.1", "html-to-image": "1.11.11", diff --git a/packages/compass-data-modeling/src/components/diagram-editor.tsx b/packages/compass-data-modeling/src/components/diagram-editor.tsx index bc9607d8ca2..859b11cc8a2 100644 --- a/packages/compass-data-modeling/src/components/diagram-editor.tsx +++ b/packages/compass-data-modeling/src/components/diagram-editor.tsx @@ -205,14 +205,11 @@ const DiagramContent: React.FunctionComponent<{ selectedItems?.type === 'field' && selectedItems.namespace === coll.ns ? selectedItems.fieldPath : undefined, - onClickAddNewFieldToCollection: () => - onAddNewFieldToCollection(coll.ns), selected, isInRelationshipDrawingMode, }); }); }, [ - onAddNewFieldToCollection, model?.collections, model?.relationships, selectedItems, @@ -319,6 +316,14 @@ const DiagramContent: React.FunctionComponent<{ [handleNodesConnect] ); + const onClickAddFieldToCollection = useCallback( + (event: React.MouseEvent, ns: string) => { + event.stopPropagation(); + onAddNewFieldToCollection(ns); + }, + [onAddNewFieldToCollection] + ); + return (
diff --git a/packages/compass-data-modeling/src/utils/nodes-and-edges.spec.tsx b/packages/compass-data-modeling/src/utils/nodes-and-edges.spec.ts similarity index 90% rename from packages/compass-data-modeling/src/utils/nodes-and-edges.spec.tsx rename to packages/compass-data-modeling/src/utils/nodes-and-edges.spec.ts index 17803c39acb..4945cf20562 100644 --- a/packages/compass-data-modeling/src/utils/nodes-and-edges.spec.tsx +++ b/packages/compass-data-modeling/src/utils/nodes-and-edges.spec.ts @@ -1,28 +1,7 @@ -import React from 'react'; import { expect } from 'chai'; -import { - screen, - waitFor, - render, - userEvent, -} from '@mongodb-js/testing-library-compass'; import { getFieldsFromSchema } from './nodes-and-edges'; describe('getFieldsFromSchema', function () { - const validateMixedType = async ( - type: React.ReactNode, - expectedTooltip: RegExp - ) => { - render(<>{type}); - const mixed = screen.getByText('(mixed)'); - expect(mixed).to.be.visible; - expect(screen.queryByText(expectedTooltip)).to.not.exist; - userEvent.hover(mixed); - await waitFor(() => { - expect(screen.getByText(expectedTooltip)).to.be.visible; - }); - }; - describe('flat schema', function () { it('return empty array for empty schema', function () { const result = getFieldsFromSchema({ jsonSchema: {} }); @@ -63,7 +42,7 @@ describe('getFieldsFromSchema', function () { ]); }); - it('returns mixed fields with tooltip on hover', async function () { + it('returns mixed fields', function () { const result = getFieldsFromSchema({ jsonSchema: { bsonType: 'object', @@ -72,16 +51,16 @@ describe('getFieldsFromSchema', function () { }, }, }); - expect(result[0]).to.deep.include({ + expect(result[0]).to.deep.equal({ name: 'age', id: ['age'], depth: 0, glyphs: [], selectable: true, selected: false, + type: ['int', 'string'], variant: undefined, }); - await validateMixedType(result[0].type, /int, string/); }); it('highlights the correct field', function () { @@ -445,32 +424,6 @@ describe('getFieldsFromSchema', function () { ]); }); - it('returns [] for array', function () { - const result = getFieldsFromSchema({ - jsonSchema: { - bsonType: 'object', - properties: { - tags: { - bsonType: 'array', - items: { bsonType: 'string' }, - }, - }, - }, - }); - expect(result).to.deep.equal([ - { - name: 'tags', - id: ['tags'], - type: '[]', - depth: 0, - glyphs: [], - selectable: true, - selected: false, - variant: undefined, - }, - ]); - }); - it('returns fields for an array of objects', function () { const result = getFieldsFromSchema({ jsonSchema: { @@ -493,7 +446,7 @@ describe('getFieldsFromSchema', function () { { name: 'todos', id: ['todos'], - type: '[]', + type: 'array', depth: 0, glyphs: [], selectable: true, @@ -523,7 +476,7 @@ describe('getFieldsFromSchema', function () { ]); }); - it('returns fields for a mixed schema with objects', async function () { + it('returns fields for a mixed schema with objects', function () { const result = getFieldsFromSchema({ jsonSchema: { bsonType: 'object', @@ -544,16 +497,16 @@ describe('getFieldsFromSchema', function () { }, }); expect(result).to.have.lengthOf(3); - expect(result[0]).to.deep.include({ + expect(result[0]).to.deep.equal({ name: 'name', id: ['name'], depth: 0, + type: ['string', 'object'], glyphs: [], selectable: true, selected: false, variant: undefined, }); - await validateMixedType(result[0].type, /string, object/); expect(result[1]).to.deep.equal({ name: 'first', id: ['name', 'first'], @@ -603,7 +556,7 @@ describe('getFieldsFromSchema', function () { { name: 'todos', id: ['todos'], - type: '[]', + type: 'array', depth: 0, glyphs: [], selectable: true, diff --git a/packages/compass-data-modeling/src/utils/nodes-and-edges.tsx b/packages/compass-data-modeling/src/utils/nodes-and-edges.ts similarity index 63% rename from packages/compass-data-modeling/src/utils/nodes-and-edges.tsx rename to packages/compass-data-modeling/src/utils/nodes-and-edges.ts index 66fa4fdbc1f..6bc35676c42 100644 --- a/packages/compass-data-modeling/src/utils/nodes-and-edges.tsx +++ b/packages/compass-data-modeling/src/utils/nodes-and-edges.ts @@ -1,13 +1,5 @@ -import React from 'react'; import toNS from 'mongodb-ns'; -import { - Body, - IconButton, - InlineDefinition, - css, - cx, -} from '@mongodb-js/compass-components'; -import type { NodeProps, EdgeProps, BaseNode } from '@mongodb-js/diagramming'; +import type { NodeProps, EdgeProps, NodeGlyph } from '@mongodb-js/diagramming'; import type { MongoDBJSONSchema } from 'mongodb-schema'; import type { SelectedItems } from '../store/diagram'; import type { @@ -17,59 +9,15 @@ import type { } from '../services/data-model-storage'; import { traverseSchema } from './schema-traversal'; import { areFieldPathsEqual } from './utils'; -import PlusWithSquare from '../components/icons/plus-with-square'; -function getBsonTypeName(bsonType: string) { - switch (bsonType) { - case 'array': - return '[]'; - default: - return bsonType; - } -} - -const addNewFieldStyles = css({ - marginLeft: 'auto', -}); - -const mixedTypeTooltipContentStyles = css({ - overflowWrap: 'anywhere', - textWrap: 'wrap', - textAlign: 'left', -}); - -function getFieldTypeDisplay(bsonTypes: string[]) { - if (bsonTypes.length === 0) { - return 'unknown'; - } - - if (bsonTypes.length === 1) { - return getBsonTypeName(bsonTypes[0]); - } - - const typesString = bsonTypes - .map((bsonType) => getBsonTypeName(bsonType)) - .join(', '); - - // We show `mixed` with a tooltip when multiple bsonTypes were found. - return ( - - Multiple types found in sample: {typesString} - - } - > - (mixed) - - ); -} +const NO_HIGHLIGHTED_FIELDS = {}; export const getHighlightedFields = ( selectedItems: SelectedItems | null, relationships?: Relationship[] ): Record => { - if (!selectedItems || selectedItems.type !== 'relationship') return {}; + if (!selectedItems || selectedItems.type !== 'relationship') + return NO_HIGHLIGHTED_FIELDS; const { id } = selectedItems; const { relationship } = relationships?.find((rel) => rel.id === id) ?? {}; const selection: Record = {}; @@ -85,6 +33,9 @@ export const getHighlightedFields = ( return selection; }; +const KEY_GLYPH: NodeGlyph[] = ['key']; +const NO_GLYPH: NodeGlyph[] = []; + export const getFieldsFromSchema = ({ jsonSchema, highlightedFields = [], @@ -105,14 +56,15 @@ export const getFieldsFromSchema = ({ fields.push({ name: fieldPath[fieldPath.length - 1], id: fieldPath, - type: getFieldTypeDisplay(fieldTypes), + type: fieldTypes.length === 1 ? fieldTypes[0] : fieldTypes, depth: fieldPath.length - 1, glyphs: fieldTypes.length === 1 && fieldTypes[0] === 'objectId' - ? ['key'] - : [], + ? KEY_GLYPH + : NO_GLYPH, selectable: true, - selected: areFieldPathsEqual(fieldPath, selectedField ?? []), + selected: + !!selectedField && areFieldPathsEqual(fieldPath, selectedField), variant: highlightedFields.length && highlightedFields.some((highlightedField) => @@ -134,10 +86,10 @@ export function collectionToBaseNodeForLayout({ ns, jsonSchema, displayPosition, -}: Pick< - DataModelCollection, - 'ns' | 'jsonSchema' | 'displayPosition' ->): BaseNode & Pick { +}: Pick): Pick< + NodeProps, + 'id' | 'position' | 'fields' +> { return { id: ns, position: { @@ -156,7 +108,6 @@ type CollectionWithRenderOptions = Pick< selectedField?: FieldPath; selected: boolean; isInRelationshipDrawingMode: boolean; - onClickAddNewFieldToCollection: () => void; }; export function collectionToDiagramNode({ @@ -167,7 +118,6 @@ export function collectionToDiagramNode({ highlightedFields, selected, isInRelationshipDrawingMode, - onClickAddNewFieldToCollection, }: CollectionWithRenderOptions): NodeProps { return { id: ns, @@ -185,19 +135,6 @@ export function collectionToDiagramNode({ selected, connectable: isInRelationshipDrawingMode, draggable: !isInRelationshipDrawingMode, - actions: onClickAddNewFieldToCollection ? ( - ) => { - event.stopPropagation(); - onClickAddNewFieldToCollection(); - }} - title="Add Field" - > - - - ) : undefined, }; }