From 3fc9e8269b8d071c3ffb1ff55c4f4cddbb35c7fd Mon Sep 17 00:00:00 2001 From: Sergey Petushkov Date: Thu, 21 Dec 2023 18:19:26 +0100 Subject: [PATCH] feat(compass-web): create browser-compatible compass package COMPASS-7413 (#5249) * feat(compass-web): create browser-compatible compass package * chore(workspace): allow opening multiple tabs; handle namespaces in initial tabs * chore(compass-web): add fonts and url handling in the sandbox * chore(sidebar): adjust sidebar to work well in web environment * chore(web): add rest of the plugins * chore(webpack): move emotion server polyfill to the shared config * chore(compass-web): depcheck fixes and very basic test setup * chore: fix depalign * chore(web): skip tests on rhel --- .../@emotion/server/create-instance/index.js | 3 + configs/webpack-config-compass/src/index.ts | 32 + package-lock.json | 1120 ++++++++++++++++- package.json | 2 + .../compass-components-provider.tsx | 10 +- .../src/components/resize-handle.tsx | 14 +- packages/compass-home/src/components/home.tsx | 19 - .../compass-home/src/components/workspace.tsx | 34 +- .../src/components/connection-info-modal.tsx | 2 +- .../src/components/csfle-marker.tsx | 5 +- .../src/components/favorite-indicator.tsx | 22 +- .../src/components/navigation-items.spec.tsx | 38 +- .../src/components/navigation-items.tsx | 54 +- .../src/components/non-genuine-marker.tsx | 5 +- .../src/components/sidebar-title.tsx | 50 +- .../src/components/sidebar.tsx | 94 +- packages/compass-sidebar/src/plugin.tsx | 10 +- packages/compass-web/.depcheckrc | 21 + packages/compass-web/.eslintignore | 2 + packages/compass-web/.eslintrc.js | 8 + packages/compass-web/.mocharc.js | 1 + packages/compass-web/.prettierignore | 3 + packages/compass-web/.prettierrc.json | 1 + packages/compass-web/package.json | 110 ++ .../@mongodb-js/oidc-plugin/index.ts | 21 + .../compass-web/polyfills/crypto/index.ts | 13 + packages/compass-web/polyfills/dns/index.ts | 49 + packages/compass-web/polyfills/fs/index.ts | 12 + packages/compass-web/polyfills/http/index.ts | 17 + .../polyfills/os-dns-native/index.ts | 5 + packages/compass-web/polyfills/os/index.ts | 4 + packages/compass-web/sandbox/index.html | 23 + packages/compass-web/sandbox/index.tsx | 272 ++++ packages/compass-web/src/index.spec.tsx | 103 ++ packages/compass-web/src/index.tsx | 207 +++ packages/compass-web/tsconfig-lint.json | 5 + packages/compass-web/tsconfig.json | 8 + packages/compass-web/webpack.config.js | 167 +++ .../src/components/index.tsx | 31 +- .../src/components/workspaces-provider.tsx | 15 +- .../src/components/workspaces.tsx | 25 +- packages/compass-workspaces/src/index.ts | 50 +- packages/compass-workspaces/src/provider.tsx | 2 + .../src/stores/workspaces.ts | 12 +- 44 files changed, 2479 insertions(+), 222 deletions(-) create mode 100644 configs/webpack-config-compass/polyfills/@emotion/server/create-instance/index.js create mode 100644 packages/compass-web/.depcheckrc create mode 100644 packages/compass-web/.eslintignore create mode 100644 packages/compass-web/.eslintrc.js create mode 100644 packages/compass-web/.mocharc.js create mode 100644 packages/compass-web/.prettierignore create mode 100644 packages/compass-web/.prettierrc.json create mode 100644 packages/compass-web/package.json create mode 100644 packages/compass-web/polyfills/@mongodb-js/oidc-plugin/index.ts create mode 100644 packages/compass-web/polyfills/crypto/index.ts create mode 100644 packages/compass-web/polyfills/dns/index.ts create mode 100644 packages/compass-web/polyfills/fs/index.ts create mode 100644 packages/compass-web/polyfills/http/index.ts create mode 100644 packages/compass-web/polyfills/os-dns-native/index.ts create mode 100644 packages/compass-web/polyfills/os/index.ts create mode 100644 packages/compass-web/sandbox/index.html create mode 100644 packages/compass-web/sandbox/index.tsx create mode 100644 packages/compass-web/src/index.spec.tsx create mode 100644 packages/compass-web/src/index.tsx create mode 100644 packages/compass-web/tsconfig-lint.json create mode 100644 packages/compass-web/tsconfig.json create mode 100644 packages/compass-web/webpack.config.js diff --git a/configs/webpack-config-compass/polyfills/@emotion/server/create-instance/index.js b/configs/webpack-config-compass/polyfills/@emotion/server/create-instance/index.js new file mode 100644 index 00000000000..3bf92c0520b --- /dev/null +++ b/configs/webpack-config-compass/polyfills/@emotion/server/create-instance/index.js @@ -0,0 +1,3 @@ +export default function createEmotionServer() { + return {}; +} diff --git a/configs/webpack-config-compass/src/index.ts b/configs/webpack-config-compass/src/index.ts index c4fa9813501..46328ddc450 100644 --- a/configs/webpack-config-compass/src/index.ts +++ b/configs/webpack-config-compass/src/index.ts @@ -88,6 +88,21 @@ const sharedResolveOptions = ( // KeyObject instances from the Node.js crypto API (https://tinyurl.com/2rrtu2hy). // Manually resolve `jose` to use the Node.js export here. jose: require.resolve('jose'), + + // Leafygreen tries to include all the server-side emotion stuff in the + // client bundle, this requires packaging a ton of otherwise unneccessary + // polyfills.To work around this, we're providing a minimally required + // polyfill for code not to break. This is mostly a problem for our web + // packages, but also not a bad thing at all for the electron app itself. + '@emotion/server/create-instance': path.resolve( + __dirname, + '..', + 'polyfills', + '@emotion', + 'server', + 'create-instance', + 'index.js' + ), }, }; }; @@ -321,6 +336,23 @@ export function createWebConfig(args: Partial): WebpackConfig { ...sharedResolveOptions(opts.target), }, ignoreWarnings: sharedIgnoreWarnings, + plugins: + isServe(opts) && opts.hot + ? [ + // Plugin types are not matching Webpack 5, but they work + new ReactRefreshWebpackPlugin() as unknown as WebpackPluginInstance, + ] + : opts.analyze + ? [ + // Plugin types are not matching Webpack 5, but they work + new BundleAnalyzerPlugin({ + logLevel: 'silent', + analyzerPort: 'auto', + }) as unknown as WebpackPluginInstance, + + new DuplicatePackageCheckerPlugin(), + ] + : [], }; } diff --git a/package-lock.json b/package-lock.json index baa0a464cd5..38b4e837540 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4795,6 +4795,16 @@ "resolved": "https://registry.npmjs.org/@gar/promisify/-/promisify-1.1.3.tgz", "integrity": "sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==" }, + "node_modules/@gribnoysup/mongodb-browser": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@gribnoysup/mongodb-browser/-/mongodb-browser-1.2.0.tgz", + "integrity": "sha512-K662GvGKghNtKcSE0bbJviieJ2dj8pFN+PRQf+a9ACy5dvO2rAzbY8uw+QDgkGnxgvqhWV/QKhyKnxi0JWF6Dw==", + "dev": true, + "peerDependencies": { + "bson": "^6.2.0", + "mongodb": "^6.3.0" + } + }, "node_modules/@hapi/hoek": { "version": "9.2.0", "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-9.2.0.tgz", @@ -6203,10 +6213,45 @@ "@leafygreen-ui/leafygreen-provider": "^3.1.0" } }, + "node_modules/@leichtgewicht/base64-codec": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@leichtgewicht/base64-codec/-/base64-codec-1.0.0.tgz", + "integrity": "sha512-0cgP4lRBzh3F4tlpTfs7F+PJyBN8j5yUC9KrQFWp/bREswgzZVHE8T1rNyRDWgvALwwpPtnJDQfqWUmxI33Epg==", + "dev": true + }, + "node_modules/@leichtgewicht/dns-packet": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/@leichtgewicht/dns-packet/-/dns-packet-6.0.3.tgz", + "integrity": "sha512-qmVHhFBFiBvPsk/wJ/EdoWHb+tGkzY4haybmDPukhF6w0+8wpEbrHTIRE9LzeUu2P0bAbmrK8WOXt5V5QN6jQg==", + "dev": true, + "dependencies": { + "@leichtgewicht/ip-codec": "^2.0.4", + "bytes.js": "^0.0.2", + "utf8-bytes": "^0.0.1", + "utf8-codec": "^1.0.0", + "utf8-length": "^0.0.1", + "utf8-string-bytes": "^1.0.3" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@leichtgewicht/dns-socket": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@leichtgewicht/dns-socket/-/dns-socket-5.0.0.tgz", + "integrity": "sha512-Sbrn/OG0HTTPGSkwIDCHy8/tUI6UglIzFsMNjzZn/Na1/i5owSm6rVi9CfKNNjRcUlYEzICELYW6EoZdjwVY2A==", + "dev": true, + "dependencies": { + "@leichtgewicht/dns-packet": "^6.0.0" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/@leichtgewicht/ip-codec": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.3.tgz", - "integrity": "sha512-nkalE/f1RvRGChwBnEIoBfSEYOXnCRdleKuv6+lePbMDrMZXeDQnqak5XDOeBgrPPyPfAdcCu/B5z+v3VhplGg==" + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.4.tgz", + "integrity": "sha512-Hcv+nVC0kZnQ3tD9GVu5xSMR4VVYOteQIr/hwFPVEvPdlXqgGEuRjiheChHgdM+JyqdgNcmzZOX/tnl0JOiI7A==" }, "node_modules/@lerna/child-process": { "version": "7.1.5", @@ -7867,6 +7912,10 @@ "resolved": "packages/compass-utils", "link": true }, + "node_modules/@mongodb-js/compass-web": { + "resolved": "packages/compass-web", + "link": true + }, "node_modules/@mongodb-js/compass-welcome": { "resolved": "packages/compass-welcome", "link": true @@ -16278,6 +16327,18 @@ "url": "https://opencollective.com/postcss/" } }, + "node_modules/available-typed-arrays": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", + "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/aws-sdk": { "version": "2.934.0", "resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.934.0.tgz", @@ -17571,6 +17632,12 @@ "node": ">= 0.8" } }, + "node_modules/bytes.js": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/bytes.js/-/bytes.js-0.0.2.tgz", + "integrity": "sha512-KrLm4hv5Qs9w6b0U7h1bCdqxrsf+e9QMsfHeyQFzAz94x/5Aqa+FTEUSNBtt5d2VuV3Hfiea3c4ti74RZDDYkg==", + "dev": true + }, "node_modules/cacache": { "version": "15.2.0", "resolved": "https://registry.npmjs.org/cacache/-/cacache-15.2.0.tgz", @@ -17677,12 +17744,13 @@ } }, "node_modules/call-bind": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", - "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.5.tgz", + "integrity": "sha512-C3nQxfFZxFRVoJoGKKI8y3MOEo129NQ+FgQ08iye+Mk4zNZZGdjfs06bVTr+DBSlA66Q2VEcMki/cUCP4SercQ==", "dependencies": { - "function-bind": "^1.1.1", - "get-intrinsic": "^1.0.2" + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.1", + "set-function-length": "^1.1.1" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -19947,6 +20015,19 @@ "node": ">=10" } }, + "node_modules/define-data-property": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.1.tgz", + "integrity": "sha512-E7uGkTzkk1d0ByLeSc6ZsFS79Axg+m1P/VsgYsxHgiuc3tFSj+MjMIwe90FC4lOAZzNBdY7kkO2P2wKdsQ1vgQ==", + "dependencies": { + "get-intrinsic": "^1.2.1", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/define-lazy-prop": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", @@ -20277,6 +20358,22 @@ "node": ">=6" } }, + "node_modules/dns-query": { + "version": "0.11.2", + "resolved": "https://registry.npmjs.org/dns-query/-/dns-query-0.11.2.tgz", + "integrity": "sha512-zF8qxQpqCB467o4A63DLpQClo77H642JEKMx0Ra9GFww7Rx0234Fo8NoG0LBoSBZxamWkXfLxhzDG19bTBHvXQ==", + "dev": true, + "dependencies": { + "@leichtgewicht/base64-codec": "^1.0.0", + "@leichtgewicht/dns-packet": "^6.0.2", + "@leichtgewicht/dns-socket": "^5.0.0", + "@leichtgewicht/ip-codec": "^2.0.4", + "utf8-codec": "^1.0.0" + }, + "bin": { + "dns-query": "bin/dns-query" + } + }, "node_modules/doctrine": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", @@ -24295,6 +24392,15 @@ } } }, + "node_modules/for-each": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", + "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", + "dev": true, + "dependencies": { + "is-callable": "^1.1.3" + } + }, "node_modules/foreground-child": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-2.0.0.tgz", @@ -24523,9 +24629,12 @@ } }, "node_modules/function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, "node_modules/function.prototype.name": { "version": "1.1.4", @@ -25016,13 +25125,14 @@ } }, "node_modules/get-intrinsic": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz", - "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==", + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.2.tgz", + "integrity": "sha512-0gSo4ml/0j98Y3lngkFEot/zhiCeWsbYIlZ+uZOVgzLyLaUw7wxUL+nCTP0XJvJg1AXulJRI3UJi8GsbDuxdGA==", "dependencies": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.1" + "function-bind": "^1.1.2", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "hasown": "^2.0.0" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -25550,6 +25660,17 @@ "delegate": "^3.1.2" } }, + "node_modules/gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "dependencies": { + "get-intrinsic": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/got": { "version": "10.7.0", "resolved": "https://registry.npmjs.org/got/-/got-10.7.0.tgz", @@ -25791,6 +25912,28 @@ "node": ">=8" } }, + "node_modules/has-property-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.1.tgz", + "integrity": "sha512-VsX8eaIewvas0xnvinAe9bw4WfIeODpGYikiWYLH+dma0Jw6KHYqWiWfhQlgOVK8D6PvjubK5Uc4P0iIhIcNVg==", + "dependencies": { + "get-intrinsic": "^1.2.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", + "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/has-symbol-support-x": { "version": "1.4.2", "resolved": "https://registry.npmjs.org/has-symbol-support-x/-/has-symbol-support-x-1.4.2.tgz", @@ -25800,9 +25943,9 @@ } }, "node_modules/has-symbols": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz", - "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", "engines": { "node": ">= 0.4" }, @@ -25821,6 +25964,21 @@ "node": "*" } }, + "node_modules/has-tostringtag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", + "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", + "dev": true, + "dependencies": { + "has-symbols": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/has-unicode": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", @@ -25870,6 +26028,17 @@ "node": ">=8" } }, + "node_modules/hasown": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.0.tgz", + "integrity": "sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/he": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", @@ -26822,6 +26991,22 @@ "resolved": "https://registry.npmjs.org/ipv6-normalize/-/ipv6-normalize-1.0.1.tgz", "integrity": "sha1-GzJYKQ02X6gyOeiZB93kWS52IKg=" }, + "node_modules/is-arguments": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", + "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-arrayish": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", @@ -26849,6 +27034,12 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "dev": true + }, "node_modules/is-callable": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.3.tgz", @@ -26946,6 +27137,21 @@ "resolved": "https://registry.npmjs.org/is-function/-/is-function-1.0.2.tgz", "integrity": "sha512-lw7DUp0aWXYg+CBCN+JKkcE0Q2RayZnSvnZBlwgxHBQhqt5pZNVy4Ri7H9GmmXkdu7LUthszM+Tor1u/2iBcpQ==" }, + "node_modules/is-generator-function": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz", + "integrity": "sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-glob": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", @@ -27222,6 +27428,21 @@ "node": ">=0.10.0" } }, + "node_modules/is-typed-array": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.12.tgz", + "integrity": "sha512-Z14TF2JNG8Lss5/HMqt0//T9JeHXttXy5pH/DBU4vi98ozO2btxzq9MwYDZYnKwU8nRsz/+GVFVRDq3DkVuSPg==", + "dev": true, + "dependencies": { + "which-typed-array": "^1.1.11" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-typedarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", @@ -31181,12 +31402,6 @@ "safe-buffer": "^5.1.2" } }, - "node_modules/md5/node_modules/is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", - "dev": true - }, "node_modules/media-type": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/media-type/-/media-type-0.3.0.tgz", @@ -35146,6 +35361,12 @@ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==" }, + "node_modules/path-browserify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz", + "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==", + "dev": true + }, "node_modules/path-exists": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", @@ -39024,6 +39245,20 @@ "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=" }, + "node_modules/set-function-length": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.1.1.tgz", + "integrity": "sha512-VoaqjbBJKiWtg4yRcKBQ7g7wnGnLV3M8oLvVWwOk2PdYY6PEFegR1vezXR0tw6fZGF9csVakIRjrJiy2veSBFQ==", + "dependencies": { + "define-data-property": "^1.1.1", + "get-intrinsic": "^1.2.1", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/set-immediate-shim": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz", @@ -42274,6 +42509,30 @@ "node": ">=0.10.0" } }, + "node_modules/utf8-bytes": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/utf8-bytes/-/utf8-bytes-0.0.1.tgz", + "integrity": "sha512-GifWmJAx2qAXT+lZLhbkWhBsy7pr6xWHiPWlVToDiELdWgZwt4Ogjf9tlgvKuALzTFR/d+EPQQI9ogJV3957Jg==", + "dev": true + }, + "node_modules/utf8-codec": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/utf8-codec/-/utf8-codec-1.0.0.tgz", + "integrity": "sha512-S/QSLezp3qvG4ld5PUfXiH7mCFxLKjSVZRFkB3DOjgwHuJPFDkInAXc/anf7BAbHt/D38ozDzL+QMZ6/7gsI6w==", + "dev": true + }, + "node_modules/utf8-length": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/utf8-length/-/utf8-length-0.0.1.tgz", + "integrity": "sha512-j/XH2ftofBiobnyApxlN/J6j/ixwT89WEjDcjT66d2i0+GIn9RZfzt8lpEXXE4jUe4NsjBSUq70kS2euQ4nnMw==", + "dev": true + }, + "node_modules/utf8-string-bytes": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/utf8-string-bytes/-/utf8-string-bytes-1.0.3.tgz", + "integrity": "sha512-i/I1Omf6lADjVBlwJpQifZOePV15snHny9w04+lc71+3t8PyWuLC/7clyoOSHOBNGXFe2PAGxmTiZ+Z4HWsPyw==", + "dev": true + }, "node_modules/util": { "version": "0.10.3", "resolved": "https://registry.npmjs.org/util/-/util-0.10.3.tgz", @@ -42365,6 +42624,12 @@ "extsprintf": "^1.2.0" } }, + "node_modules/vm-browserify": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-1.1.2.tgz", + "integrity": "sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==", + "dev": true + }, "node_modules/vscode-windows-registry": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/vscode-windows-registry/-/vscode-windows-registry-1.0.2.tgz", @@ -42766,6 +43031,25 @@ "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", "dev": true }, + "node_modules/which-typed-array": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.13.tgz", + "integrity": "sha512-P5Nra0qjSncduVPEAr7xhoF5guty49ArDTwzJ/yNuPIbZppyRxFQsRCWrocxIY+CnMVG+qfbU2FmDKyvSGClow==", + "dev": true, + "dependencies": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.4", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/why-is-node-running": { "version": "2.2.2", "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.2.2.tgz", @@ -47837,6 +48121,286 @@ "node": ">=0.3.1" } }, + "packages/compass-web": { + "name": "@mongodb-js/compass-web", + "version": "0.1.0", + "license": "SSPL", + "devDependencies": { + "@gribnoysup/mongodb-browser": "^1.2.0", + "@mongodb-js/compass-aggregations": "^9.23.4", + "@mongodb-js/compass-app-stores": "^7.7.5", + "@mongodb-js/compass-collection": "^4.20.5", + "@mongodb-js/compass-components": "^1.20.2", + "@mongodb-js/compass-crud": "^13.21.5", + "@mongodb-js/compass-databases-collections": "^1.20.5", + "@mongodb-js/compass-explain-plan": "^6.21.3", + "@mongodb-js/compass-export-to-language": "^8.22.3", + "@mongodb-js/compass-indexes": "^5.20.3", + "@mongodb-js/compass-query-bar": "^8.22.2", + "@mongodb-js/compass-schema": "^6.22.3", + "@mongodb-js/compass-schema-validation": "^6.21.5", + "@mongodb-js/compass-sidebar": "^5.20.5", + "@mongodb-js/compass-workspaces": "^0.2.5", + "@mongodb-js/eslint-config-compass": "^1.0.12", + "@mongodb-js/mocha-config-compass": "^1.3.3", + "@mongodb-js/prettier-config-compass": "^1.0.1", + "@mongodb-js/tsconfig-compass": "^1.0.3", + "@mongodb-js/webpack-config-compass": "^1.2.7", + "@testing-library/react": "^12.1.4", + "@testing-library/user-event": "^13.5.0", + "@types/chai": "^4.2.21", + "@types/chai-dom": "^0.0.10", + "@types/mocha": "^9.0.0", + "@types/react": "^17.0.5", + "@types/react-dom": "^17.0.10", + "@types/sinon-chai": "^3.2.5", + "buffer": "^6.0.3", + "chai": "^4.3.6", + "depcheck": "^1.4.1", + "dns-query": "^0.11.2", + "eslint": "^7.25.0", + "events": "^3.3.0", + "hadron-app-registry": "^9.1.1", + "mocha": "^10.2.0", + "mongodb-connection-string-url": "^2.6.0", + "mongodb-data-service": "^22.16.2", + "nyc": "^15.1.0", + "path-browserify": "^1.0.1", + "prettier": "^2.7.1", + "process": "^0.11.10", + "readable-stream": "^4.5.0", + "sinon": "^17.0.1", + "util": "^0.12.5", + "vm-browserify": "^1.1.2", + "whatwg-url": "^13.0.0" + }, + "peerDependencies": { + "bson": "^6.2.0", + "mongodb": "^6.3.0", + "react": "^17.0.2", + "react-dom": "^17.0.2" + } + }, + "packages/compass-web/node_modules/@sinonjs/commons": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.0.tgz", + "integrity": "sha512-jXBtWAF4vmdNmZgD5FoKsVLv3rPgDnLgPbU84LIJ3otV44vJlDRokVng5v8NFJdCf/da9legHcKaRuZs4L7faA==", + "dev": true, + "dependencies": { + "type-detect": "4.0.8" + } + }, + "packages/compass-web/node_modules/@sinonjs/fake-timers": { + "version": "11.2.2", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-11.2.2.tgz", + "integrity": "sha512-G2piCSxQ7oWOxwGSAyFHfPIsyeJGXYtc6mFbnFA+kRXkiEnTl8c/8jul2S329iFBnDI9HGoeWWAZvuvOkZccgw==", + "dev": true, + "dependencies": { + "@sinonjs/commons": "^3.0.0" + } + }, + "packages/compass-web/node_modules/@sinonjs/samsam": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-8.0.0.tgz", + "integrity": "sha512-Bp8KUVlLp8ibJZrnvq2foVhP0IVX2CIprMJPK0vqGqgrDa0OHVKeZyBykqskkrdxV6yKBPmGasO8LVjAKR3Gew==", + "dev": true, + "dependencies": { + "@sinonjs/commons": "^2.0.0", + "lodash.get": "^4.4.2", + "type-detect": "^4.0.8" + } + }, + "packages/compass-web/node_modules/@sinonjs/samsam/node_modules/@sinonjs/commons": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-2.0.0.tgz", + "integrity": "sha512-uLa0j859mMrg2slwQYdO/AkrOfmH+X6LTVmNTS9CqexuE2IvVORIkSpJLqePAbEnKJ77aMmCwr1NUZ57120Xcg==", + "dev": true, + "dependencies": { + "type-detect": "4.0.8" + } + }, + "packages/compass-web/node_modules/@types/whatwg-url": { + "version": "11.0.3", + "resolved": "https://registry.npmjs.org/@types/whatwg-url/-/whatwg-url-11.0.3.tgz", + "integrity": "sha512-z1ELvMijRL1QmU7QuzDkeYXSF2+dXI0ITKoQsIoVKcNBOiK5RMmWy+pYYxJTHFt8vkpZe7UsvRErQwcxZkjoUw==", + "dev": true, + "dependencies": { + "@types/webidl-conversions": "*" + } + }, + "packages/compass-web/node_modules/buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "packages/compass-web/node_modules/diff": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.1.0.tgz", + "integrity": "sha512-D+mk+qE8VC/PAUrlAU34N+VfXev0ghe5ywmpqrawphmVZc1bEfn56uo9qpyGp1p4xpzOHkSW4ztBd6L7Xx4ACw==", + "dev": true, + "engines": { + "node": ">=0.3.1" + } + }, + "packages/compass-web/node_modules/events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "dev": true, + "engines": { + "node": ">=0.8.x" + } + }, + "packages/compass-web/node_modules/mongodb-connection-string-url": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/mongodb-connection-string-url/-/mongodb-connection-string-url-3.0.0.tgz", + "integrity": "sha512-t1Vf+m1I5hC2M5RJx/7AtxgABy1cZmIPQRMXw+gEIPn/cZNF3Oiy+l0UIypUwVB5trcWHq3crg2g3uAR9aAwsQ==", + "dev": true, + "dependencies": { + "@types/whatwg-url": "^11.0.2", + "whatwg-url": "^13.0.0" + } + }, + "packages/compass-web/node_modules/nise": { + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/nise/-/nise-5.1.5.tgz", + "integrity": "sha512-VJuPIfUFaXNRzETTQEEItTOP8Y171ijr+JLq42wHes3DiryR8vT+1TXQW/Rx8JNUhyYYWyIvjXTU6dOhJcs9Nw==", + "dev": true, + "dependencies": { + "@sinonjs/commons": "^2.0.0", + "@sinonjs/fake-timers": "^10.0.2", + "@sinonjs/text-encoding": "^0.7.1", + "just-extend": "^4.0.2", + "path-to-regexp": "^1.7.0" + } + }, + "packages/compass-web/node_modules/nise/node_modules/@sinonjs/commons": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-2.0.0.tgz", + "integrity": "sha512-uLa0j859mMrg2slwQYdO/AkrOfmH+X6LTVmNTS9CqexuE2IvVORIkSpJLqePAbEnKJ77aMmCwr1NUZ57120Xcg==", + "dev": true, + "dependencies": { + "type-detect": "4.0.8" + } + }, + "packages/compass-web/node_modules/nise/node_modules/@sinonjs/fake-timers": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.3.0.tgz", + "integrity": "sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==", + "dev": true, + "dependencies": { + "@sinonjs/commons": "^3.0.0" + } + }, + "packages/compass-web/node_modules/nise/node_modules/@sinonjs/fake-timers/node_modules/@sinonjs/commons": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.0.tgz", + "integrity": "sha512-jXBtWAF4vmdNmZgD5FoKsVLv3rPgDnLgPbU84LIJ3otV44vJlDRokVng5v8NFJdCf/da9legHcKaRuZs4L7faA==", + "dev": true, + "dependencies": { + "type-detect": "4.0.8" + } + }, + "packages/compass-web/node_modules/readable-stream": { + "version": "4.5.1", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.5.1.tgz", + "integrity": "sha512-uQjbf34vmf/asGnOHQEw07Q4llgMACQZTWWa4MmICS0IKJoHbLwKCy71H3eR99Dw5iYejc6W+pqZZEeqRtUFAw==", + "dev": true, + "dependencies": { + "abort-controller": "^3.0.0", + "buffer": "^6.0.3", + "events": "^3.3.0", + "process": "^0.11.10", + "string_decoder": "^1.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "packages/compass-web/node_modules/sinon": { + "version": "17.0.1", + "resolved": "https://registry.npmjs.org/sinon/-/sinon-17.0.1.tgz", + "integrity": "sha512-wmwE19Lie0MLT+ZYNpDymasPHUKTaZHUH/pKEubRXIzySv9Atnlw+BUMGCzWgV7b7wO+Hw6f1TEOr0IUnmU8/g==", + "dev": true, + "dependencies": { + "@sinonjs/commons": "^3.0.0", + "@sinonjs/fake-timers": "^11.2.2", + "@sinonjs/samsam": "^8.0.0", + "diff": "^5.1.0", + "nise": "^5.1.5", + "supports-color": "^7.2.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/sinon" + } + }, + "packages/compass-web/node_modules/tr46": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-4.1.1.tgz", + "integrity": "sha512-2lv/66T7e5yNyhAAC4NaKe5nVavzuGJQVVtRYLyQ2OI8tsJ61PMLlelehb0wi2Hx6+hT/OJUWZcw8MjlSRnxvw==", + "dev": true, + "dependencies": { + "punycode": "^2.3.0" + }, + "engines": { + "node": ">=14" + } + }, + "packages/compass-web/node_modules/util": { + "version": "0.12.5", + "resolved": "https://registry.npmjs.org/util/-/util-0.12.5.tgz", + "integrity": "sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==", + "dev": true, + "dependencies": { + "inherits": "^2.0.3", + "is-arguments": "^1.0.4", + "is-generator-function": "^1.0.7", + "is-typed-array": "^1.1.3", + "which-typed-array": "^1.1.2" + } + }, + "packages/compass-web/node_modules/webidl-conversions": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", + "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "packages/compass-web/node_modules/whatwg-url": { + "version": "13.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-13.0.0.tgz", + "integrity": "sha512-9WWbymnqj57+XEuqADHrCJ2eSXzn8WXIW/YSGaZtb2WKAInQ6CHfaUUcTyyver0p8BDg5StLQq8h1vtZuwmOig==", + "dev": true, + "dependencies": { + "tr46": "^4.1.1", + "webidl-conversions": "^7.0.0" + }, + "engines": { + "node": ">=16" + } + }, "packages/compass-welcome": { "name": "@mongodb-js/compass-welcome", "version": "0.20.0", @@ -56345,6 +56909,12 @@ "resolved": "https://registry.npmjs.org/@gar/promisify/-/promisify-1.1.3.tgz", "integrity": "sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==" }, + "@gribnoysup/mongodb-browser": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@gribnoysup/mongodb-browser/-/mongodb-browser-1.2.0.tgz", + "integrity": "sha512-K662GvGKghNtKcSE0bbJviieJ2dj8pFN+PRQf+a9ACy5dvO2rAzbY8uw+QDgkGnxgvqhWV/QKhyKnxi0JWF6Dw==", + "dev": true + }, "@hapi/hoek": { "version": "9.2.0", "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-9.2.0.tgz", @@ -57562,10 +58132,39 @@ "@leafygreen-ui/tokens": "^1.4.1" } }, + "@leichtgewicht/base64-codec": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@leichtgewicht/base64-codec/-/base64-codec-1.0.0.tgz", + "integrity": "sha512-0cgP4lRBzh3F4tlpTfs7F+PJyBN8j5yUC9KrQFWp/bREswgzZVHE8T1rNyRDWgvALwwpPtnJDQfqWUmxI33Epg==", + "dev": true + }, + "@leichtgewicht/dns-packet": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/@leichtgewicht/dns-packet/-/dns-packet-6.0.3.tgz", + "integrity": "sha512-qmVHhFBFiBvPsk/wJ/EdoWHb+tGkzY4haybmDPukhF6w0+8wpEbrHTIRE9LzeUu2P0bAbmrK8WOXt5V5QN6jQg==", + "dev": true, + "requires": { + "@leichtgewicht/ip-codec": "^2.0.4", + "bytes.js": "^0.0.2", + "utf8-bytes": "^0.0.1", + "utf8-codec": "^1.0.0", + "utf8-length": "^0.0.1", + "utf8-string-bytes": "^1.0.3" + } + }, + "@leichtgewicht/dns-socket": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@leichtgewicht/dns-socket/-/dns-socket-5.0.0.tgz", + "integrity": "sha512-Sbrn/OG0HTTPGSkwIDCHy8/tUI6UglIzFsMNjzZn/Na1/i5owSm6rVi9CfKNNjRcUlYEzICELYW6EoZdjwVY2A==", + "dev": true, + "requires": { + "@leichtgewicht/dns-packet": "^6.0.0" + } + }, "@leichtgewicht/ip-codec": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.3.tgz", - "integrity": "sha512-nkalE/f1RvRGChwBnEIoBfSEYOXnCRdleKuv6+lePbMDrMZXeDQnqak5XDOeBgrPPyPfAdcCu/B5z+v3VhplGg==" + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.4.tgz", + "integrity": "sha512-Hcv+nVC0kZnQ3tD9GVu5xSMR4VVYOteQIr/hwFPVEvPdlXqgGEuRjiheChHgdM+JyqdgNcmzZOX/tnl0JOiI7A==" }, "@lerna/child-process": { "version": "7.1.5", @@ -61144,6 +61743,249 @@ } } }, + "@mongodb-js/compass-web": { + "version": "file:packages/compass-web", + "requires": { + "@gribnoysup/mongodb-browser": "^1.2.0", + "@mongodb-js/compass-aggregations": "^9.23.4", + "@mongodb-js/compass-app-stores": "^7.7.5", + "@mongodb-js/compass-collection": "^4.20.5", + "@mongodb-js/compass-components": "^1.20.2", + "@mongodb-js/compass-crud": "^13.21.5", + "@mongodb-js/compass-databases-collections": "^1.20.5", + "@mongodb-js/compass-explain-plan": "^6.21.3", + "@mongodb-js/compass-export-to-language": "^8.22.3", + "@mongodb-js/compass-indexes": "^5.20.3", + "@mongodb-js/compass-query-bar": "^8.22.2", + "@mongodb-js/compass-schema": "^6.22.3", + "@mongodb-js/compass-schema-validation": "^6.21.5", + "@mongodb-js/compass-sidebar": "^5.20.5", + "@mongodb-js/compass-workspaces": "^0.2.5", + "@mongodb-js/eslint-config-compass": "^1.0.12", + "@mongodb-js/mocha-config-compass": "^1.3.3", + "@mongodb-js/prettier-config-compass": "^1.0.1", + "@mongodb-js/tsconfig-compass": "^1.0.3", + "@mongodb-js/webpack-config-compass": "^1.2.7", + "@testing-library/react": "^12.1.4", + "@testing-library/user-event": "^13.5.0", + "@types/chai": "^4.2.21", + "@types/chai-dom": "^0.0.10", + "@types/mocha": "^9.0.0", + "@types/react": "^17.0.5", + "@types/react-dom": "^17.0.10", + "@types/sinon-chai": "^3.2.5", + "buffer": "^6.0.3", + "chai": "^4.3.6", + "depcheck": "^1.4.1", + "dns-query": "^0.11.2", + "eslint": "^7.25.0", + "events": "^3.3.0", + "hadron-app-registry": "^9.1.1", + "mocha": "^10.2.0", + "mongodb-connection-string-url": "^2.6.0", + "mongodb-data-service": "^22.16.2", + "nyc": "^15.1.0", + "path-browserify": "^1.0.1", + "prettier": "^2.7.1", + "process": "^0.11.10", + "readable-stream": "^4.5.0", + "sinon": "^17.0.1", + "util": "^0.12.5", + "vm-browserify": "^1.1.2", + "whatwg-url": "^13.0.0" + }, + "dependencies": { + "@sinonjs/commons": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.0.tgz", + "integrity": "sha512-jXBtWAF4vmdNmZgD5FoKsVLv3rPgDnLgPbU84LIJ3otV44vJlDRokVng5v8NFJdCf/da9legHcKaRuZs4L7faA==", + "dev": true, + "requires": { + "type-detect": "4.0.8" + } + }, + "@sinonjs/fake-timers": { + "version": "11.2.2", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-11.2.2.tgz", + "integrity": "sha512-G2piCSxQ7oWOxwGSAyFHfPIsyeJGXYtc6mFbnFA+kRXkiEnTl8c/8jul2S329iFBnDI9HGoeWWAZvuvOkZccgw==", + "dev": true, + "requires": { + "@sinonjs/commons": "^3.0.0" + } + }, + "@sinonjs/samsam": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-8.0.0.tgz", + "integrity": "sha512-Bp8KUVlLp8ibJZrnvq2foVhP0IVX2CIprMJPK0vqGqgrDa0OHVKeZyBykqskkrdxV6yKBPmGasO8LVjAKR3Gew==", + "dev": true, + "requires": { + "@sinonjs/commons": "^2.0.0", + "lodash.get": "^4.4.2", + "type-detect": "^4.0.8" + }, + "dependencies": { + "@sinonjs/commons": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-2.0.0.tgz", + "integrity": "sha512-uLa0j859mMrg2slwQYdO/AkrOfmH+X6LTVmNTS9CqexuE2IvVORIkSpJLqePAbEnKJ77aMmCwr1NUZ57120Xcg==", + "dev": true, + "requires": { + "type-detect": "4.0.8" + } + } + } + }, + "@types/whatwg-url": { + "version": "11.0.3", + "resolved": "https://registry.npmjs.org/@types/whatwg-url/-/whatwg-url-11.0.3.tgz", + "integrity": "sha512-z1ELvMijRL1QmU7QuzDkeYXSF2+dXI0ITKoQsIoVKcNBOiK5RMmWy+pYYxJTHFt8vkpZe7UsvRErQwcxZkjoUw==", + "dev": true, + "requires": { + "@types/webidl-conversions": "*" + } + }, + "buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "dev": true, + "requires": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "diff": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.1.0.tgz", + "integrity": "sha512-D+mk+qE8VC/PAUrlAU34N+VfXev0ghe5ywmpqrawphmVZc1bEfn56uo9qpyGp1p4xpzOHkSW4ztBd6L7Xx4ACw==", + "dev": true + }, + "events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "dev": true + }, + "mongodb-connection-string-url": { + "version": "https://registry.npmjs.org/mongodb-connection-string-url/-/mongodb-connection-string-url-3.0.0.tgz", + "integrity": "sha512-t1Vf+m1I5hC2M5RJx/7AtxgABy1cZmIPQRMXw+gEIPn/cZNF3Oiy+l0UIypUwVB5trcWHq3crg2g3uAR9aAwsQ==", + "dev": true, + "requires": { + "@types/whatwg-url": "^11.0.2", + "whatwg-url": "^13.0.0" + } + }, + "nise": { + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/nise/-/nise-5.1.5.tgz", + "integrity": "sha512-VJuPIfUFaXNRzETTQEEItTOP8Y171ijr+JLq42wHes3DiryR8vT+1TXQW/Rx8JNUhyYYWyIvjXTU6dOhJcs9Nw==", + "dev": true, + "requires": { + "@sinonjs/commons": "^2.0.0", + "@sinonjs/fake-timers": "^10.0.2", + "@sinonjs/text-encoding": "^0.7.1", + "just-extend": "^4.0.2", + "path-to-regexp": "^1.7.0" + }, + "dependencies": { + "@sinonjs/commons": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-2.0.0.tgz", + "integrity": "sha512-uLa0j859mMrg2slwQYdO/AkrOfmH+X6LTVmNTS9CqexuE2IvVORIkSpJLqePAbEnKJ77aMmCwr1NUZ57120Xcg==", + "dev": true, + "requires": { + "type-detect": "4.0.8" + } + }, + "@sinonjs/fake-timers": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.3.0.tgz", + "integrity": "sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==", + "dev": true, + "requires": { + "@sinonjs/commons": "^3.0.0" + }, + "dependencies": { + "@sinonjs/commons": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.0.tgz", + "integrity": "sha512-jXBtWAF4vmdNmZgD5FoKsVLv3rPgDnLgPbU84LIJ3otV44vJlDRokVng5v8NFJdCf/da9legHcKaRuZs4L7faA==", + "dev": true, + "requires": { + "type-detect": "4.0.8" + } + } + } + } + } + }, + "readable-stream": { + "version": "4.5.1", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.5.1.tgz", + "integrity": "sha512-uQjbf34vmf/asGnOHQEw07Q4llgMACQZTWWa4MmICS0IKJoHbLwKCy71H3eR99Dw5iYejc6W+pqZZEeqRtUFAw==", + "dev": true, + "requires": { + "abort-controller": "^3.0.0", + "buffer": "^6.0.3", + "events": "^3.3.0", + "process": "^0.11.10", + "string_decoder": "^1.3.0" + } + }, + "sinon": { + "version": "17.0.1", + "resolved": "https://registry.npmjs.org/sinon/-/sinon-17.0.1.tgz", + "integrity": "sha512-wmwE19Lie0MLT+ZYNpDymasPHUKTaZHUH/pKEubRXIzySv9Atnlw+BUMGCzWgV7b7wO+Hw6f1TEOr0IUnmU8/g==", + "dev": true, + "requires": { + "@sinonjs/commons": "^3.0.0", + "@sinonjs/fake-timers": "^11.2.2", + "@sinonjs/samsam": "^8.0.0", + "diff": "^5.1.0", + "nise": "^5.1.5", + "supports-color": "^7.2.0" + } + }, + "tr46": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-4.1.1.tgz", + "integrity": "sha512-2lv/66T7e5yNyhAAC4NaKe5nVavzuGJQVVtRYLyQ2OI8tsJ61PMLlelehb0wi2Hx6+hT/OJUWZcw8MjlSRnxvw==", + "dev": true, + "requires": { + "punycode": "^2.3.0" + } + }, + "util": { + "version": "0.12.5", + "resolved": "https://registry.npmjs.org/util/-/util-0.12.5.tgz", + "integrity": "sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "is-arguments": "^1.0.4", + "is-generator-function": "^1.0.7", + "is-typed-array": "^1.1.3", + "which-typed-array": "^1.1.2" + } + }, + "webidl-conversions": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", + "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", + "dev": true + }, + "whatwg-url": { + "version": "13.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-13.0.0.tgz", + "integrity": "sha512-9WWbymnqj57+XEuqADHrCJ2eSXzn8WXIW/YSGaZtb2WKAInQ6CHfaUUcTyyver0p8BDg5StLQq8h1vtZuwmOig==", + "dev": true, + "requires": { + "tr46": "^4.1.1", + "webidl-conversions": "^7.0.0" + } + } + } + }, "@mongodb-js/compass-welcome": { "version": "file:packages/compass-welcome", "requires": { @@ -70781,6 +71623,12 @@ } } }, + "available-typed-arrays": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", + "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==", + "dev": true + }, "aws-sdk": { "version": "2.934.0", "resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.934.0.tgz", @@ -72358,6 +73206,12 @@ "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==" }, + "bytes.js": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/bytes.js/-/bytes.js-0.0.2.tgz", + "integrity": "sha512-KrLm4hv5Qs9w6b0U7h1bCdqxrsf+e9QMsfHeyQFzAz94x/5Aqa+FTEUSNBtt5d2VuV3Hfiea3c4ti74RZDDYkg==", + "dev": true + }, "cacache": { "version": "15.2.0", "resolved": "https://registry.npmjs.org/cacache/-/cacache-15.2.0.tgz", @@ -72442,12 +73296,13 @@ } }, "call-bind": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", - "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.5.tgz", + "integrity": "sha512-C3nQxfFZxFRVoJoGKKI8y3MOEo129NQ+FgQ08iye+Mk4zNZZGdjfs06bVTr+DBSlA66Q2VEcMki/cUCP4SercQ==", "requires": { - "function-bind": "^1.1.1", - "get-intrinsic": "^1.0.2" + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.1", + "set-function-length": "^1.1.1" } }, "callsites": { @@ -74863,6 +75718,16 @@ "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-2.0.1.tgz", "integrity": "sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==" }, + "define-data-property": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.1.tgz", + "integrity": "sha512-E7uGkTzkk1d0ByLeSc6ZsFS79Axg+m1P/VsgYsxHgiuc3tFSj+MjMIwe90FC4lOAZzNBdY7kkO2P2wKdsQ1vgQ==", + "requires": { + "get-intrinsic": "^1.2.1", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.0" + } + }, "define-lazy-prop": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", @@ -75126,6 +75991,19 @@ "@leichtgewicht/ip-codec": "^2.0.1" } }, + "dns-query": { + "version": "0.11.2", + "resolved": "https://registry.npmjs.org/dns-query/-/dns-query-0.11.2.tgz", + "integrity": "sha512-zF8qxQpqCB467o4A63DLpQClo77H642JEKMx0Ra9GFww7Rx0234Fo8NoG0LBoSBZxamWkXfLxhzDG19bTBHvXQ==", + "dev": true, + "requires": { + "@leichtgewicht/base64-codec": "^1.0.0", + "@leichtgewicht/dns-packet": "^6.0.2", + "@leichtgewicht/dns-socket": "^5.0.0", + "@leichtgewicht/ip-codec": "^2.0.4", + "utf8-codec": "^1.0.0" + } + }, "doctrine": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", @@ -78293,6 +79171,15 @@ "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz", "integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==" }, + "for-each": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", + "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", + "dev": true, + "requires": { + "is-callable": "^1.1.3" + } + }, "foreground-child": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-2.0.0.tgz", @@ -78467,9 +79354,9 @@ "optional": true }, "function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==" }, "function.prototype.name": { "version": "1.1.4", @@ -78885,13 +79772,14 @@ "integrity": "sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==" }, "get-intrinsic": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz", - "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==", + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.2.tgz", + "integrity": "sha512-0gSo4ml/0j98Y3lngkFEot/zhiCeWsbYIlZ+uZOVgzLyLaUw7wxUL+nCTP0XJvJg1AXulJRI3UJi8GsbDuxdGA==", "requires": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.1" + "function-bind": "^1.1.2", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "hasown": "^2.0.0" } }, "get-package-info": { @@ -79299,6 +80187,14 @@ "delegate": "^3.1.2" } }, + "gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "requires": { + "get-intrinsic": "^1.1.3" + } + }, "got": { "version": "10.7.0", "resolved": "https://registry.npmjs.org/got/-/got-10.7.0.tgz", @@ -80821,15 +81717,28 @@ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" }, + "has-property-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.1.tgz", + "integrity": "sha512-VsX8eaIewvas0xnvinAe9bw4WfIeODpGYikiWYLH+dma0Jw6KHYqWiWfhQlgOVK8D6PvjubK5Uc4P0iIhIcNVg==", + "requires": { + "get-intrinsic": "^1.2.2" + } + }, + "has-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", + "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==" + }, "has-symbol-support-x": { "version": "1.4.2", "resolved": "https://registry.npmjs.org/has-symbol-support-x/-/has-symbol-support-x-1.4.2.tgz", "integrity": "sha512-3ToOva++HaW+eCpgqZrCfN51IPB+7bJNVT6CUATzueB5Heb8o6Nam0V3HG5dlDvZU1Gn5QLcbahiKw/XVk5JJw==" }, "has-symbols": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz", - "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==" + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==" }, "has-to-string-tag-x": { "version": "1.4.1", @@ -80839,6 +81748,15 @@ "has-symbol-support-x": "^1.4.1" } }, + "has-tostringtag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", + "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", + "dev": true, + "requires": { + "has-symbols": "^1.0.2" + } + }, "has-unicode": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", @@ -80878,6 +81796,14 @@ } } }, + "hasown": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.0.tgz", + "integrity": "sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==", + "requires": { + "function-bind": "^1.1.2" + } + }, "he": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", @@ -81619,6 +82545,16 @@ "resolved": "https://registry.npmjs.org/ipv6-normalize/-/ipv6-normalize-1.0.1.tgz", "integrity": "sha1-GzJYKQ02X6gyOeiZB93kWS52IKg=" }, + "is-arguments": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", + "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + } + }, "is-arrayish": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", @@ -81637,6 +82573,12 @@ "call-bind": "^1.0.2" } }, + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "dev": true + }, "is-callable": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.3.tgz", @@ -81695,6 +82637,15 @@ "resolved": "https://registry.npmjs.org/is-function/-/is-function-1.0.2.tgz", "integrity": "sha512-lw7DUp0aWXYg+CBCN+JKkcE0Q2RayZnSvnZBlwgxHBQhqt5pZNVy4Ri7H9GmmXkdu7LUthszM+Tor1u/2iBcpQ==" }, + "is-generator-function": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz", + "integrity": "sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==", + "dev": true, + "requires": { + "has-tostringtag": "^1.0.0" + } + }, "is-glob": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", @@ -81886,6 +82837,15 @@ "text-extensions": "^1.0.0" } }, + "is-typed-array": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.12.tgz", + "integrity": "sha512-Z14TF2JNG8Lss5/HMqt0//T9JeHXttXy5pH/DBU4vi98ozO2btxzq9MwYDZYnKwU8nRsz/+GVFVRDq3DkVuSPg==", + "dev": true, + "requires": { + "which-typed-array": "^1.1.11" + } + }, "is-typedarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", @@ -85186,14 +86146,6 @@ "charenc": "0.0.2", "crypt": "0.0.2", "is-buffer": "~1.1.6" - }, - "dependencies": { - "is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", - "dev": true - } } }, "md5.js": { @@ -88460,6 +89412,12 @@ } } }, + "path-browserify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz", + "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==", + "dev": true + }, "path-exists": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", @@ -91388,6 +92346,17 @@ "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=" }, + "set-function-length": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.1.1.tgz", + "integrity": "sha512-VoaqjbBJKiWtg4yRcKBQ7g7wnGnLV3M8oLvVWwOk2PdYY6PEFegR1vezXR0tw6fZGF9csVakIRjrJiy2veSBFQ==", + "requires": { + "define-data-property": "^1.1.1", + "get-intrinsic": "^1.2.1", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.0" + } + }, "set-immediate-shim": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz", @@ -93898,6 +94867,30 @@ "os-homedir": "^1.0.0" } }, + "utf8-bytes": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/utf8-bytes/-/utf8-bytes-0.0.1.tgz", + "integrity": "sha512-GifWmJAx2qAXT+lZLhbkWhBsy7pr6xWHiPWlVToDiELdWgZwt4Ogjf9tlgvKuALzTFR/d+EPQQI9ogJV3957Jg==", + "dev": true + }, + "utf8-codec": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/utf8-codec/-/utf8-codec-1.0.0.tgz", + "integrity": "sha512-S/QSLezp3qvG4ld5PUfXiH7mCFxLKjSVZRFkB3DOjgwHuJPFDkInAXc/anf7BAbHt/D38ozDzL+QMZ6/7gsI6w==", + "dev": true + }, + "utf8-length": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/utf8-length/-/utf8-length-0.0.1.tgz", + "integrity": "sha512-j/XH2ftofBiobnyApxlN/J6j/ixwT89WEjDcjT66d2i0+GIn9RZfzt8lpEXXE4jUe4NsjBSUq70kS2euQ4nnMw==", + "dev": true + }, + "utf8-string-bytes": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/utf8-string-bytes/-/utf8-string-bytes-1.0.3.tgz", + "integrity": "sha512-i/I1Omf6lADjVBlwJpQifZOePV15snHny9w04+lc71+3t8PyWuLC/7clyoOSHOBNGXFe2PAGxmTiZ+Z4HWsPyw==", + "dev": true + }, "util": { "version": "0.10.3", "resolved": "https://registry.npmjs.org/util/-/util-0.10.3.tgz", @@ -93978,6 +94971,12 @@ "extsprintf": "^1.2.0" } }, + "vm-browserify": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-1.1.2.tgz", + "integrity": "sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==", + "dev": true + }, "vscode-windows-registry": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/vscode-windows-registry/-/vscode-windows-registry-1.0.2.tgz", @@ -94258,6 +95257,19 @@ "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", "dev": true }, + "which-typed-array": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.13.tgz", + "integrity": "sha512-P5Nra0qjSncduVPEAr7xhoF5guty49ArDTwzJ/yNuPIbZppyRxFQsRCWrocxIY+CnMVG+qfbU2FmDKyvSGClow==", + "dev": true, + "requires": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.4", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.0" + } + }, "why-is-node-running": { "version": "2.2.2", "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.2.2.tgz", diff --git a/package.json b/package.json index 010fba97d20..5f9c2a8e7d0 100644 --- a/package.json +++ b/package.json @@ -29,7 +29,9 @@ "reformat": "lerna run reformat --stream --no-bail", "package-compass": "npm run package-compass --workspace=mongodb-compass --", "prestart": "npm run compile --workspace=@mongodb-js/webpack-config-compass", + "prestart-web": "npm run prestart", "start": "npm run start --workspace=mongodb-compass", + "start-web": "npm run start --workspace=@mongodb-js/compass-web", "test": "lerna run test --concurrency 1 --stream", "test-changed": "lerna run test --stream --concurrency 1 --since origin/HEAD", "test-ci": "lerna run test-ci --concurrency 1", diff --git a/packages/compass-components/src/components/compass-components-provider.tsx b/packages/compass-components/src/components/compass-components-provider.tsx index 07e87849a88..d2a82b30475 100644 --- a/packages/compass-components/src/components/compass-components-provider.tsx +++ b/packages/compass-components/src/components/compass-components-provider.tsx @@ -13,20 +13,12 @@ type CompassComponentsProviderProps = { * value will be derived from the system settings */ darkMode?: boolean; - /** - * Leafygreen provider portalContainer property as a ref - */ - portalContainerRef?: React.RefObject; - /** - * Leafygreen provider scrollContainer property as a ref - */ - scrollContainerRef?: React.RefObject; /** * Either React children or a render callback that will get the darkMode * property passed as function properties */ children?: - | React.ReactChildren + | React.ReactNode | (({ darkMode, }: { diff --git a/packages/compass-components/src/components/resize-handle.tsx b/packages/compass-components/src/components/resize-handle.tsx index 49b13f76f0a..4236ad5b6af 100644 --- a/packages/compass-components/src/components/resize-handle.tsx +++ b/packages/compass-components/src/components/resize-handle.tsx @@ -8,6 +8,7 @@ enum ResizeDirection { } const baseResizerStyles = css({ + all: 'unset', position: 'absolute', background: 'transparent', padding: 0, @@ -17,18 +18,22 @@ const baseResizerStyles = css({ opacity: '0', outline: 'none', zIndex: 100, - ':focus': { + '&:focus': { opacity: 1, }, - ':hover': { + '&:hover': { transitionDelay: '250ms', opacity: 1, }, WebkitAppearance: 'none', - '::-webkit-slider-thumb': { + '&::-moz-range-thumb': { + width: 0, + height: 0, + }, + '&::-webkit-slider-thumb': { WebkitAppearance: 'none', }, - '::-ms-track': { + '&::-ms-track': { background: 'none', borderColor: 'none', color: 'none', @@ -36,6 +41,7 @@ const baseResizerStyles = css({ }); const verticalResizerStyle = css({ + height: '100%', width: '4px !important', right: '-2px', bottom: 0, diff --git a/packages/compass-home/src/components/home.tsx b/packages/compass-home/src/components/home.tsx index 66332f67132..4bfedf6357d 100644 --- a/packages/compass-home/src/components/home.tsx +++ b/packages/compass-home/src/components/home.tsx @@ -33,14 +33,7 @@ import updateTitle from '../modules/update-title'; import Workspace from './workspace'; import { AtlasSignIn } from '@mongodb-js/atlas-service/renderer'; import { CompassSettingsPlugin } from '@mongodb-js/compass-settings'; -import { CreateViewPlugin } from '@mongodb-js/compass-aggregations'; import { CompassFindInPagePlugin } from '@mongodb-js/compass-find-in-page'; -import { - CreateNamespacePlugin, - DropNamespacePlugin, - RenameCollectionPlugin, -} from '@mongodb-js/compass-databases-collections'; -import { ImportPlugin, ExportPlugin } from '@mongodb-js/compass-import-export'; import { DataServiceProvider } from 'mongodb-data-service/provider'; import { CompassInstanceStorePlugin } from '@mongodb-js/compass-app-stores'; import type { WorkspaceTab } from '@mongodb-js/compass-workspaces'; @@ -332,18 +325,6 @@ function Home({ { - return ( - <> - - - - - - - - ); - }} /> diff --git a/packages/compass-home/src/components/workspace.tsx b/packages/compass-home/src/components/workspace.tsx index e1fac9f433f..e934d7974cd 100644 --- a/packages/compass-home/src/components/workspace.tsx +++ b/packages/compass-home/src/components/workspace.tsx @@ -2,12 +2,10 @@ import React from 'react'; import { css } from '@mongodb-js/compass-components'; import type { ConnectionInfo } from '@mongodb-js/connection-storage/renderer'; import { CompassShellPlugin } from '@mongodb-js/compass-shell'; -import { CompassSchemaValidationPlugin } from '@mongodb-js/compass-schema-validation'; import { WorkspaceTab as CollectionWorkspace, CollectionTabsProvider, } from '@mongodb-js/compass-collection'; -import { CompassAggregationsPlugin } from '@mongodb-js/compass-aggregations'; import WorkspacesPlugin, { WorkspacesProvider, } from '@mongodb-js/compass-workspaces'; @@ -17,11 +15,20 @@ import { DatabasesWorkspaceTab, CollectionsWorkspaceTab, } from '@mongodb-js/compass-databases-collections'; -import { CompassDocumentsPlugin } from '@mongodb-js/compass-crud'; import { CompassSidebarPlugin } from '@mongodb-js/compass-sidebar'; -import { CompassIndexesPlugin } from '@mongodb-js/compass-indexes'; -import { CompassSchemaPlugin } from '@mongodb-js/compass-schema'; import CompassQueryBarPlugin from '@mongodb-js/compass-query-bar'; +import { CompassDocumentsPlugin } from '@mongodb-js/compass-crud'; +import { CompassAggregationsPlugin } from '@mongodb-js/compass-aggregations'; +import { CompassSchemaPlugin } from '@mongodb-js/compass-schema'; +import { CompassIndexesPlugin } from '@mongodb-js/compass-indexes'; +import { CompassSchemaValidationPlugin } from '@mongodb-js/compass-schema-validation'; +import { CreateViewPlugin } from '@mongodb-js/compass-aggregations'; +import { + CreateNamespacePlugin, + DropNamespacePlugin, + RenameCollectionPlugin, +} from '@mongodb-js/compass-databases-collections'; +import { ImportPlugin, ExportPlugin } from '@mongodb-js/compass-import-export'; const verticalSplitStyles = css({ width: '100vw', @@ -39,13 +46,11 @@ const shellContainerStyles = css({ export default function Workspace({ connectionInfo, onActiveWorkspaceTabChange, - renderModals, }: { connectionInfo: ConnectionInfo | null | undefined; onActiveWorkspaceTabChange: React.ComponentProps< typeof WorkspacesPlugin >['onActiveWorkspaceTabChange']; - renderModals?: () => React.ReactElement; }): React.ReactElement { return (
@@ -69,7 +74,7 @@ export default function Workspace({ queryBar={CompassQueryBarPlugin} > { return ( @@ -78,7 +83,18 @@ export default function Workspace({ /> ); }} - renderModals={renderModals} + renderModals={() => { + return ( + <> + + + + + + + + ); + }} > diff --git a/packages/compass-sidebar/src/components/connection-info-modal.tsx b/packages/compass-sidebar/src/components/connection-info-modal.tsx index 53cb62bb652..d4d3cfb0d09 100644 --- a/packages/compass-sidebar/src/components/connection-info-modal.tsx +++ b/packages/compass-sidebar/src/components/connection-info-modal.tsx @@ -170,7 +170,7 @@ function getClusterInfo({ instance }: InfoParameters): ConnectionInfo { break; default: - clusterType = ServerType.humanize(servers[0].type); + clusterType = ServerType.humanize(servers[0]?.type ?? 'Unknown'); break; } diff --git a/packages/compass-sidebar/src/components/csfle-marker.tsx b/packages/compass-sidebar/src/components/csfle-marker.tsx index 4e8aff071b2..b16be4a8982 100644 --- a/packages/compass-sidebar/src/components/csfle-marker.tsx +++ b/packages/compass-sidebar/src/components/csfle-marker.tsx @@ -10,10 +10,13 @@ import { } from '@mongodb-js/compass-components'; const badgeContainerStyles = css({ - padding: `0 ${spacing[3]}px ${spacing[2]}px`, + lineHeight: 1, + paddingLeft: spacing[3], + paddingRight: spacing[3], }); const badgeButtonStyles = css({ + all: 'unset', background: 'inherit', padding: 0, margin: 0, diff --git a/packages/compass-sidebar/src/components/favorite-indicator.tsx b/packages/compass-sidebar/src/components/favorite-indicator.tsx index db0d66e2b53..594cae930dc 100644 --- a/packages/compass-sidebar/src/components/favorite-indicator.tsx +++ b/packages/compass-sidebar/src/components/favorite-indicator.tsx @@ -5,19 +5,23 @@ import { useConnectionColor } from '@mongodb-js/connection-form'; import { css, spacing } from '@mongodb-js/compass-components'; +const favoriteCSS = css({ + height: spacing[2], +}); + export default function FavoriteIndicator({ - favorite, + favoriteColor, }: { - favorite: ConnectionFavoriteOptions; + favoriteColor: ConnectionFavoriteOptions['color']; }) { const { connectionColorToHex } = useConnectionColor(); - const favoriteColorHex = connectionColorToHex(favorite.color) ?? ''; - - const favoriteCSS = css({ - backgroundColor: favoriteColorHex || 'transparent', - height: spacing[2], - }); + const favoriteColorHex = connectionColorToHex(favoriteColor) ?? 'transparent'; - return
; + return ( +
+ ); } diff --git a/packages/compass-sidebar/src/components/navigation-items.spec.tsx b/packages/compass-sidebar/src/components/navigation-items.spec.tsx index 8b0e43b95b7..659f0c11990 100644 --- a/packages/compass-sidebar/src/components/navigation-items.spec.tsx +++ b/packages/compass-sidebar/src/components/navigation-items.spec.tsx @@ -7,6 +7,7 @@ import thunk from 'redux-thunk'; import reducer from '../modules'; import { NavigationItems } from './navigation-items'; +import { WorkspacesProvider } from '@mongodb-js/compass-workspaces'; function renderNavigationItems( props?: Partial> @@ -14,21 +15,28 @@ function renderNavigationItems( const store = createStore(reducer, applyMiddleware(thunk)); return render( - { - /* noop */ - }} - showCreateDatabaseAction={true} - isPerformanceTabSupported={true} - onFilterChange={() => { - /* noop */ - }} - currentLocation={null} - currentNamespace={null} - {...props} - /> + null }, + { name: 'Performance', component: () => null }, + ]} + > + { + /* noop */ + }} + showCreateDatabaseAction={true} + isPerformanceTabSupported={true} + onFilterChange={() => { + /* noop */ + }} + currentLocation={null} + currentNamespace={null} + {...props} + /> + ); } diff --git a/packages/compass-sidebar/src/components/navigation-items.tsx b/packages/compass-sidebar/src/components/navigation-items.tsx index cec524caa16..4689ae66a89 100644 --- a/packages/compass-sidebar/src/components/navigation-items.tsx +++ b/packages/compass-sidebar/src/components/navigation-items.tsx @@ -24,7 +24,10 @@ import DatabaseCollectionFilter from './database-collection-filter'; import SidebarDatabasesNavigation from './sidebar-databases-navigation'; import { changeFilterRegex } from '../modules/databases'; import type { RootState } from '../modules'; -import { useOpenWorkspace } from '@mongodb-js/compass-workspaces/provider'; +import { + useOpenWorkspace, + useWorkspacePlugins, +} from '@mongodb-js/compass-workspaces/provider'; type DatabasesActions = 'open-create-database' | 'refresh-databases'; @@ -274,6 +277,7 @@ export function NavigationItems({ openPerformanceWorkspace, openDatabasesWorkspace, } = useOpenWorkspace(); + const { hasWorkspacePlugin } = useWorkspacePlugins(); const databasesActions = useMemo(() => { const actions: ItemAction[] = [ @@ -303,8 +307,12 @@ export function NavigationItems({ return ( shouldRender && ( <> - - + {hasWorkspacePlugin('My Queries') && ( + + )} + {hasWorkspacePlugin('Performance') && ( + + )} ) @@ -314,24 +322,28 @@ export function NavigationItems({ return ( shouldRender && ( <> - - isExpanded={isExpanded} - onAction={onAction} - onClick={openMyQueriesWorkspace} - glyph="CurlyBraces" - label="My Queries" - isActive={currentLocation === 'My Queries'} - /> - - isExpanded={isExpanded} - onAction={onAction} - onClick={openPerformanceWorkspace} - glyph="Gauge" - label="Performance" - isActive={currentLocation === 'Performance'} - disabled={!isPerformanceTabSupported} - disabledMessage="Performance metrics are not available for your deployment or to your database user" - /> + {hasWorkspacePlugin('My Queries') && ( + + isExpanded={isExpanded} + onAction={onAction} + onClick={openMyQueriesWorkspace} + glyph="CurlyBraces" + label="My Queries" + isActive={currentLocation === 'My Queries'} + /> + )} + {hasWorkspacePlugin('Performance') && ( + + isExpanded={isExpanded} + onAction={onAction} + onClick={openPerformanceWorkspace} + glyph="Gauge" + label="Performance" + isActive={currentLocation === 'Performance'} + disabled={!isPerformanceTabSupported} + disabledMessage="Performance metrics are not available for your deployment or to your database user" + /> + )} isExpanded={isExpanded} onAction={onAction} diff --git a/packages/compass-sidebar/src/components/non-genuine-marker.tsx b/packages/compass-sidebar/src/components/non-genuine-marker.tsx index a155a75bb32..1ba8789312f 100644 --- a/packages/compass-sidebar/src/components/non-genuine-marker.tsx +++ b/packages/compass-sidebar/src/components/non-genuine-marker.tsx @@ -11,10 +11,13 @@ import { } from '@mongodb-js/compass-components'; const nonGenuineMarkerContainer = css({ - padding: `0 ${spacing[3]}px ${spacing[2]}px`, + lineHeight: 1, + paddingLeft: spacing[3], + paddingRight: spacing[3], }); const nonGenuineMarkerButton = css({ + all: 'unset', background: 'inherit', padding: 0, margin: 0, diff --git a/packages/compass-sidebar/src/components/sidebar-title.tsx b/packages/compass-sidebar/src/components/sidebar-title.tsx index e252f1fa4fa..4c2c1b74c8e 100644 --- a/packages/compass-sidebar/src/components/sidebar-title.tsx +++ b/packages/compass-sidebar/src/components/sidebar-title.tsx @@ -8,10 +8,12 @@ import { spacing, ItemActionControls, useDarkMode, + useDefaultAction, } from '@mongodb-js/compass-components'; import type { ItemAction } from '@mongodb-js/compass-components'; import { useOpenWorkspace } from '@mongodb-js/compass-workspaces/provider'; +import FavoriteIndicator from './favorite-indicator'; type Action = | 'copy-connection-string' @@ -94,11 +96,13 @@ const iconButtonStyle = css({ function SidebarTitle({ title, isFavorite, + favoriteColor, onAction, isExpanded = false, }: { title: string; isFavorite: boolean; + favoriteColor?: string; isExpanded?: boolean; onAction(actionName: Action, ...rest: any[]): void; }) { @@ -144,28 +148,34 @@ function SidebarTitle({ } }, [isExpanded, onAction, openMyQueriesWorkspace]); + const defaultActionProps = useDefaultAction(onClick); + return ( - // eslint-disable-next-line jsx-a11y/click-events-have-key-events, jsx-a11y/no-static-element-interactions -
- - {isExpanded && {title}} - {isExpanded && ( - - onAction={onAction} - iconSize="small" - actions={actions} - data-testid="sidebar-title-actions" - iconClassName={cx( - iconButtonStyle, - darkMode ? iconButtonDark : iconButtonLight - )} - > + <> +
+ + {isExpanded && {title}} + {isExpanded && ( + + onAction={onAction} + iconSize="small" + actions={actions} + data-testid="sidebar-title-actions" + iconClassName={cx( + iconButtonStyle, + darkMode ? iconButtonDark : iconButtonLight + )} + > + )} +
+ {isFavorite && favoriteColor && ( + )} -
+ ); } diff --git a/packages/compass-sidebar/src/components/sidebar.tsx b/packages/compass-sidebar/src/components/sidebar.tsx index d6ebfaf9c0a..0b1d2d80385 100644 --- a/packages/compass-sidebar/src/components/sidebar.tsx +++ b/packages/compass-sidebar/src/components/sidebar.tsx @@ -13,7 +13,6 @@ import { globalAppRegistryEmit } from '@mongodb-js/mongodb-redux-common/app-regi import { SaveConnectionModal } from '@mongodb-js/connection-form'; import SidebarTitle from './sidebar-title'; -import FavoriteIndicator from './favorite-indicator'; import NavigationItems from './navigation-items'; import ConnectionInfoModal from './connection-info-modal'; import NonGenuineWarningModal from './non-genuine-warning-modal'; @@ -30,13 +29,39 @@ import type { RootState } from '../modules'; const TOAST_TIMEOUT_MS = 5000; // 5 seconds. -// NOTE: This covers both the typical case where we have no badges and the case where we do. -const badgesPlaceholderStyles = css({ - paddingTop: spacing[3], +const sidebarStyles = css({ + // Sidebar internally has z-indexes higher than zero. We set zero on the + // container so that the sidebar doesn't stick out in the layout z ordering + // with other parts of the app + zIndex: 0, +}); + +const connectionInfoContainerStyles = css({}); + +const connectionBadgesContainerStyles = css({ + display: 'grid', + gridTemplateColumns: '100%', + gridTemplateRows: 'auto', + gap: spacing[2], + marginTop: spacing[3], + '&:empty': { + display: 'none', + }, +}); + +const navigationItemsContainerStyles = css({ + display: 'flex', + flexDirection: 'column', + flex: 1, + marginTop: spacing[2], + '&:first-child': { + marginTop: 2, + }, }); // eslint-disable-next-line no-empty-pattern export function Sidebar({ + showConnectionInfo = true, activeWorkspace, isExpanded, connectionInfo, @@ -49,6 +74,7 @@ export function Sidebar({ isGenuine, csfleMode, }: { + showConnectionInfo?: boolean; activeWorkspace: { type: string; namespace?: string } | null; isExpanded: boolean; connectionInfo: Omit & Partial; @@ -153,40 +179,44 @@ export function Sidebar({ expanded={isExpanded} setExpanded={setIsExpanded} data-testid="navigation-sidebar" + className={sidebarStyles} > <> - - {connectionInfo.favorite && ( - + {showConnectionInfo && ( +
+ +
+ {isExpanded && ( + + )} + {isExpanded && ( + + )} +
+
)} -
- {isExpanded && ( - - )} - {isExpanded && ( - - )} +
+
- - = () => { +const SidebarPlugin: React.FunctionComponent = ({ + showConnectionInfo, +}) => { const activeWorkspace = useActiveWorkspace(); return ( = () => { ); }} > - + ); }; diff --git a/packages/compass-web/.depcheckrc b/packages/compass-web/.depcheckrc new file mode 100644 index 00000000000..9c46b1934ab --- /dev/null +++ b/packages/compass-web/.depcheckrc @@ -0,0 +1,21 @@ +ignores: + - '@mongodb-js/prettier-config-compass' + - '@mongodb-js/tsconfig-compass' + - '@types/chai' + - '@types/sinon-chai' + - 'sinon' + - '@testing-library/user-event' + - '@types/chai-dom' + - '@types/react' + - '@types/react-dom' +# Used in webpack config as polyfills, depcheck can't detect that because of `/` +# at the end of require + - 'buffer' + - 'events' + - 'process' + - 'util' +# Already a dependency of mongodb-data-service -> devtools-connect, only +# referenced in webpack for weird polyfilling reasons (see config) + - 'resolve-mongodb-srv' +ignore-patterns: + - 'dist' diff --git a/packages/compass-web/.eslintignore b/packages/compass-web/.eslintignore new file mode 100644 index 00000000000..85a8a75e68c --- /dev/null +++ b/packages/compass-web/.eslintignore @@ -0,0 +1,2 @@ +.nyc-output +dist diff --git a/packages/compass-web/.eslintrc.js b/packages/compass-web/.eslintrc.js new file mode 100644 index 00000000000..e4cf824b6ac --- /dev/null +++ b/packages/compass-web/.eslintrc.js @@ -0,0 +1,8 @@ +module.exports = { + root: true, + extends: ['@mongodb-js/eslint-config-compass'], + parserOptions: { + tsconfigRootDir: __dirname, + project: ['./tsconfig-lint.json'], + }, +}; diff --git a/packages/compass-web/.mocharc.js b/packages/compass-web/.mocharc.js new file mode 100644 index 00000000000..a7e53abc444 --- /dev/null +++ b/packages/compass-web/.mocharc.js @@ -0,0 +1 @@ +module.exports = require('@mongodb-js/mocha-config-compass/compass-plugin'); diff --git a/packages/compass-web/.prettierignore b/packages/compass-web/.prettierignore new file mode 100644 index 00000000000..4d28df6603a --- /dev/null +++ b/packages/compass-web/.prettierignore @@ -0,0 +1,3 @@ +.nyc_output +dist +coverage diff --git a/packages/compass-web/.prettierrc.json b/packages/compass-web/.prettierrc.json new file mode 100644 index 00000000000..18853d1532e --- /dev/null +++ b/packages/compass-web/.prettierrc.json @@ -0,0 +1 @@ +"@mongodb-js/prettier-config-compass" diff --git a/packages/compass-web/package.json b/packages/compass-web/package.json new file mode 100644 index 00000000000..1e45d12829f --- /dev/null +++ b/packages/compass-web/package.json @@ -0,0 +1,110 @@ +{ + "name": "@mongodb-js/compass-web", + "productName": "compass-web Plugin", + "description": "Compass application packaged for the browser environment", + "author": { + "name": "MongoDB Inc", + "email": "compass@mongodb.com" + }, + "publishConfig": { + "access": "public" + }, + "bugs": { + "url": "https://jira.mongodb.org/projects/COMPASS/issues", + "email": "compass@mongodb.com" + }, + "homepage": "https://github.com/mongodb-js/compass", + "version": "0.1.0", + "repository": { + "type": "git", + "url": "https://github.com/mongodb-js/compass.git" + }, + "files": [ + "dist" + ], + "license": "SSPL", + "main": "dist/index.js", + "compass:main": "src/index.ts", + "exports": { + ".": "./dist/index.js" + }, + "compass:exports": { + ".": "./src/index.ts" + }, + "types": "./dist/src/index.d.ts", + "scripts": { + "prepublishOnly": "npm run compile && compass-scripts check-exports-exist", + "compile": "npm run webpack -- --mode production", + "webpack": "webpack-compass", + "postcompile": "tsc --emitDeclarationOnly", + "start": "npm run webpack serve -- --mode development", + "analyze": "npm run webpack -- --mode production --analyze", + "typecheck": "tsc -p tsconfig-lint.json --noEmit", + "eslint": "eslint", + "prettier": "prettier", + "lint": "npm run eslint . && npm run prettier -- --check .", + "depcheck": "depcheck", + "check": "npm run typecheck && npm run lint && npm run depcheck", + "check-ci": "npm run check", + "test": "mocha", + "test-cov": "nyc --compact=false --produce-source-map=false -x \"**/*.spec.*\" --reporter=lcov --reporter=text --reporter=html npm run test", + "test-watch": "npm run test -- --watch", + "test-ci": "npm run test-cov", + "reformat": "npm run eslint . -- --fix && npm run prettier -- --write ." + }, + "peerDependencies": { + "bson": "^6.2.0", + "mongodb": "^6.3.0", + "react": "^17.0.2", + "react-dom": "^17.0.2" + }, + "devDependencies": { + "@gribnoysup/mongodb-browser": "^1.2.0", + "@mongodb-js/compass-aggregations": "^9.23.4", + "@mongodb-js/compass-app-stores": "^7.7.5", + "@mongodb-js/compass-collection": "^4.20.5", + "@mongodb-js/compass-components": "^1.20.2", + "@mongodb-js/compass-crud": "^13.21.5", + "@mongodb-js/compass-databases-collections": "^1.20.5", + "@mongodb-js/compass-explain-plan": "^6.21.3", + "@mongodb-js/compass-export-to-language": "^8.22.3", + "@mongodb-js/compass-indexes": "^5.20.3", + "@mongodb-js/compass-query-bar": "^8.22.2", + "@mongodb-js/compass-schema": "^6.22.3", + "@mongodb-js/compass-schema-validation": "^6.21.5", + "@mongodb-js/compass-sidebar": "^5.20.5", + "@mongodb-js/compass-workspaces": "^0.2.5", + "@mongodb-js/eslint-config-compass": "^1.0.12", + "@mongodb-js/mocha-config-compass": "^1.3.3", + "@mongodb-js/prettier-config-compass": "^1.0.1", + "@mongodb-js/tsconfig-compass": "^1.0.3", + "@mongodb-js/webpack-config-compass": "^1.2.7", + "@testing-library/react": "^12.1.4", + "@testing-library/user-event": "^13.5.0", + "@types/chai": "^4.2.21", + "@types/chai-dom": "^0.0.10", + "@types/mocha": "^9.0.0", + "@types/react": "^17.0.5", + "@types/react-dom": "^17.0.10", + "@types/sinon-chai": "^3.2.5", + "buffer": "^6.0.3", + "chai": "^4.3.6", + "depcheck": "^1.4.1", + "dns-query": "^0.11.2", + "eslint": "^7.25.0", + "events": "^3.3.0", + "hadron-app-registry": "^9.1.1", + "mocha": "^10.2.0", + "mongodb-connection-string-url": "^2.6.0", + "mongodb-data-service": "^22.16.2", + "nyc": "^15.1.0", + "path-browserify": "^1.0.1", + "prettier": "^2.7.1", + "process": "^0.11.10", + "readable-stream": "^4.5.0", + "sinon": "^17.0.1", + "util": "^0.12.5", + "vm-browserify": "^1.1.2", + "whatwg-url": "^13.0.0" + } +} diff --git a/packages/compass-web/polyfills/@mongodb-js/oidc-plugin/index.ts b/packages/compass-web/polyfills/@mongodb-js/oidc-plugin/index.ts new file mode 100644 index 00000000000..c7858314de8 --- /dev/null +++ b/packages/compass-web/polyfills/@mongodb-js/oidc-plugin/index.ts @@ -0,0 +1,21 @@ +export function createMongoDBOIDCPlugin() { + return { + logger: { + on() { + // noop + }, + off() { + // noop + }, + once() { + // noop + }, + addListener() { + // noop + }, + removeListener() { + // noop + }, + }, + }; +} diff --git a/packages/compass-web/polyfills/crypto/index.ts b/packages/compass-web/polyfills/crypto/index.ts new file mode 100644 index 00000000000..df3b1efc117 --- /dev/null +++ b/packages/compass-web/polyfills/crypto/index.ts @@ -0,0 +1,13 @@ +/* global crypto */ +export function randomBytes( + n: number, + cb: (err: any | null, res?: Buffer) => void +): Buffer | void { + const vals = crypto.getRandomValues(new Uint32Array(n)); + if (cb) { + cb(null, Buffer.from(vals)); + return; + } + return Buffer.from(vals); +} +export default { randomBytes }; diff --git a/packages/compass-web/polyfills/dns/index.ts b/packages/compass-web/polyfills/dns/index.ts new file mode 100644 index 00000000000..af38da49fe0 --- /dev/null +++ b/packages/compass-web/polyfills/dns/index.ts @@ -0,0 +1,49 @@ +import { query, wellknown, lookupTxt } from 'dns-query'; +import { promisify } from 'util'; +export function resolveSrv( + hostname: string, + cb: (err: any | null, res?: any) => void +) { + query( + { question: { type: 'SRV', name: hostname } }, + { endpoints: wellknown.endpoints('doh') } + ).then(({ answers }) => { + cb( + null, + answers?.flatMap((answer) => { + if (answer.type !== 'SRV') { + return []; + } + return { + ...answer.data, + name: answer.data.target, + }; + }) + ); + }, cb); +} +export function resolveTxt( + hostname: string, + cb: (err: any | null, res?: any) => void +) { + lookupTxt(hostname, { endpoints: wellknown.endpoints('doh') }).then( + ({ entries }) => { + cb( + null, + entries.map((entry) => { + return [entry.data]; + }) + ); + }, + cb + ); +} +export const promises = { + resolveSrv: promisify(resolveSrv), + resolveTxt: promisify(resolveTxt), +}; +export default { + resolveSrv, + resolveTxt, + promises, +}; diff --git a/packages/compass-web/polyfills/fs/index.ts b/packages/compass-web/polyfills/fs/index.ts new file mode 100644 index 00000000000..4c6c7ce18f6 --- /dev/null +++ b/packages/compass-web/polyfills/fs/index.ts @@ -0,0 +1,12 @@ +export const promises = { + chmod() { + return Promise.resolve(); + }, +}; +export function rmSync() { + // noop +} +export function readFileSync() { + // noop +} +export default { promises, rmSync, readFileSync }; diff --git a/packages/compass-web/polyfills/http/index.ts b/packages/compass-web/polyfills/http/index.ts new file mode 100644 index 00000000000..9558f9f4285 --- /dev/null +++ b/packages/compass-web/polyfills/http/index.ts @@ -0,0 +1,17 @@ +import { EventEmitter } from 'events'; +class Server extends EventEmitter { + listen() { + queueMicrotask(() => { + this.emit('listening'); + }); + } + address() { + return null; + } + close() { + // noop + } +} +export function createServer() { + return new Server(); +} diff --git a/packages/compass-web/polyfills/os-dns-native/index.ts b/packages/compass-web/polyfills/os-dns-native/index.ts new file mode 100644 index 00000000000..5dbd57c902f --- /dev/null +++ b/packages/compass-web/polyfills/os-dns-native/index.ts @@ -0,0 +1,5 @@ +import { resolveSrv, resolveTxt } from 'dns'; +export const withNodeFallback = { resolveSrv, resolveTxt }; +export function wasNativelyLookedUp() { + return false; +} diff --git a/packages/compass-web/polyfills/os/index.ts b/packages/compass-web/polyfills/os/index.ts new file mode 100644 index 00000000000..359dc59d566 --- /dev/null +++ b/packages/compass-web/polyfills/os/index.ts @@ -0,0 +1,4 @@ +export function tmpdir() { + return ''; +} +export default { tmpdir }; diff --git a/packages/compass-web/sandbox/index.html b/packages/compass-web/sandbox/index.html new file mode 100644 index 00000000000..3c710cd6149 --- /dev/null +++ b/packages/compass-web/sandbox/index.html @@ -0,0 +1,23 @@ + + + + + + Compass Web + + + + + +
+ + + diff --git a/packages/compass-web/sandbox/index.tsx b/packages/compass-web/sandbox/index.tsx new file mode 100644 index 00000000000..aa9f86a7a1e --- /dev/null +++ b/packages/compass-web/sandbox/index.tsx @@ -0,0 +1,272 @@ +import React, { useCallback, useState } from 'react'; +import ReactDOM from 'react-dom'; +import { + TextArea, + Button, + resetGlobalCSS, + Card, + KeylineCard, + css, + spacing, + palette, + Label, + ErrorBoundary, + Banner, + Body, +} from '@mongodb-js/compass-components'; +import { + redactConnectionString, + ConnectionString, +} from 'mongodb-connection-string-url'; +import { CompassWeb } from '../src/index'; +import type { OpenWorkspaceOptions } from '@mongodb-js/compass-workspaces'; + +const sandboxContainerStyles = css({ + width: '100%', + height: '100%', +}); + +const cardContainerStyles = css({ + width: '100%', + height: '100%', + paddingTop: spacing[7], +}); + +const cardStyles = css({ + width: '50%', + maxWidth: spacing[6] * 10, + minWidth: spacing[6] * 6, + marginLeft: 'auto', + marginRight: 'auto', +}); + +const connectionFormStyles = css({ + display: 'grid', + gridTemplateColumns: '100%', + gridAutoRows: 'auto', + gap: spacing[3], +}); + +const historyListStyles = css({ + all: 'unset', + marginTop: spacing[1], + display: 'grid', + gridTemplateColumns: '100%', + gridAutoRows: 'auto', + gap: spacing[2], +}); + +const historyListItemStyles = css({ + listStyle: 'none', + paddingTop: spacing[2], + paddingBottom: spacing[2], + paddingLeft: spacing[2], + paddingRight: spacing[2], +}); + +const historyItemButtonStyles = css({ + all: 'unset', + display: 'block', + width: '100%', + cursor: 'pointer', + color: palette.black, + whiteSpace: 'nowrap', + overflow: 'hidden', + textOverflow: 'ellipsis', +}); + +resetGlobalCSS(); + +function getHistory(): string[] { + try { + const b64Str = localStorage.getItem('CONNECTIONS_HISTORY'); + if (!b64Str) { + return []; + } + const binStr = window.atob(b64Str); + const bytes = Uint8Array.from(binStr, (v) => v.codePointAt(0) ?? 0); + const str = new TextDecoder().decode(bytes); + return JSON.parse(str); + } catch (err) { + return []; + } +} + +function saveHistory(history: any) { + try { + const bytes = new TextEncoder().encode(JSON.stringify(history)); + const binStr = String.fromCodePoint(...bytes); + const b64Str = window.btoa(binStr); + localStorage.setItem('CONNECTIONS_HISTORY', b64Str); + } catch (err) { + // noop + } +} + +function validateConnectionString(str: string) { + try { + new ConnectionString(str); + return null; + } catch (err) { + return (err as Error).message; + } +} + +const App = () => { + const [initialTab] = useState(() => { + const [, tab, namespace = ''] = window.location.pathname.split('/'); + if (tab === 'databases') { + return { type: 'Databases' }; + } + if (tab === 'collections' && namespace) { + return { type: 'Collections', namespace }; + } + if (tab === 'collection' && namespace) { + return { type: 'Collection', namespace }; + } + return { type: 'Databases' }; + }); + const [connectionsHistory, setConnectionsHistory] = useState(() => { + return getHistory(); + }); + const [focused, setFocused] = useState(false); + const [connectionString, setConnectionString] = useState(''); + const [openCompassWeb, setOpenCompassWeb] = useState(false); + const [ + connectionStringValidationResult, + setConnectionStringValidationResult, + ] = useState(null); + + const canSubmit = + connectionStringValidationResult === null && connectionString !== ''; + + const onChangeConnectionString = useCallback((str: string) => { + setConnectionStringValidationResult(validateConnectionString(str)); + setConnectionString(str); + }, []); + + const onConnectClick = useCallback(() => { + setOpenCompassWeb(true); + setConnectionsHistory((history) => { + if (history.includes(connectionString)) { + return history; + } + history.unshift(connectionString); + if (history.length > 10) { + history.pop(); + } + saveHistory(history); + return [...history]; + }); + }, [connectionString]); + + if (openCompassWeb) { + return ( + + + { + let newPath: string; + switch (tab?.type) { + case 'Databases': + newPath = '/databases'; + break; + case 'Collections': + newPath = `/collections/${tab.namespace}`; + break; + case 'Collection': + newPath = `/collection/${tab.namespace}`; + break; + default: + newPath = '/'; + } + if (newPath) { + window.history.replaceState(null, '', newPath); + } + }} + > + + + ); + } + + return ( + +
+ +
{ + evt.preventDefault(); + onConnectClick(); + }} + > + + {connectionStringValidationResult && ( + + {connectionStringValidationResult} + + )} + {connectionsHistory.length > 0 && ( +
+ +
    + {connectionsHistory.map((connectionString) => { + return ( + + + + ); + })} +
+
+ )} + +
+
+
+ + ); +}; + +ReactDOM.render(, document.querySelector('#sandbox-app')); diff --git a/packages/compass-web/src/index.spec.tsx b/packages/compass-web/src/index.spec.tsx new file mode 100644 index 00000000000..b9ec86b135d --- /dev/null +++ b/packages/compass-web/src/index.spec.tsx @@ -0,0 +1,103 @@ +import React from 'react'; +import { screen, render, cleanup, waitFor } from '@testing-library/react'; +import type { ConnectionOptions } from 'mongodb-data-service'; +import { expect } from 'chai'; +import { CompassWeb } from './'; +import Sinon from 'sinon'; +import EventEmitter from 'events'; +import ConnectionString from 'mongodb-connection-string-url'; + +function mockDb(name: string) { + return { _id: name, name }; +} + +class MockDataService extends EventEmitter { + constructor(private connectionOptions: ConnectionOptions) { + super(); + } + getConnectionString() { + return new ConnectionString(this.connectionOptions.connectionString); + } + getConnectionOptions() { + return { connectionString: 'mongodb://localhost:27017' }; + } + getLastSeenTopology() { + return { type: 'Unknown', servers: new Map([]) }; + } + instance() { + return Promise.resolve({}); + } + currentOp() { + return Promise.resolve({}); + } + top() { + return Promise.resolve({}); + } + configuredKMSProviders() { + return []; + } + listDatabases() { + return Promise.resolve([mockDb('foo'), mockDb('bar'), mockDb('buz')]); + } + disconnect() {} +} + +describe('CompassWeb', function () { + before(function () { + // TODO(COMPASS-7551): for some reason, specifically evergreen rhel machine can't + // fully render this component, skipping for now + if (process.env.EVERGREEN_BUILD_VARIANT === 'rhel') { + this.skip(); + } + }); + + const mockConnectFn = Sinon.spy( + ({ connectionOptions }: { connectionOptions: ConnectionOptions }) => { + return Sinon.spy(new MockDataService(connectionOptions)); + } + ); + + function renderCompassWeb( + props: Partial> = {}, + connectFn = mockConnectFn + ) { + return render( + {}} + {...props} + // @ts-expect-error see component props description + __TEST_MONGODB_DATA_SERVICE_CONNECT_FN={connectFn} + > + ); + } + + afterEach(cleanup); + + it('should render CompassWeb and connect using provided connection string', async function () { + renderCompassWeb(); + + await waitFor(() => { + screen.getByText('Connecting to localhost:27017…'); + }); + + expect(mockConnectFn).to.have.been.calledWithMatch({ + connectionOptions: { connectionString: 'mongodb://localhost:27017' }, + }); + + // Wait for connection to happen and navigation tree to render + await waitFor(() => { + screen.getByTestId('compass-web-connected'); + screen.getByRole('button', { name: 'Databases' }); + screen.getAllByRole('tree'); + }); + + // TODO(COMPASS-7551): These are not rendered in tests because of the + // navigation virtualization. We should make it possible to render those + // here either by modifying the dom observer mock or by providing some way + // to pass the test value to the virtualized component + // expect(screen.getByRole('treeitem', {name: 'foo'})).to.exist; + // expect(screen.getByRole('treeitem', {name: 'bar'})).to.exist; + // expect(screen.getByRole('treeitem', {name: 'buz'})).to.exist; + }); +}); diff --git a/packages/compass-web/src/index.tsx b/packages/compass-web/src/index.tsx new file mode 100644 index 00000000000..e2039780fc0 --- /dev/null +++ b/packages/compass-web/src/index.tsx @@ -0,0 +1,207 @@ +import React, { useEffect, useMemo, useRef, useState } from 'react'; +import { connect } from 'mongodb-data-service'; +import type { DataService } from 'mongodb-data-service'; +import { AppRegistryProvider, globalAppRegistry } from 'hadron-app-registry'; +import { DataServiceProvider } from 'mongodb-data-service/provider'; +import { CompassInstanceStorePlugin } from '@mongodb-js/compass-app-stores'; +import WorkspacesPlugin, { + WorkspacesProvider, +} from '@mongodb-js/compass-workspaces'; +import { + DatabasesWorkspaceTab, + CollectionsWorkspaceTab, +} from '@mongodb-js/compass-databases-collections'; +import { + CompassComponentsProvider, + SpinLoaderWithLabel, + css, +} from '@mongodb-js/compass-components'; +import { ConnectionString } from 'mongodb-connection-string-url'; +import { + WorkspaceTab as CollectionWorkspace, + CollectionTabsProvider, +} from '@mongodb-js/compass-collection'; +import { CompassSidebarPlugin } from '@mongodb-js/compass-sidebar'; +import CompassQueryBarPlugin from '@mongodb-js/compass-query-bar'; +import { CompassDocumentsPlugin } from '@mongodb-js/compass-crud'; +import { + CompassAggregationsPlugin, + CreateViewPlugin, +} from '@mongodb-js/compass-aggregations'; +import { CompassSchemaPlugin } from '@mongodb-js/compass-schema'; +import { + activate as activateCompassIndexesPluginRoles, + CompassIndexesPlugin, +} from '@mongodb-js/compass-indexes'; +import { CompassSchemaValidationPlugin } from '@mongodb-js/compass-schema-validation'; +import { activate as activateExplainPlanPluginRoles } from '@mongodb-js/compass-explain-plan'; +import { activate as activateExportToLanguagePluginRoles } from '@mongodb-js/compass-export-to-language'; +import { + CreateNamespacePlugin, + DropNamespacePlugin, + RenameCollectionPlugin, +} from '@mongodb-js/compass-databases-collections'; + +// TODO(COMPASS-7403): only required while these plugins are not converted to the new +// plugin interface +activateExplainPlanPluginRoles(globalAppRegistry); +activateExportToLanguagePluginRoles(globalAppRegistry); +activateCompassIndexesPluginRoles(globalAppRegistry); + +type CompassWebProps = { + darkMode?: boolean; + connectionString: string; +} & Pick< + React.ComponentProps, + 'initialWorkspaceTabs' | 'onActiveWorkspaceTabChange' +>; + +const loadingContainerStyles = css({ + width: '100%', + height: '100%', + display: 'flex', + alignItems: 'center', + justifyContent: 'center', +}); + +const spinnerStyles = css({ + flex: 'none', +}); + +function LoadingScreen({ connectionString }: { connectionString: string }) { + const host = useMemo(() => { + try { + const url = new ConnectionString(connectionString); + return url.hosts[0]; + } catch { + return 'cluster'; + } + }, [connectionString]); + + return ( +
+ +
+ ); +} + +const DEFAULT_TAB = { type: 'Databases' } as const; + +const connectedContainerStyles = css({ + width: '100%', + height: '100%', + display: 'flex', +}); + +const CompassWeb = ({ + darkMode, + connectionString, + initialWorkspaceTabs, + onActiveWorkspaceTabChange, + // @ts-expect-error not an interface we want to expose in any way, only for + // testing purposes, should never be used otherwise + __TEST_MONGODB_DATA_SERVICE_CONNECT_FN, +}: CompassWebProps) => { + const [connected, setConnected] = useState(false); + const [connectionError, setConnectionError] = useState(null); + const dataService = useRef(); + + useEffect(() => { + const controller = new AbortController(); + let ds: DataService; + void (async () => { + try { + const connectFn = + (__TEST_MONGODB_DATA_SERVICE_CONNECT_FN as typeof connect) ?? connect; + ds = await connectFn({ + connectionOptions: { connectionString }, + signal: controller.signal, + }); + dataService.current = ds; + setConnected(true); + } catch (err) { + setConnectionError(err); + } + })(); + return () => { + void ds?.disconnect(); + }; + }, [connectionString, __TEST_MONGODB_DATA_SERVICE_CONNECT_FN]); + + // Re-throw connection error so that parent component can render an + // appropriate error screen with an error boundary (only relevant while we are + // handling a single connection) + if (connectionError) { + throw connectionError; + } + + if (connected && dataService.current) { + return ( + + + + + + +
+ { + return ( + + ); + }} + renderModals={() => { + return ( + <> + + + + + + ); + }} + > +
+
+
+
+
+
+
+ ); + } + + return ( + + + + ); +}; + +export { CompassWeb }; diff --git a/packages/compass-web/tsconfig-lint.json b/packages/compass-web/tsconfig-lint.json new file mode 100644 index 00000000000..6bdef84f322 --- /dev/null +++ b/packages/compass-web/tsconfig-lint.json @@ -0,0 +1,5 @@ +{ + "extends": "./tsconfig.json", + "include": ["**/*"], + "exclude": ["node_modules", "dist"] +} diff --git a/packages/compass-web/tsconfig.json b/packages/compass-web/tsconfig.json new file mode 100644 index 00000000000..74e46cf57af --- /dev/null +++ b/packages/compass-web/tsconfig.json @@ -0,0 +1,8 @@ +{ + "extends": "@mongodb-js/tsconfig-compass/tsconfig.react.json", + "compilerOptions": { + "outDir": "dist" + }, + "include": ["src/**/*", "sandbox/**/*"], + "exclude": ["./src/**/*.spec.*"] +} diff --git a/packages/compass-web/webpack.config.js b/packages/compass-web/webpack.config.js new file mode 100644 index 00000000000..343ed63599c --- /dev/null +++ b/packages/compass-web/webpack.config.js @@ -0,0 +1,167 @@ +const path = require('path'); +const { + webpack, + createWebConfig, + isServe, + merge, +} = require('@mongodb-js/webpack-config-compass'); +const { createWebSocketProxy } = require('@gribnoysup/mongodb-browser/proxy'); + +function localPolyfill(name) { + return path.resolve(__dirname, 'polyfills', ...name.split('/'), 'index.ts'); +} + +module.exports = async (env, args) => { + const serve = isServe({ env }); + + let config = createWebConfig({ + ...args, + hot: serve, + entry: path.resolve(__dirname, serve ? 'sandbox' : 'src', 'index.tsx'), + }); + + delete config.externals; + + config = merge(config, { + resolve: { + alias: { + // TODO(ticket): data-service (only certain connection types, not + // explicitly optional) + '@mongodb-js/ssh-tunnel': false, + ssh2: false, + + // TODO(ticket): data-service -> devtools-connect (only certain + // connection types, not explicitly optional) + '@mongodb-js/oidc-plugin': localPolyfill('@mongodb-js/oidc-plugin'), + 'system-ca': false, + http: localPolyfill('http'), + zlib: false, + os: localPolyfill('os'), + crypto: localPolyfill('crypto'), + + // TODO(ticket): non-optional data-service -> devtools-connect required + // for +srv, should be skippable + dns: false, + 'os-dns-native': false, + 'resolve-mongodb-srv': false, + + // TODO(ticket): compass-logging + // hard to disable the whole thing while there are direct dependencies + // on logger + // 'mongodb-log-writer': localPolyfill('mongodb-log-writer'), + v8: false, + // TODO(ticket): compass-logging + 'hadron-ipc': false, + + // TODO(ticket): compass-user-data + // can't disable the whole module, imports used directly in module scope + // '@mongodb-js/compass-user-data': false, + worker_threads: false, + + // TODO(ticket): compass-utils + fs: localPolyfill('fs'), + + // TODO(ticket): required by FileInput component, we probably can remove + // this dependency from the package + path: require.resolve('path-browserify'), + + // Optional data-service -> devtools-connect dependencies + socks: false, + 'mongodb-client-encryption': false, + kerberos: false, + + // Things that are easier to polyfill than not to + stream: require.resolve('readable-stream'), + // The `/` so that we are resolving the installed polyfill version, not + // a built-in Node.js one + util: require.resolve('util/'), + buffer: require.resolve('buffer/'), + events: require.resolve('events/'), + // Used by export-to-language feature and there is no real way we can + // remove the usage at the moment + vm: require.resolve('vm-browserify'), + + // TODO(ticket): requires a polyfill to be able to parse connection + // string correctly at the moment, but we should also omit some + // depdendencies that might not be required for this to work in the + // browser + url: require.resolve('whatwg-url'), + // Make sure we're not getting multiple versions included + 'whatwg-url': require.resolve('whatwg-url'), + }, + }, + plugins: [ + new webpack.ProvidePlugin({ + Buffer: ['buffer', 'Buffer'], + process: require.resolve('process/browser'), + }), + ], + }); + + if (serve) { + // TODO: logs are pretty rough here, should make it better + createWebSocketProxy(); + + config.output = { + path: config.output.path, + filename: config.output.filename, + assetModuleFilename: config.output.assetModuleFilename, + }; + + return merge(config, { + devServer: { + hot: true, + magicHtml: false, + historyApiFallback: { + rewrites: [{ from: /./, to: 'index.html' }], + }, + static: { + directory: path.resolve(__dirname, 'sandbox'), + publicPath: '/', + }, + client: { + overlay: { warnings: false, errors: true, runtimeErrors: true }, + }, + }, + resolve: { + alias: { + // TODO(ticket): move mongodb-browser from mms to the monorepo and + // package it too + mongodb: require.resolve('@gribnoysup/mongodb-browser'), + + // NB: We polyfill those in `@gribnoysup/mongodb-browser` already, but + // devtools-connect does its own dns resolution (for a good reason + // COMPASS-4768) for srv so we have to do it again. This is something + // that potentially mms will also need to adjust on their side if they + // ever want to support passing srv connections as-is (but they don't + // need to, they already have a resolved info for connection on their + // side) + dns: localPolyfill('dns'), + 'os-dns-native': localPolyfill('os-dns-native'), + + // We exclude it for the published distribution as it requires dns + // resolution to work which is not expected. Re-include for the + // sandbox + 'resolve-mongodb-srv': require.resolve('resolve-mongodb-srv'), + }, + }, + }); + } + + config.output = { + path: config.output.path, + filename: config.output.filename, + library: { + name: 'CompassWeb', + type: 'commonjs2', + }, + }; + + return merge(config, { + externals: { + // TODO(ticket): move mongodb-browser from mms to the monorepo and package + // it too + mongodb: 'commonjs2 mongodb', + }, + }); +}; diff --git a/packages/compass-workspaces/src/components/index.tsx b/packages/compass-workspaces/src/components/index.tsx index a90f85234f2..4ed746ff20a 100644 --- a/packages/compass-workspaces/src/components/index.tsx +++ b/packages/compass-workspaces/src/components/index.tsx @@ -1,5 +1,5 @@ import React, { useEffect, useRef } from 'react'; -import { css } from '@mongodb-js/compass-components'; +import { css, cx, palette, useDarkMode } from '@mongodb-js/compass-components'; import type { CollectionTabInfo } from '../stores/workspaces'; import { getActiveTab, @@ -36,7 +36,12 @@ type WorkspacesWithSidebarProps = { /** * Initial workspace tab to show (by default no tabs will be shown initially) */ - initialWorkspaceTab?: OpenWorkspaceOptions; + initialWorkspaceTabs?: OpenWorkspaceOptions[] | null; + /** + * Workspace configuration to be opened when all tabs are closed (defaults to + * "My Queries") + */ + openOnEmptyWorkspace?: OpenWorkspaceOptions | null; /** * Workspaces sidebar component slot Required so that plugin modals can be * rendered inside workspace React tree and access workspace state and actions @@ -51,8 +56,19 @@ type WorkspacesWithSidebarProps = { renderModals?: () => React.ReactElement | null; }; +const containerLightThemeStyles = css({ + backgroundColor: palette.white, + color: palette.gray.dark2, +}); + +const containerDarkThemeStyles = css({ + backgroundColor: palette.black, + color: palette.white, +}); + const horizontalSplitStyles = css({ width: '100%', + height: '100%', display: 'grid', gridTemplateColumns: 'min-content auto', minHeight: 0, @@ -72,10 +88,12 @@ const WorkspacesWithSidebar: React.FunctionComponent< > = ({ activeTab, activeTabCollectionInfo, + openOnEmptyWorkspace, onActiveWorkspaceTabChange, renderSidebar, renderModals, }) => { + const darkMode = useDarkMode(); const onChange = useRef(onActiveWorkspaceTabChange); onChange.current = onActiveWorkspaceTabChange; useEffect(() => { @@ -83,12 +101,17 @@ const WorkspacesWithSidebar: React.FunctionComponent< }, [activeTab, activeTabCollectionInfo]); return ( -
+
{renderSidebar && React.createElement(renderSidebar)}
- +
{renderModals && React.createElement(renderModals)} diff --git a/packages/compass-workspaces/src/components/workspaces-provider.tsx b/packages/compass-workspaces/src/components/workspaces-provider.tsx index f4972471030..0fedc3ab9bf 100644 --- a/packages/compass-workspaces/src/components/workspaces-provider.tsx +++ b/packages/compass-workspaces/src/components/workspaces-provider.tsx @@ -1,4 +1,4 @@ -import React, { useContext, useRef, useCallback } from 'react'; +import React, { useContext, useRef, useCallback, useMemo } from 'react'; import type { AnyWorkspace, WorkspaceComponent } from '../'; export type AnyWorkspaceComponent = @@ -21,9 +21,15 @@ export const WorkspacesProvider: React.FunctionComponent<{ ); }; -export const useWorkspacePlugin = () => { +export const useWorkspacePlugins = () => { const workspaces = useContext(WorkspacesContext); - return useCallback( + const hasWorkspacePlugin = useCallback( + (name: T) => { + return workspaces.some((ws) => ws.name === name); + }, + [workspaces] + ); + const getWorkspacePluginByName = useCallback( (name: T) => { const plugin = workspaces.find((workspace) => workspace.name === name); if (!plugin) { @@ -35,4 +41,7 @@ export const useWorkspacePlugin = () => { }, [workspaces] ); + return useMemo(() => { + return { hasWorkspacePlugin, getWorkspacePluginByName }; + }, [hasWorkspacePlugin, getWorkspacePluginByName]); }; diff --git a/packages/compass-workspaces/src/components/workspaces.tsx b/packages/compass-workspaces/src/components/workspaces.tsx index 8b558a83e60..ac3b691b130 100644 --- a/packages/compass-workspaces/src/components/workspaces.tsx +++ b/packages/compass-workspaces/src/components/workspaces.tsx @@ -1,4 +1,4 @@ -import React, { useMemo } from 'react'; +import React, { useCallback, useMemo } from 'react'; import { AppRegistryProvider } from 'hadron-app-registry'; import { ErrorBoundary, @@ -10,6 +10,7 @@ import { } from '@mongodb-js/compass-components'; import type { CollectionTabInfo, + OpenWorkspaceOptions, WorkspaceTab, WorkspacesState, } from '../stores/workspaces'; @@ -23,7 +24,7 @@ import { selectPrevTab, selectTab, } from '../stores/workspaces'; -import { useWorkspacePlugin } from './workspaces-provider'; +import { useWorkspacePlugins } from './workspaces-provider'; import toNS from 'mongodb-ns'; import { useLoggerAndTelemetry } from '@mongodb-js/compass-logging/provider'; import { connect } from '../stores/context'; @@ -64,12 +65,13 @@ type CompassWorkspacesProps = { tabs: WorkspaceTab[]; activeTab?: WorkspaceTab | null; collectionInfo: Record; + openOnEmptyWorkspace?: OpenWorkspaceOptions | null; onSelectTab(at: number): void; onSelectNextTab(): void; onSelectPrevTab(): void; onMoveTab(from: number, to: number): void; - onCreateTab(): void; + onCreateTab(defaultTab?: OpenWorkspaceOptions | null): void; onCloseTab(at: number): void; }; @@ -77,6 +79,7 @@ const CompassWorkspaces: React.FunctionComponent = ({ tabs, activeTab, collectionInfo, + openOnEmptyWorkspace, onSelectTab, onSelectNextTab, onSelectPrevTab, @@ -85,7 +88,7 @@ const CompassWorkspaces: React.FunctionComponent = ({ onCloseTab, }) => { const { log, mongoLogId } = useLoggerAndTelemetry('COMPASS-WORKSPACES'); - const getWorkspaceByName = useWorkspacePlugin(); + const { getWorkspacePluginByName } = useWorkspacePlugins(); const tabDescriptions = useMemo(() => { return tabs.map((tab) => { @@ -154,15 +157,15 @@ const CompassWorkspaces: React.FunctionComponent = ({ case 'My Queries': case 'Performance': case 'Databases': { - const Component = getWorkspaceByName(activeTab.type); + const Component = getWorkspacePluginByName(activeTab.type); return ; } case 'Collections': { - const Component = getWorkspaceByName(activeTab.type); + const Component = getWorkspacePluginByName(activeTab.type); return ; } case 'Collection': { - const Component = getWorkspaceByName(activeTab.type); + const Component = getWorkspacePluginByName(activeTab.type); // eslint-disable-next-line @typescript-eslint/no-unused-vars const { id, type, ...collectionMetadata } = activeTab; return ; @@ -170,7 +173,11 @@ const CompassWorkspaces: React.FunctionComponent = ({ default: return null; } - }, [activeTab, getWorkspaceByName]); + }, [activeTab, getWorkspacePluginByName]); + + const onCreateNewTab = useCallback(() => { + onCreateTab(openOnEmptyWorkspace); + }, [onCreateTab, openOnEmptyWorkspace]); return (
@@ -180,7 +187,7 @@ const CompassWorkspaces: React.FunctionComponent = ({ onSelectNextTab={onSelectNextTab} onSelectPrevTab={onSelectPrevTab} onMoveTab={onMoveTab} - onCreateNewTab={onCreateTab} + onCreateNewTab={onCreateNewTab} onCloseTab={onCloseTab} tabs={tabDescriptions} selectedTabIndex={activeTabIndex} diff --git a/packages/compass-workspaces/src/index.ts b/packages/compass-workspaces/src/index.ts index 96f59e31533..89ee1924f69 100644 --- a/packages/compass-workspaces/src/index.ts +++ b/packages/compass-workspaces/src/index.ts @@ -21,6 +21,7 @@ import type { DataService } from 'mongodb-data-service'; import type { DataServiceLocator } from 'mongodb-data-service/provider'; import { dataServiceLocator } from 'mongodb-data-service/provider'; import { WorkspacesStoreContext } from './stores/context'; +import toNS from 'mongodb-ns'; export type WorkspacesServices = { globalAppRegistry: AppRegistry; @@ -28,13 +29,48 @@ export type WorkspacesServices = { dataService: DataService; }; +/** + * When opening tabs initially, there might be the case that db and collection + * models don't exist yet on the instance model. Workspaces expect the models to + * exist when rendered, so we prepopulate instance model with collections and + * databases to support that case + */ +function prepopulateInstanceModel( + tabs: OpenWorkspaceOptions[], + instance: MongoDBInstance +) { + for (const tab of tabs) { + if (tab.type === 'Collections' || tab.type === 'Collection') { + const { ns, database, collection, validCollectionName } = toNS( + tab.namespace + ); + const db = + instance.databases.get(database) ?? + instance.databases.add({ _id: database }); + + if ( + collection && + validCollectionName && + !db.collections.get(collection, 'name') + ) { + db.collections.add({ _id: ns }); + } + } + } +} + export function configureStore( - initialWorkspaceTab: OpenWorkspaceOptions | undefined | null, + initialWorkspaceTabs: OpenWorkspaceOptions[] | undefined | null, services: WorkspacesServices ) { - const initialTabs = initialWorkspaceTab - ? [getInitialTabState(initialWorkspaceTab)] - : []; + const initialTabs = + initialWorkspaceTabs && initialWorkspaceTabs.length > 0 + ? initialWorkspaceTabs.map((tab) => { + return getInitialTabState(tab); + }) + : []; + + prepopulateInstanceModel(initialTabs, services.instance); const store = createStore( workspacesReducer, @@ -50,11 +86,13 @@ export function configureStore( } export function activateWorkspacePlugin( - { initialWorkspaceTab }: { initialWorkspaceTab?: OpenWorkspaceOptions }, + { + initialWorkspaceTabs, + }: { initialWorkspaceTabs?: OpenWorkspaceOptions[] | null }, { globalAppRegistry, instance, dataService }: WorkspacesServices, { on, cleanup }: ActivateHelpers ) { - const store = configureStore(initialWorkspaceTab, { + const store = configureStore(initialWorkspaceTabs, { globalAppRegistry, instance, dataService, diff --git a/packages/compass-workspaces/src/provider.tsx b/packages/compass-workspaces/src/provider.tsx index 262af72b8d1..7196c585baf 100644 --- a/packages/compass-workspaces/src/provider.tsx +++ b/packages/compass-workspaces/src/provider.tsx @@ -226,3 +226,5 @@ export function useActiveWorkspace() { } export const workspacesServiceLocator = useWorkspacesService; + +export { useWorkspacePlugins } from './components/workspaces-provider'; diff --git a/packages/compass-workspaces/src/stores/workspaces.ts b/packages/compass-workspaces/src/stores/workspaces.ts index bdbda1e7e2d..ff7728c476b 100644 --- a/packages/compass-workspaces/src/stores/workspaces.ts +++ b/packages/compass-workspaces/src/stores/workspaces.ts @@ -161,7 +161,7 @@ const reducer: Reducer = ( const currentActiveTab = getActiveTab(state); let newTab: WorkspaceTab; if (!currentActiveTab) { - newTab = getInitialTabState({ type: 'My Queries' }); + newTab = getInitialTabState(action.defaultTab); } else { // eslint-disable-next-line @typescript-eslint/no-unused-vars const { id: _id, ...tabProps } = currentActiveTab; @@ -479,10 +479,16 @@ export const selectNextTab = (): SelectNextTabAction => { type OpenTabFromCurrentActiveAction = { type: WorkspacesActions.OpenTabFromCurrentActive; + defaultTab: OpenWorkspaceOptions; }; -export const openTabFromCurrent = (): OpenTabFromCurrentActiveAction => { - return { type: WorkspacesActions.OpenTabFromCurrentActive }; +export const openTabFromCurrent = ( + defaultTab?: OpenWorkspaceOptions | null +): OpenTabFromCurrentActiveAction => { + return { + type: WorkspacesActions.OpenTabFromCurrentActive, + defaultTab: defaultTab ?? { type: 'My Queries' }, + }; }; type CloseTabAction = { type: WorkspacesActions.CloseTab; atIndex: number };