From 993bdcc3f0927922e93b9817c1dfab23c480b022 Mon Sep 17 00:00:00 2001 From: Rhys Howell Date: Fri, 26 Sep 2025 17:59:32 -0400 Subject: [PATCH 1/3] chore(data-modeling): bump diagramming, pass new options, remove related code --- package-lock.json | 458 ++++++++++++++++-- packages/compass-data-modeling/package.json | 2 +- .../src/components/diagram-editor.tsx | 12 +- ...edges.spec.tsx => nodes-and-edges.spec.ts} | 63 +-- ...nodes-and-edges.tsx => nodes-and-edges.ts} | 95 +--- 5 files changed, 451 insertions(+), 179 deletions(-) rename packages/compass-data-modeling/src/utils/{nodes-and-edges.spec.tsx => nodes-and-edges.spec.ts} (90%) rename packages/compass-data-modeling/src/utils/{nodes-and-edges.tsx => nodes-and-edges.ts} (63%) diff --git a/package-lock.json b/package-lock.json index a1da082bcea..02800eaec88 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10155,26 +10155,6 @@ "url": "https://opencollective.com/node-fetch" } }, - "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==", - "license": "MIT", - "dependencies": { - "@emotion/react": "^11.14.0", - "@emotion/styled": "^11.14.0", - "@leafygreen-ui/icon": "^14.3.0", - "@leafygreen-ui/leafygreen-provider": "^5.0.2", - "@leafygreen-ui/palette": "^5.0.0", - "@leafygreen-ui/tokens": "^3.2.1", - "@leafygreen-ui/typography": "^22.1.0", - "@xyflow/react": "12.5.1", - "d3-path": "^3.1.0", - "elkjs": "^0.10.0", - "react": "17.0.2", - "react-dom": "17.0.2" - } - }, "node_modules/@mongodb-js/dl-center": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/@mongodb-js/dl-center/-/dl-center-1.3.0.tgz", @@ -49116,7 +49096,7 @@ "@mongodb-js/compass-user-data": "^0.10.1", "@mongodb-js/compass-utils": "^0.9.16", "@mongodb-js/compass-workspaces": "^0.59.0", - "@mongodb-js/diagramming": "^1.5.1", + "@mongodb-js/diagramming": "^1.8.0", "bson": "^6.10.4", "compass-preferences-model": "^2.57.0", "html-to-image": "1.11.11", @@ -49151,6 +49131,232 @@ "xvfb-maybe": "^0.2.1" } }, + "packages/compass-data-modeling/node_modules/@leafygreen-ui/emotion": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/@leafygreen-ui/emotion/-/emotion-5.0.3.tgz", + "integrity": "sha512-elu8af9Qh8Oy/IwqXcNKitHAQBAO4+zmHuLi0fRzY46kTwXvLYqPpJFRcySqITWLPyBcMsF56ta8yQKXghEYOA==", + "license": "Apache-2.0", + "dependencies": { + "@emotion/css": "^11.1.3", + "@emotion/server": "^11.4.0" + } + }, + "packages/compass-data-modeling/node_modules/@leafygreen-ui/hooks": { + "version": "9.1.4", + "resolved": "https://registry.npmjs.org/@leafygreen-ui/hooks/-/hooks-9.1.4.tgz", + "integrity": "sha512-Cr+XRTh+8M8g30TjY7YPEHvtJmiPd9Nquc6Kcm/GqUNAPKthMGJIQKyzSlF+mvBDbrvV6dZVZh8mvHdENa2Tfg==", + "license": "Apache-2.0", + "dependencies": { + "@leafygreen-ui/lib": "^15.4.0", + "@leafygreen-ui/tokens": "^3.2.4", + "lodash": "^4.17.21" + } + }, + "packages/compass-data-modeling/node_modules/@leafygreen-ui/hooks/node_modules/@leafygreen-ui/lib": { + "version": "15.4.0", + "resolved": "https://registry.npmjs.org/@leafygreen-ui/lib/-/lib-15.4.0.tgz", + "integrity": "sha512-jF6sJ4+rmhvky7Gs8c1wxtOyiYEhu+I+3M5PFi+xFHjNm/tkxjSfjsz18eEccR6M6li8JGVb2o/OU/mbVg0oqQ==", + "license": "Apache-2.0", + "dependencies": { + "lodash": "^4.17.21" + }, + "peerDependencies": { + "react": "^17.0.0 || ^18.0.0" + } + }, + "packages/compass-data-modeling/node_modules/@leafygreen-ui/icon": { + "version": "14.5.1", + "resolved": "https://registry.npmjs.org/@leafygreen-ui/icon/-/icon-14.5.1.tgz", + "integrity": "sha512-SU0U2yJWox8I5Cs+NWErdxXEK8bp8hvbarIUkvucGDpJ6BGimho1f0v5Df1kQq3vDQRYX413nZeoPTL5b7g4KQ==", + "license": "Apache-2.0", + "dependencies": { + "@leafygreen-ui/emotion": "^5.0.3", + "lodash": "^4.17.21" + } + }, + "packages/compass-data-modeling/node_modules/@leafygreen-ui/inline-definition": { + "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": "^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": "^5.0.4" + } + }, + "packages/compass-data-modeling/node_modules/@leafygreen-ui/leafygreen-provider": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/@leafygreen-ui/leafygreen-provider/-/leafygreen-provider-5.0.4.tgz", + "integrity": "sha512-VDlmjTiIqlITVhq4VKUDq8FLySWnHkTxSV2n1sxOanLNPuatOXjxsPmCkPUBXhmQKk/fBf4yQnDKOwJvkyzE6Q==", + "license": "Apache-2.0", + "dependencies": { + "@leafygreen-ui/hooks": "^9.1.3", + "@leafygreen-ui/lib": "^15.3.0", + "react-transition-group": "^4.4.5" + } + }, + "packages/compass-data-modeling/node_modules/@leafygreen-ui/palette": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@leafygreen-ui/palette/-/palette-5.0.2.tgz", + "integrity": "sha512-+PrfGeJSv4goxm/vKpfJJDOP7t/uElj+14K8jiIyu3qR3TcFRIZ5h1VMvICTUgqvRc8W+xIZYQwsLa2XCu2lvw==", + "license": "Apache-2.0" + }, + "packages/compass-data-modeling/node_modules/@leafygreen-ui/polymorphic": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@leafygreen-ui/polymorphic/-/polymorphic-3.1.0.tgz", + "integrity": "sha512-5fbXD6ExTmMScvODuipfB1Ti/Dvoaxxg+daSftqXfNQlEkEnd5cPnezOOl1LMsu2xUoZT6NXsFgukZYsmXEVpQ==", + "license": "Apache-2.0", + "dependencies": { + "@leafygreen-ui/lib": "^15.4.0", + "lodash": "^4.17.21" + } + }, + "packages/compass-data-modeling/node_modules/@leafygreen-ui/polymorphic/node_modules/@leafygreen-ui/lib": { + "version": "15.4.0", + "resolved": "https://registry.npmjs.org/@leafygreen-ui/lib/-/lib-15.4.0.tgz", + "integrity": "sha512-jF6sJ4+rmhvky7Gs8c1wxtOyiYEhu+I+3M5PFi+xFHjNm/tkxjSfjsz18eEccR6M6li8JGVb2o/OU/mbVg0oqQ==", + "license": "Apache-2.0", + "dependencies": { + "lodash": "^4.17.21" + }, + "peerDependencies": { + "react": "^17.0.0 || ^18.0.0" + } + }, + "packages/compass-data-modeling/node_modules/@leafygreen-ui/popover": { + "version": "14.0.6", + "resolved": "https://registry.npmjs.org/@leafygreen-ui/popover/-/popover-14.0.6.tgz", + "integrity": "sha512-H84TSOZbk43kRqrNvly4eMTV/L4SlnrVMPPasH/bOW8knt7dGnSkSjWlawH78qe0yCxt+rWKW7MmUMuaPagNnw==", + "license": "Apache-2.0", + "dependencies": { + "@floating-ui/react": "^0.26.28", + "@leafygreen-ui/emotion": "^5.0.3", + "@leafygreen-ui/hooks": "^9.1.4", + "@leafygreen-ui/lib": "^15.4.0", + "@leafygreen-ui/portal": "^7.0.4", + "@leafygreen-ui/tokens": "^3.2.4", + "@types/react-transition-group": "^4.4.5", + "lodash": "^4.17.21", + "react-transition-group": "^4.4.5" + }, + "peerDependencies": { + "@leafygreen-ui/leafygreen-provider": "^5.0.4" + } + }, + "packages/compass-data-modeling/node_modules/@leafygreen-ui/popover/node_modules/@leafygreen-ui/lib": { + "version": "15.4.0", + "resolved": "https://registry.npmjs.org/@leafygreen-ui/lib/-/lib-15.4.0.tgz", + "integrity": "sha512-jF6sJ4+rmhvky7Gs8c1wxtOyiYEhu+I+3M5PFi+xFHjNm/tkxjSfjsz18eEccR6M6li8JGVb2o/OU/mbVg0oqQ==", + "license": "Apache-2.0", + "dependencies": { + "lodash": "^4.17.21" + }, + "peerDependencies": { + "react": "^17.0.0 || ^18.0.0" + } + }, + "packages/compass-data-modeling/node_modules/@leafygreen-ui/popover/node_modules/@leafygreen-ui/portal": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/@leafygreen-ui/portal/-/portal-7.0.4.tgz", + "integrity": "sha512-qpxnBlpLzQtP4GCcbTo2M4RYpPuORMjgP+IMJNl2oQAg75DLIIAcRbV5yuMpN1IRsus0fBHykfquSe5UvA13aw==", + "license": "Apache-2.0", + "dependencies": { + "@leafygreen-ui/hooks": "^9.1.3", + "@leafygreen-ui/lib": "^15.3.0" + }, + "peerDependencies": { + "react-dom": "^17.0.0 || ^18.0.0" + } + }, + "packages/compass-data-modeling/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" + } + }, + "packages/compass-data-modeling/node_modules/@leafygreen-ui/tooltip/node_modules/@leafygreen-ui/lib": { + "version": "15.4.0", + "resolved": "https://registry.npmjs.org/@leafygreen-ui/lib/-/lib-15.4.0.tgz", + "integrity": "sha512-jF6sJ4+rmhvky7Gs8c1wxtOyiYEhu+I+3M5PFi+xFHjNm/tkxjSfjsz18eEccR6M6li8JGVb2o/OU/mbVg0oqQ==", + "license": "Apache-2.0", + "dependencies": { + "lodash": "^4.17.21" + }, + "peerDependencies": { + "react": "^17.0.0 || ^18.0.0" + } + }, + "packages/compass-data-modeling/node_modules/@leafygreen-ui/typography": { + "version": "22.1.3", + "resolved": "https://registry.npmjs.org/@leafygreen-ui/typography/-/typography-22.1.3.tgz", + "integrity": "sha512-yhQGva/0t2wyJe+edt88Dld1FUyw0xXMrHVegjtTH7c7EiLjG1eD4S+ze/Iz4F7Pxm0wXuxV3ZBrHfx2XqR6mA==", + "license": "Apache-2.0", + "dependencies": { + "@leafygreen-ui/emotion": "^5.0.3", + "@leafygreen-ui/icon": "^14.5.1", + "@leafygreen-ui/lib": "^15.4.0", + "@leafygreen-ui/palette": "^5.0.2", + "@leafygreen-ui/polymorphic": "^3.1.0", + "@leafygreen-ui/tokens": "^3.2.4" + }, + "peerDependencies": { + "@leafygreen-ui/leafygreen-provider": "^5.0.4" + } + }, + "packages/compass-data-modeling/node_modules/@leafygreen-ui/typography/node_modules/@leafygreen-ui/lib": { + "version": "15.4.0", + "resolved": "https://registry.npmjs.org/@leafygreen-ui/lib/-/lib-15.4.0.tgz", + "integrity": "sha512-jF6sJ4+rmhvky7Gs8c1wxtOyiYEhu+I+3M5PFi+xFHjNm/tkxjSfjsz18eEccR6M6li8JGVb2o/OU/mbVg0oqQ==", + "license": "Apache-2.0", + "dependencies": { + "lodash": "^4.17.21" + }, + "peerDependencies": { + "react": "^17.0.0 || ^18.0.0" + } + }, + "packages/compass-data-modeling/node_modules/@mongodb-js/diagramming": { + "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", + "@leafygreen-ui/typography": "^22.1.0", + "@xyflow/react": "12.5.1", + "d3-path": "^3.1.0", + "elkjs": "^0.10.0", + "react": "17.0.2", + "react-dom": "17.0.2" + } + }, "packages/compass-data-modeling/node_modules/@sinonjs/commons": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.1.tgz", @@ -62780,7 +62986,7 @@ "@mongodb-js/compass-user-data": "^0.10.1", "@mongodb-js/compass-utils": "^0.9.16", "@mongodb-js/compass-workspaces": "^0.59.0", - "@mongodb-js/diagramming": "^1.5.1", + "@mongodb-js/diagramming": "^1.8.0", "@mongodb-js/eslint-config-compass": "^1.4.10", "@mongodb-js/mocha-config-compass": "^1.7.1", "@mongodb-js/prettier-config-compass": "^1.2.8", @@ -62813,6 +63019,195 @@ "xvfb-maybe": "^0.2.1" }, "dependencies": { + "@leafygreen-ui/emotion": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/@leafygreen-ui/emotion/-/emotion-5.0.3.tgz", + "integrity": "sha512-elu8af9Qh8Oy/IwqXcNKitHAQBAO4+zmHuLi0fRzY46kTwXvLYqPpJFRcySqITWLPyBcMsF56ta8yQKXghEYOA==", + "requires": { + "@emotion/css": "^11.1.3", + "@emotion/server": "^11.4.0" + } + }, + "@leafygreen-ui/hooks": { + "version": "9.1.4", + "resolved": "https://registry.npmjs.org/@leafygreen-ui/hooks/-/hooks-9.1.4.tgz", + "integrity": "sha512-Cr+XRTh+8M8g30TjY7YPEHvtJmiPd9Nquc6Kcm/GqUNAPKthMGJIQKyzSlF+mvBDbrvV6dZVZh8mvHdENa2Tfg==", + "requires": { + "@leafygreen-ui/lib": "^15.4.0", + "@leafygreen-ui/tokens": "^3.2.4", + "lodash": "^4.17.21" + }, + "dependencies": { + "@leafygreen-ui/lib": { + "version": "15.4.0", + "resolved": "https://registry.npmjs.org/@leafygreen-ui/lib/-/lib-15.4.0.tgz", + "integrity": "sha512-jF6sJ4+rmhvky7Gs8c1wxtOyiYEhu+I+3M5PFi+xFHjNm/tkxjSfjsz18eEccR6M6li8JGVb2o/OU/mbVg0oqQ==", + "requires": { + "lodash": "^4.17.21" + } + } + } + }, + "@leafygreen-ui/icon": { + "version": "14.5.1", + "resolved": "https://registry.npmjs.org/@leafygreen-ui/icon/-/icon-14.5.1.tgz", + "integrity": "sha512-SU0U2yJWox8I5Cs+NWErdxXEK8bp8hvbarIUkvucGDpJ6BGimho1f0v5Df1kQq3vDQRYX413nZeoPTL5b7g4KQ==", + "requires": { + "@leafygreen-ui/emotion": "^5.0.3", + "lodash": "^4.17.21" + } + }, + "@leafygreen-ui/inline-definition": { + "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": "^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" + } + }, + "@leafygreen-ui/leafygreen-provider": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/@leafygreen-ui/leafygreen-provider/-/leafygreen-provider-5.0.4.tgz", + "integrity": "sha512-VDlmjTiIqlITVhq4VKUDq8FLySWnHkTxSV2n1sxOanLNPuatOXjxsPmCkPUBXhmQKk/fBf4yQnDKOwJvkyzE6Q==", + "requires": { + "@leafygreen-ui/hooks": "^9.1.3", + "@leafygreen-ui/lib": "^15.3.0", + "react-transition-group": "^4.4.5" + } + }, + "@leafygreen-ui/palette": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@leafygreen-ui/palette/-/palette-5.0.2.tgz", + "integrity": "sha512-+PrfGeJSv4goxm/vKpfJJDOP7t/uElj+14K8jiIyu3qR3TcFRIZ5h1VMvICTUgqvRc8W+xIZYQwsLa2XCu2lvw==" + }, + "@leafygreen-ui/polymorphic": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@leafygreen-ui/polymorphic/-/polymorphic-3.1.0.tgz", + "integrity": "sha512-5fbXD6ExTmMScvODuipfB1Ti/Dvoaxxg+daSftqXfNQlEkEnd5cPnezOOl1LMsu2xUoZT6NXsFgukZYsmXEVpQ==", + "requires": { + "@leafygreen-ui/lib": "^15.4.0", + "lodash": "^4.17.21" + }, + "dependencies": { + "@leafygreen-ui/lib": { + "version": "15.4.0", + "resolved": "https://registry.npmjs.org/@leafygreen-ui/lib/-/lib-15.4.0.tgz", + "integrity": "sha512-jF6sJ4+rmhvky7Gs8c1wxtOyiYEhu+I+3M5PFi+xFHjNm/tkxjSfjsz18eEccR6M6li8JGVb2o/OU/mbVg0oqQ==", + "requires": { + "lodash": "^4.17.21" + } + } + } + }, + "@leafygreen-ui/popover": { + "version": "14.0.6", + "resolved": "https://registry.npmjs.org/@leafygreen-ui/popover/-/popover-14.0.6.tgz", + "integrity": "sha512-H84TSOZbk43kRqrNvly4eMTV/L4SlnrVMPPasH/bOW8knt7dGnSkSjWlawH78qe0yCxt+rWKW7MmUMuaPagNnw==", + "requires": { + "@floating-ui/react": "^0.26.28", + "@leafygreen-ui/emotion": "^5.0.3", + "@leafygreen-ui/hooks": "^9.1.4", + "@leafygreen-ui/lib": "^15.4.0", + "@leafygreen-ui/portal": "^7.0.4", + "@leafygreen-ui/tokens": "^3.2.4", + "@types/react-transition-group": "^4.4.5", + "lodash": "^4.17.21", + "react-transition-group": "^4.4.5" + }, + "dependencies": { + "@leafygreen-ui/lib": { + "version": "15.4.0", + "resolved": "https://registry.npmjs.org/@leafygreen-ui/lib/-/lib-15.4.0.tgz", + "integrity": "sha512-jF6sJ4+rmhvky7Gs8c1wxtOyiYEhu+I+3M5PFi+xFHjNm/tkxjSfjsz18eEccR6M6li8JGVb2o/OU/mbVg0oqQ==", + "requires": { + "lodash": "^4.17.21" + } + }, + "@leafygreen-ui/portal": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/@leafygreen-ui/portal/-/portal-7.0.4.tgz", + "integrity": "sha512-qpxnBlpLzQtP4GCcbTo2M4RYpPuORMjgP+IMJNl2oQAg75DLIIAcRbV5yuMpN1IRsus0fBHykfquSe5UvA13aw==", + "requires": { + "@leafygreen-ui/hooks": "^9.1.3", + "@leafygreen-ui/lib": "^15.3.0" + } + } + } + }, + "@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": "^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" + }, + "dependencies": { + "@leafygreen-ui/lib": { + "version": "15.4.0", + "resolved": "https://registry.npmjs.org/@leafygreen-ui/lib/-/lib-15.4.0.tgz", + "integrity": "sha512-jF6sJ4+rmhvky7Gs8c1wxtOyiYEhu+I+3M5PFi+xFHjNm/tkxjSfjsz18eEccR6M6li8JGVb2o/OU/mbVg0oqQ==", + "requires": { + "lodash": "^4.17.21" + } + } + } + }, + "@leafygreen-ui/typography": { + "version": "22.1.3", + "resolved": "https://registry.npmjs.org/@leafygreen-ui/typography/-/typography-22.1.3.tgz", + "integrity": "sha512-yhQGva/0t2wyJe+edt88Dld1FUyw0xXMrHVegjtTH7c7EiLjG1eD4S+ze/Iz4F7Pxm0wXuxV3ZBrHfx2XqR6mA==", + "requires": { + "@leafygreen-ui/emotion": "^5.0.3", + "@leafygreen-ui/icon": "^14.5.1", + "@leafygreen-ui/lib": "^15.4.0", + "@leafygreen-ui/palette": "^5.0.2", + "@leafygreen-ui/polymorphic": "^3.1.0", + "@leafygreen-ui/tokens": "^3.2.4" + }, + "dependencies": { + "@leafygreen-ui/lib": { + "version": "15.4.0", + "resolved": "https://registry.npmjs.org/@leafygreen-ui/lib/-/lib-15.4.0.tgz", + "integrity": "sha512-jF6sJ4+rmhvky7Gs8c1wxtOyiYEhu+I+3M5PFi+xFHjNm/tkxjSfjsz18eEccR6M6li8JGVb2o/OU/mbVg0oqQ==", + "requires": { + "lodash": "^4.17.21" + } + } + } + }, + "@mongodb-js/diagramming": { + "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": "^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", + "@leafygreen-ui/typography": "^22.1.0", + "@xyflow/react": "12.5.1", + "d3-path": "^3.1.0", + "elkjs": "^0.10.0", + "react": "17.0.2", + "react-dom": "17.0.2" + } + }, "@sinonjs/commons": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.1.tgz", @@ -65759,25 +66154,6 @@ } } }, - "@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==", - "requires": { - "@emotion/react": "^11.14.0", - "@emotion/styled": "^11.14.0", - "@leafygreen-ui/icon": "^13.1.2", - "@leafygreen-ui/leafygreen-provider": "^4.0.2", - "@leafygreen-ui/palette": "^4.1.3", - "@leafygreen-ui/tokens": "^3.2.4", - "@leafygreen-ui/typography": "^20.0.2", - "@xyflow/react": "12.5.1", - "d3-path": "^3.1.0", - "elkjs": "^0.10.0", - "react": "^17.0.2", - "react-dom": "^17.0.2" - } - }, "@mongodb-js/dl-center": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/@mongodb-js/dl-center/-/dl-center-1.3.0.tgz", diff --git a/packages/compass-data-modeling/package.json b/packages/compass-data-modeling/package.json index 6eadcf7c58f..5f39b71a288 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.1", "@mongodb-js/compass-utils": "^0.9.16", "@mongodb-js/compass-workspaces": "^0.59.0", - "@mongodb-js/diagramming": "^1.5.1", + "@mongodb-js/diagramming": "^1.8.0", "bson": "^6.10.4", "compass-preferences-model": "^2.57.0", "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, }; } From 53814be35ae03a0a640c3e177721fa8654e07138 Mon Sep 17 00:00:00 2001 From: Rhys Howell Date: Mon, 29 Sep 2025 04:18:20 -0400 Subject: [PATCH 2/3] feat(data-explorer): COMPASS-9742-add-add-field --- .../src/components/diagram-editor.tsx | 12 +++++ .../src/store/diagram.ts | 32 +++++++++++++ .../src/utils/nodes-and-edges.ts | 47 +++++++++++++++++-- .../compass-data-modeling/src/utils/schema.ts | 18 ++++++- 4 files changed, 102 insertions(+), 7 deletions(-) diff --git a/packages/compass-data-modeling/src/components/diagram-editor.tsx b/packages/compass-data-modeling/src/components/diagram-editor.tsx index 859b11cc8a2..8a3c71ffeac 100644 --- a/packages/compass-data-modeling/src/components/diagram-editor.tsx +++ b/packages/compass-data-modeling/src/components/diagram-editor.tsx @@ -10,6 +10,7 @@ import type { DataModelingState } from '../store/reducer'; import { addNewFieldToCollection, moveCollection, + onAddNestedField, selectCollection, selectRelationship, selectBackground, @@ -131,6 +132,7 @@ const DiagramContent: React.FunctionComponent<{ isInRelationshipDrawingMode: boolean; editErrors?: string[]; newCollection?: string; + onAddFieldToObjectField: (ns: string, parentPath: string[]) => void; onAddNewFieldToCollection: (ns: string) => void; onMoveCollection: (ns: string, newPosition: [number, number]) => void; onCollectionSelect: (namespace: string) => void; @@ -153,6 +155,7 @@ const DiagramContent: React.FunctionComponent<{ model, isInRelationshipDrawingMode, newCollection, + onAddFieldToObjectField, onAddNewFieldToCollection, onMoveCollection, onCollectionSelect, @@ -324,6 +327,13 @@ const DiagramContent: React.FunctionComponent<{ [onAddNewFieldToCollection] ); + const onClickAddFieldToObjectField = useCallback( + (event: React.MouseEvent, nodeId: string, parentPath: string[]) => { + onAddFieldToObjectField(nodeId, parentPath); + }, + [onAddFieldToObjectField] + ); + return (
@@ -384,6 +395,7 @@ const ConnectedDiagramContent = connect( }, { onAddNewFieldToCollection: addNewFieldToCollection, + onAddFieldToObjectField: onAddNestedField, onMoveCollection: moveCollection, onCollectionSelect: selectCollection, onRelationshipSelect: selectRelationship, diff --git a/packages/compass-data-modeling/src/store/diagram.ts b/packages/compass-data-modeling/src/store/diagram.ts index fd41d43b3d7..0be67bcd368 100644 --- a/packages/compass-data-modeling/src/store/diagram.ts +++ b/packages/compass-data-modeling/src/store/diagram.ts @@ -500,6 +500,38 @@ export function redoEdit(): DataModelingThunkAction { }; } +export function onAddNestedField( + ns: string, + parentFieldPath: string[] +): DataModelingThunkAction { + return (dispatch, getState) => { + const modelState = selectCurrentModelFromState(getState()); + + const collection = modelState.collections.find((c) => c.ns === ns); + if (!collection) { + throw new Error('Collection to add field to not found'); + } + + const edit: Omit< + Extract, + 'id' | 'timestamp' + > = { + type: 'AddField', + ns, + // Use the first unique field name we can use. + field: [ + ...parentFieldPath, + getNewUnusedFieldName(collection.jsonSchema, parentFieldPath), + ], + jsonSchema: { + bsonType: 'string', + }, + }; + + return dispatch(applyEdit(edit)); + }; +} + export function addNewFieldToCollection( ns: string ): DataModelingThunkAction { diff --git a/packages/compass-data-modeling/src/utils/nodes-and-edges.ts b/packages/compass-data-modeling/src/utils/nodes-and-edges.ts index 6bc35676c42..64c54018b9e 100644 --- a/packages/compass-data-modeling/src/utils/nodes-and-edges.ts +++ b/packages/compass-data-modeling/src/utils/nodes-and-edges.ts @@ -1,5 +1,10 @@ import toNS from 'mongodb-ns'; -import type { NodeProps, EdgeProps, NodeGlyph } from '@mongodb-js/diagramming'; +import type { + NodeProps, + EdgeProps, + NodeGlyph, + NodeField, +} from '@mongodb-js/diagramming'; import type { MongoDBJSONSchema } from 'mongodb-schema'; import type { SelectedItems } from '../store/diagram'; import type { @@ -33,6 +38,37 @@ export const getHighlightedFields = ( return selection; }; +const getBaseNodeField = (fieldPath: string[]): NodeField => { + return { + name: fieldPath[fieldPath.length - 1], + id: fieldPath, + depth: fieldPath.length - 1, + }; +}; + +/** + * Create the base field list to be used for positioning and measuring in node layouts. + */ +export const getBaseFieldsFromSchema = ({ + jsonSchema, +}: { + jsonSchema: MongoDBJSONSchema; +}): NodeField[] => { + if (!jsonSchema || !jsonSchema.properties) { + return []; + } + const fields: NodeField[] = []; + + traverseSchema({ + jsonSchema, + visitor: ({ fieldPath }) => { + fields.push(getBaseNodeField(fieldPath)); + }, + }); + + return fields; +}; + const KEY_GLYPH: NodeGlyph[] = ['key']; const NO_GLYPH: NodeGlyph[] = []; @@ -54,9 +90,9 @@ export const getFieldsFromSchema = ({ jsonSchema, visitor: ({ fieldPath, fieldTypes }) => { fields.push({ - name: fieldPath[fieldPath.length - 1], - id: fieldPath, + ...getBaseNodeField(fieldPath), type: fieldTypes.length === 1 ? fieldTypes[0] : fieldTypes, + id: fieldPath, depth: fieldPath.length - 1, glyphs: fieldTypes.length === 1 && fieldTypes[0] === 'objectId' @@ -64,7 +100,8 @@ export const getFieldsFromSchema = ({ : NO_GLYPH, selectable: true, selected: - !!selectedField && areFieldPathsEqual(fieldPath, selectedField), + !!selectedField?.length && + areFieldPathsEqual(fieldPath, selectedField), variant: highlightedFields.length && highlightedFields.some((highlightedField) => @@ -96,7 +133,7 @@ export function collectionToBaseNodeForLayout({ x: displayPosition[0], y: displayPosition[1], }, - fields: getFieldsFromSchema({ jsonSchema }), + fields: getBaseFieldsFromSchema({ jsonSchema }), }; } diff --git a/packages/compass-data-modeling/src/utils/schema.ts b/packages/compass-data-modeling/src/utils/schema.ts index 71e6332663f..db545a13b36 100644 --- a/packages/compass-data-modeling/src/utils/schema.ts +++ b/packages/compass-data-modeling/src/utils/schema.ts @@ -1,7 +1,21 @@ import type { MongoDBJSONSchema } from 'mongodb-schema'; -export function getNewUnusedFieldName(jsonSchema: MongoDBJSONSchema): string { - const existingFieldNames = new Set(Object.keys(jsonSchema.properties || {})); +export function getNewUnusedFieldName( + jsonSchema: MongoDBJSONSchema, + parentFieldPath: string[] = [] +): string { + let parentJSONSchema: MongoDBJSONSchema | undefined = jsonSchema; + for (const currentField of parentFieldPath) { + if (!currentField) { + throw new Error('Invalid field path to get new field name'); + } + parentJSONSchema = parentJSONSchema?.properties?.[currentField]; + } + + const existingFieldNames = new Set( + Object.keys(parentJSONSchema?.properties || {}) + ); + let i = 1; let fieldName = `field-${i}`; From 839b752135d82fdd8325c1f237a5a8c1cfe0909e Mon Sep 17 00:00:00 2001 From: Rhys Howell Date: Wed, 1 Oct 2025 12:47:11 +0200 Subject: [PATCH 3/3] fixup: remove duplicate fields --- packages/compass-data-modeling/src/utils/nodes-and-edges.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/compass-data-modeling/src/utils/nodes-and-edges.ts b/packages/compass-data-modeling/src/utils/nodes-and-edges.ts index 1820e87db12..4e9c92bd4d9 100644 --- a/packages/compass-data-modeling/src/utils/nodes-and-edges.ts +++ b/packages/compass-data-modeling/src/utils/nodes-and-edges.ts @@ -91,9 +91,7 @@ export const getFieldsFromSchema = ({ visitor: ({ fieldPath, fieldTypes }) => { fields.push({ ...getBaseNodeField(fieldPath), - id: fieldPath, type: fieldTypes.length === 1 ? fieldTypes[0] : fieldTypes, - depth: fieldPath.length - 1, glyphs: fieldTypes.length === 1 && fieldTypes[0] === 'objectId' ? KEY_GLYPH