From f5f1030e448619059c718e6bf1dda04aafd265be Mon Sep 17 00:00:00 2001 From: Darshana Venkatesh Date: Mon, 18 Aug 2025 15:06:18 -0700 Subject: [PATCH 01/22] add confirmation banner --- .github/ISSUE_TEMPLATE/config.yml | 3 +- AUTHORS | 1 + README.md | 2 +- package-lock.json | 443 +----------------- .../aggregation-side-panel/feedback-link.tsx | 2 +- .../src/modules/search-indexes.ts | 8 +- .../src/modules/update-view.ts | 21 + packages/compass-indexes/package.json | 1 + .../indexes-toolbar/indexes-toolbar.spec.tsx | 66 ++- .../indexes-toolbar/indexes-toolbar.tsx | 105 +++-- .../src/components/indexes/indexes.spec.tsx | 87 +++- .../src/components/indexes/indexes.tsx | 85 +++- .../view-version-incompatible-banners.tsx | 70 +++ .../src/modules/index-view.spec.ts | 10 +- .../compass-indexes/src/modules/index-view.ts | 5 +- .../src/modules/search-indexes.ts | 21 +- packages/compass-indexes/src/stores/store.ts | 8 +- .../src/utils/atlas-upgrade-cluster-link.ts | 7 + packages/compass/README.md | 2 +- .../src/app/utils/view-search-queryable.ts | 30 ++ packages/compass/src/main/menu.ts | 4 +- 21 files changed, 454 insertions(+), 527 deletions(-) create mode 100644 packages/compass-indexes/src/components/view-version-incompatible-banners/view-version-incompatible-banners.tsx create mode 100644 packages/compass-indexes/src/utils/atlas-upgrade-cluster-link.ts create mode 100644 packages/compass/src/app/utils/view-search-queryable.ts diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index 48ec79055e5..cf591bf45f1 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -4,9 +4,8 @@ contact_links: url: https://jira.mongodb.org/ about: Report a bug to the COMPASS project in Jira. - name: Feature Request - url: https://feedback.mongodb.com/forums/924283-compass + url: https://feedback.mongodb.com/ about: Request a new feature or enhancement via the MongoDB Feedback Engine. - name: General Questions and Inquiries url: https://www.mongodb.com/community/forums/tags/c/data/developer-tools/49/compass about: Visit our forums for public community discussion and collaboration. - diff --git a/AUTHORS b/AUTHORS index e0ea8fa15d1..a9bdd2f3dac 100644 --- a/AUTHORS +++ b/AUTHORS @@ -110,3 +110,4 @@ Moses Yang Jimmy Choi <150958139+JimmyChoiMDB@users.noreply.github.com> Jacob Lu <43422771+jcobis@users.noreply.github.com> Nataly Carbonell +DarshanaVenkatesh <70602567+DarshanaVenkatesh@users.noreply.github.com> diff --git a/README.md b/README.md index 3e8ef820546..1e79467e038 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ For contributing, please refer to [CONTRIBUTING.md](CONTRIBUTING.md) For issues, please create a ticket in our [JIRA Project](https://jira.mongodb.org/browse/COMPASS). -Is there anything else you’d like to see in Compass? Let us know by submitting suggestions in out [feedback forum](https://feedback.mongodb.com/forums/924283-compass). +Is there anything else you’d like to see in Compass? Let us know by submitting suggestions in out [feedback forum](https://feedback.mongodb.com/). ## Packages Overview diff --git a/package-lock.json b/package-lock.json index 3cf6bf4c754..a31621bd0e7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -43729,228 +43729,6 @@ "mocha": "^10.2.0" } }, - "packages/bson-transpilers/node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.39.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.39.1.tgz", - "integrity": "sha512-yYegZ5n3Yr6eOcqgj2nJH8cH/ZZgF+l0YIdKILSDjYFRjgYQMgv/lRjV5Z7Up04b9VYUondt8EPMqg7kTWgJ2g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "8.39.1", - "@typescript-eslint/type-utils": "8.39.1", - "@typescript-eslint/utils": "8.39.1", - "@typescript-eslint/visitor-keys": "8.39.1", - "graphemer": "^1.4.0", - "ignore": "^7.0.0", - "natural-compare": "^1.4.0", - "ts-api-utils": "^2.1.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "@typescript-eslint/parser": "^8.39.1", - "eslint": "^8.57.0 || ^9.0.0", - "typescript": ">=4.8.4 <6.0.0" - } - }, - "packages/bson-transpilers/node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/type-utils": { - "version": "8.39.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.39.1.tgz", - "integrity": "sha512-gu9/ahyatyAdQbKeHnhT4R+y3YLtqqHyvkfDxaBYk97EcbfChSJXyaJnIL3ygUv7OuZatePHmQvuH5ru0lnVeA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/types": "8.39.1", - "@typescript-eslint/typescript-estree": "8.39.1", - "@typescript-eslint/utils": "8.39.1", - "debug": "^4.3.4", - "ts-api-utils": "^2.1.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0", - "typescript": ">=4.8.4 <6.0.0" - } - }, - "packages/bson-transpilers/node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/utils": { - "version": "8.39.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.39.1.tgz", - "integrity": "sha512-VF5tZ2XnUSTuiqZFXCZfZs1cgkdd3O/sSYmdo2EpSyDlC86UM/8YytTmKnehOW3TGAlivqTDT6bS87B/GQ/jyg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@eslint-community/eslint-utils": "^4.7.0", - "@typescript-eslint/scope-manager": "8.39.1", - "@typescript-eslint/types": "8.39.1", - "@typescript-eslint/typescript-estree": "8.39.1" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0", - "typescript": ">=4.8.4 <6.0.0" - } - }, - "packages/bson-transpilers/node_modules/@typescript-eslint/parser": { - "version": "8.39.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.39.1.tgz", - "integrity": "sha512-pUXGCuHnnKw6PyYq93lLRiZm3vjuslIy7tus1lIQTYVK9bL8XBgJnCWm8a0KcTtHC84Yya1Q6rtll+duSMj0dg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/scope-manager": "8.39.1", - "@typescript-eslint/types": "8.39.1", - "@typescript-eslint/typescript-estree": "8.39.1", - "@typescript-eslint/visitor-keys": "8.39.1", - "debug": "^4.3.4" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0", - "typescript": ">=4.8.4 <6.0.0" - } - }, - "packages/bson-transpilers/node_modules/@typescript-eslint/project-service": { - "version": "8.39.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.39.1.tgz", - "integrity": "sha512-8fZxek3ONTwBu9ptw5nCKqZOSkXshZB7uAxuFF0J/wTMkKydjXCzqqga7MlFMpHi9DoG4BadhmTkITBcg8Aybw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/tsconfig-utils": "^8.39.1", - "@typescript-eslint/types": "^8.39.1", - "debug": "^4.3.4" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "typescript": ">=4.8.4 <6.0.0" - } - }, - "packages/bson-transpilers/node_modules/@typescript-eslint/scope-manager": { - "version": "8.39.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.39.1.tgz", - "integrity": "sha512-RkBKGBrjgskFGWuyUGz/EtD8AF/GW49S21J8dvMzpJitOF1slLEbbHnNEtAHtnDAnx8qDEdRrULRnWVx27wGBw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/types": "8.39.1", - "@typescript-eslint/visitor-keys": "8.39.1" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "packages/bson-transpilers/node_modules/@typescript-eslint/tsconfig-utils": { - "version": "8.39.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.39.1.tgz", - "integrity": "sha512-ePUPGVtTMR8XMU2Hee8kD0Pu4NDE1CN9Q1sxGSGd/mbOtGZDM7pnhXNJnzW63zk/q+Z54zVzj44HtwXln5CvHA==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "typescript": ">=4.8.4 <6.0.0" - } - }, - "packages/bson-transpilers/node_modules/@typescript-eslint/types": { - "version": "8.39.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.39.1.tgz", - "integrity": "sha512-7sPDKQQp+S11laqTrhHqeAbsCfMkwJMrV7oTDvtDds4mEofJYir414bYKUEb8YPUm9QL3U+8f6L6YExSoAGdQw==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "packages/bson-transpilers/node_modules/@typescript-eslint/typescript-estree": { - "version": "8.39.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.39.1.tgz", - "integrity": "sha512-EKkpcPuIux48dddVDXyQBlKdeTPMmALqBUbEk38McWv0qVEZwOpVJBi7ugK5qVNgeuYjGNQxrrnoM/5+TI/BPw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/project-service": "8.39.1", - "@typescript-eslint/tsconfig-utils": "8.39.1", - "@typescript-eslint/types": "8.39.1", - "@typescript-eslint/visitor-keys": "8.39.1", - "debug": "^4.3.4", - "fast-glob": "^3.3.2", - "is-glob": "^4.0.3", - "minimatch": "^9.0.4", - "semver": "^7.6.0", - "ts-api-utils": "^2.1.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "typescript": ">=4.8.4 <6.0.0" - } - }, - "packages/bson-transpilers/node_modules/@typescript-eslint/visitor-keys": { - "version": "8.39.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.39.1.tgz", - "integrity": "sha512-W8FQi6kEh2e8zVhQ0eeRnxdvIoOkAp/CPAahcNio6nO9dsIwb9b34z90KOlheoyuVf6LSOEdjlkxSkapNEc+4A==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/types": "8.39.1", - "eslint-visitor-keys": "^4.2.1" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, "packages/bson-transpilers/node_modules/argparse": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", @@ -43959,39 +43737,6 @@ "sprintf-js": "~1.0.2" } }, - "packages/bson-transpilers/node_modules/brace-expansion": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", - "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "packages/bson-transpilers/node_modules/eslint-visitor-keys": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", - "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "packages/bson-transpilers/node_modules/ignore": { - "version": "7.0.5", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", - "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 4" - } - }, "packages/bson-transpilers/node_modules/js-yaml": { "version": "3.14.1", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", @@ -44004,22 +43749,6 @@ "js-yaml": "bin/js-yaml.js" } }, - "packages/bson-transpilers/node_modules/minimatch": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", - "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "packages/collection-model": { "name": "mongodb-collection-model", "version": "5.31.1", @@ -47083,6 +46812,7 @@ "@mongodb-js/compass-logging": "^1.7.11", "@mongodb-js/compass-telemetry": "^1.13.0", "@mongodb-js/compass-workspaces": "^0.51.0", + "@mongodb-js/connection-info": "^0.17.1", "@mongodb-js/mongodb-constants": "^0.12.2", "@mongodb-js/shell-bson-parser": "^1.2.0", "bson": "^6.10.4", @@ -59146,6 +58876,7 @@ "@mongodb-js/compass-logging": "^1.7.11", "@mongodb-js/compass-telemetry": "^1.13.0", "@mongodb-js/compass-workspaces": "^0.51.0", + "@mongodb-js/connection-info": "^0.17.1", "@mongodb-js/eslint-config-compass": "^1.4.6", "@mongodb-js/mocha-config-compass": "^1.7.0", "@mongodb-js/mongodb-constants": "^0.12.2", @@ -69082,146 +68813,6 @@ "mocha": "^10.2.0" }, "dependencies": { - "@mongodb-js/eslint-config-compass": { - "version": "https://registry.npmjs.org/@mongodb-js/eslint-config-compass/-/eslint-config-compass-1.4.5.tgz", - "integrity": "sha512-5KLev9+SSp3ytlL5GA0oY/YamyrMGtPS63rgLYgJkvWTfyCN1obBzvNcbAAz4UntX7mU2/iWZ8GJnvR9jHKwEA==", - "dev": true, - "requires": { - "@babel/core": "^7.24.3", - "@babel/eslint-parser": "^7.14.3", - "@mongodb-js/eslint-config-devtools": "^0.9.9", - "@mongodb-js/eslint-plugin-compass": "^1.2.13", - "@typescript-eslint/eslint-plugin": "^8.38.0", - "@typescript-eslint/parser": "^8.38.0", - "eslint": "^8.57.1", - "eslint-config-prettier": "^8.3.0", - "eslint-plugin-chai-friendly": "^1.1.0", - "eslint-plugin-filename-rules": "^1.2.0", - "eslint-plugin-jsx-a11y": "^6.10.2", - "eslint-plugin-mocha": "^8.0.0", - "eslint-plugin-react": "^7.37.5", - "eslint-plugin-react-hooks": "^5.2.0" - } - }, - "@typescript-eslint/eslint-plugin": { - "version": "8.39.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.39.1.tgz", - "integrity": "sha512-yYegZ5n3Yr6eOcqgj2nJH8cH/ZZgF+l0YIdKILSDjYFRjgYQMgv/lRjV5Z7Up04b9VYUondt8EPMqg7kTWgJ2g==", - "dev": true, - "requires": { - "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "8.39.1", - "@typescript-eslint/type-utils": "8.39.1", - "@typescript-eslint/utils": "8.39.1", - "@typescript-eslint/visitor-keys": "8.39.1", - "graphemer": "^1.4.0", - "ignore": "^7.0.0", - "natural-compare": "^1.4.0", - "ts-api-utils": "^2.1.0" - }, - "dependencies": { - "@typescript-eslint/type-utils": { - "version": "8.39.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.39.1.tgz", - "integrity": "sha512-gu9/ahyatyAdQbKeHnhT4R+y3YLtqqHyvkfDxaBYk97EcbfChSJXyaJnIL3ygUv7OuZatePHmQvuH5ru0lnVeA==", - "dev": true, - "requires": { - "@typescript-eslint/types": "8.39.1", - "@typescript-eslint/typescript-estree": "8.39.1", - "@typescript-eslint/utils": "8.39.1", - "debug": "^4.3.4", - "ts-api-utils": "^2.1.0" - } - }, - "@typescript-eslint/utils": { - "version": "8.39.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.39.1.tgz", - "integrity": "sha512-VF5tZ2XnUSTuiqZFXCZfZs1cgkdd3O/sSYmdo2EpSyDlC86UM/8YytTmKnehOW3TGAlivqTDT6bS87B/GQ/jyg==", - "dev": true, - "requires": { - "@eslint-community/eslint-utils": "^4.7.0", - "@typescript-eslint/scope-manager": "8.39.1", - "@typescript-eslint/types": "8.39.1", - "@typescript-eslint/typescript-estree": "8.39.1" - } - } - } - }, - "@typescript-eslint/parser": { - "version": "8.39.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.39.1.tgz", - "integrity": "sha512-pUXGCuHnnKw6PyYq93lLRiZm3vjuslIy7tus1lIQTYVK9bL8XBgJnCWm8a0KcTtHC84Yya1Q6rtll+duSMj0dg==", - "dev": true, - "requires": { - "@typescript-eslint/scope-manager": "8.39.1", - "@typescript-eslint/types": "8.39.1", - "@typescript-eslint/typescript-estree": "8.39.1", - "@typescript-eslint/visitor-keys": "8.39.1", - "debug": "^4.3.4" - } - }, - "@typescript-eslint/project-service": { - "version": "8.39.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.39.1.tgz", - "integrity": "sha512-8fZxek3ONTwBu9ptw5nCKqZOSkXshZB7uAxuFF0J/wTMkKydjXCzqqga7MlFMpHi9DoG4BadhmTkITBcg8Aybw==", - "dev": true, - "requires": { - "@typescript-eslint/tsconfig-utils": "^8.39.1", - "@typescript-eslint/types": "^8.39.1", - "debug": "^4.3.4" - } - }, - "@typescript-eslint/scope-manager": { - "version": "8.39.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.39.1.tgz", - "integrity": "sha512-RkBKGBrjgskFGWuyUGz/EtD8AF/GW49S21J8dvMzpJitOF1slLEbbHnNEtAHtnDAnx8qDEdRrULRnWVx27wGBw==", - "dev": true, - "requires": { - "@typescript-eslint/types": "8.39.1", - "@typescript-eslint/visitor-keys": "8.39.1" - } - }, - "@typescript-eslint/tsconfig-utils": { - "version": "8.39.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.39.1.tgz", - "integrity": "sha512-ePUPGVtTMR8XMU2Hee8kD0Pu4NDE1CN9Q1sxGSGd/mbOtGZDM7pnhXNJnzW63zk/q+Z54zVzj44HtwXln5CvHA==", - "dev": true, - "requires": {} - }, - "@typescript-eslint/types": { - "version": "8.39.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.39.1.tgz", - "integrity": "sha512-7sPDKQQp+S11laqTrhHqeAbsCfMkwJMrV7oTDvtDds4mEofJYir414bYKUEb8YPUm9QL3U+8f6L6YExSoAGdQw==", - "dev": true - }, - "@typescript-eslint/typescript-estree": { - "version": "8.39.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.39.1.tgz", - "integrity": "sha512-EKkpcPuIux48dddVDXyQBlKdeTPMmALqBUbEk38McWv0qVEZwOpVJBi7ugK5qVNgeuYjGNQxrrnoM/5+TI/BPw==", - "dev": true, - "requires": { - "@typescript-eslint/project-service": "8.39.1", - "@typescript-eslint/tsconfig-utils": "8.39.1", - "@typescript-eslint/types": "8.39.1", - "@typescript-eslint/visitor-keys": "8.39.1", - "debug": "^4.3.4", - "fast-glob": "^3.3.2", - "is-glob": "^4.0.3", - "minimatch": "^9.0.4", - "semver": "^7.6.0", - "ts-api-utils": "^2.1.0" - } - }, - "@typescript-eslint/visitor-keys": { - "version": "8.39.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.39.1.tgz", - "integrity": "sha512-W8FQi6kEh2e8zVhQ0eeRnxdvIoOkAp/CPAahcNio6nO9dsIwb9b34z90KOlheoyuVf6LSOEdjlkxSkapNEc+4A==", - "dev": true, - "requires": { - "@typescript-eslint/types": "8.39.1", - "eslint-visitor-keys": "^4.2.1" - } - }, "argparse": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", @@ -69230,27 +68821,6 @@ "sprintf-js": "~1.0.2" } }, - "brace-expansion": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", - "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", - "dev": true, - "requires": { - "balanced-match": "^1.0.0" - } - }, - "eslint-visitor-keys": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", - "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", - "dev": true - }, - "ignore": { - "version": "7.0.5", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", - "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==", - "dev": true - }, "js-yaml": { "version": "3.14.1", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", @@ -69259,15 +68829,6 @@ "argparse": "^1.0.7", "esprima": "^4.0.0" } - }, - "minimatch": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", - "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", - "dev": true, - "requires": { - "brace-expansion": "^2.0.1" - } } } }, diff --git a/packages/compass-aggregations/src/components/aggregation-side-panel/feedback-link.tsx b/packages/compass-aggregations/src/components/aggregation-side-panel/feedback-link.tsx index 5a56a848bb0..43ea0f78580 100644 --- a/packages/compass-aggregations/src/components/aggregation-side-panel/feedback-link.tsx +++ b/packages/compass-aggregations/src/components/aggregation-side-panel/feedback-link.tsx @@ -1,7 +1,7 @@ import React from 'react'; import { css, Icon, Link, spacing } from '@mongodb-js/compass-components'; -const FEEDBACK_URL = 'https://feedback.mongodb.com/forums/924283-compass'; +const FEEDBACK_URL = 'https://feedback.mongodb.com/'; const linkContainerStyles = css({ paddingTop: spacing[1600], diff --git a/packages/compass-aggregations/src/modules/search-indexes.ts b/packages/compass-aggregations/src/modules/search-indexes.ts index c29a03c3fde..5bbf314bfd8 100644 --- a/packages/compass-aggregations/src/modules/search-indexes.ts +++ b/packages/compass-aggregations/src/modules/search-indexes.ts @@ -80,14 +80,18 @@ const reducer: Reducer = (state = INITIAL_STATE, action) => { return state; }; -export const fetchIndexes = (): PipelineBuilderThunkAction> => { +export const fetchIndexes = ( + viewNamespace?: string +): PipelineBuilderThunkAction> => { return async (dispatch, getState) => { const { - namespace, + namespace: collectionNamespace, dataService: { dataService }, searchIndexes: { status }, } = getState(); + const namespace = viewNamespace || collectionNamespace; // fetch indexes for view if passed in + if ( !dataService || status === SearchIndexesStatuses.LOADING || diff --git a/packages/compass-aggregations/src/modules/update-view.ts b/packages/compass-aggregations/src/modules/update-view.ts index 87ce2838964..7119d94a147 100644 --- a/packages/compass-aggregations/src/modules/update-view.ts +++ b/packages/compass-aggregations/src/modules/update-view.ts @@ -8,6 +8,9 @@ import { import type { PipelineBuilderThunkAction } from '.'; import { isAction } from '../utils/is-action'; import type { AnyAction } from 'redux'; +import { showConfirmation } from '@mongodb-js/compass-components'; +import { fetchIndexes } from './search-indexes'; +import { isPipelineSearchQueryable } from 'mongodb-compass/src/app/utils/view-search-queryable'; export type UpdateViewState = null | string; @@ -107,6 +110,24 @@ export const updateView = (): PipelineBuilderThunkAction> => { getState(), pipelineBuilder ); + + await dispatch(fetchIndexes(viewNamespace)); + if (state.searchIndexes.indexes.length > 0) { + const pipelineIsSearchQueryable = isPipelineSearchQueryable(viewPipeline); + const confirmed = await showConfirmation({ + title: `Are you sure you want to update the view?`, + description: pipelineIsSearchQueryable + ? 'There are search indexes created on this view. Updating the view will result in an index rebuild, which will consume additional resources on your cluster.' + : 'This update will make the view incompatible with search indexes and will cause all search indexes to fail. Only views containing $addFields, $set or $match stages with the $expr operator are compatible with search indexes.', + buttonText: 'Update', + variant: pipelineIsSearchQueryable ? 'primary' : 'danger', + }); + + if (!confirmed) { + return; + } + } + const options = { viewOn: toNS(state.namespace).collection, pipeline: viewPipeline, diff --git a/packages/compass-indexes/package.json b/packages/compass-indexes/package.json index 36f22d94867..ed0a5cfb671 100644 --- a/packages/compass-indexes/package.json +++ b/packages/compass-indexes/package.json @@ -78,6 +78,7 @@ "@mongodb-js/compass-workspaces": "^0.51.0", "@mongodb-js/mongodb-constants": "^0.12.2", "@mongodb-js/shell-bson-parser": "^1.2.0", + "@mongodb-js/connection-info": "^0.17.1", "bson": "^6.10.4", "compass-preferences-model": "^2.50.0", "lodash": "^4.17.21", diff --git a/packages/compass-indexes/src/components/indexes-toolbar/indexes-toolbar.spec.tsx b/packages/compass-indexes/src/components/indexes-toolbar/indexes-toolbar.spec.tsx index 9bac366ab8e..c9a8a7bcddb 100644 --- a/packages/compass-indexes/src/components/indexes-toolbar/indexes-toolbar.spec.tsx +++ b/packages/compass-indexes/src/components/indexes-toolbar/indexes-toolbar.spec.tsx @@ -113,27 +113,49 @@ describe('IndexesToolbar Component', function () { }); }); }); - - it('should not render a warning', function () { - expect(screen.queryByText('Readonly views may not contain indexes')).to - .not.exist; - }); }); describe('when it is a readonly view', function () { - beforeEach(function () { - renderIndexesToolbar({ - isReadonlyView: true, + describe('and server version is < 8.1+', function () { + beforeEach(function () { + renderIndexesToolbar({ + isReadonlyView: true, + indexView: 'search-indexes', + }); }); - }); - it('should not render the create index button', function () { - expect(screen.queryByText('Create Index')).to.not.exist; + it('should not render the create index button', function () { + expect(screen.queryByText('Create Index')).to.not.exist; + }); + + it('should not render the create search index button', function () { + expect(screen.queryByText('Create Search Index')).to.not.exist; + }); + + it('should not render the refresh button', function () { + expect(screen.queryByText('Refresh')).to.not.exist; + }); }); + describe('and server version is > 8.1+', function () { + beforeEach(function () { + renderIndexesToolbar({ + isReadonlyView: true, + serverVersion: '8.1.0', + indexView: 'search-indexes', + }); + }); + + it('should not render the create index button', function () { + expect(screen.queryByText('Create Index')).to.not.exist; + }); - it('should render a warning', function () { - expect(screen.getByText('Readonly views may not contain indexes.')).to.be - .visible; + it('should render the create search index button <8.1', function () { + expect(screen.getByText('Create Search Index')).to.be.visible; + }); + + it('should not render the refresh button', function () { + expect(screen.queryByText('Refresh')).to.be.visible; + }); }); }); @@ -332,5 +354,21 @@ describe('IndexesToolbar Component', function () { expect(segmentControl.closest('button')).to.have.attr('disabled'); expect(onChangeViewCallback).to.not.have.been.calledOnce; }); + + describe('and readonly view >8.1', function () { + beforeEach(function () { + renderIndexesToolbar({ + isReadonlyView: true, + serverVersion: '8.1.0', + }); + }); + + it('it renders tabs with Indexes disabled', function () { + const indexesTab = screen.getByText('Indexes'); + expect(indexesTab).to.be.visible; + expect(indexesTab.closest('button')).to.have.attr('disabled'); + expect(screen.getByText('Search Indexes')).to.be.visible; + }); + }); }); }); diff --git a/packages/compass-indexes/src/components/indexes-toolbar/indexes-toolbar.tsx b/packages/compass-indexes/src/components/indexes-toolbar/indexes-toolbar.tsx index 0989e4edee1..973dc517641 100644 --- a/packages/compass-indexes/src/components/indexes-toolbar/indexes-toolbar.tsx +++ b/packages/compass-indexes/src/components/indexes-toolbar/indexes-toolbar.tsx @@ -1,30 +1,32 @@ import React, { useCallback } from 'react'; import { connect } from 'react-redux'; import { - withPreferences, usePreference, + withPreferences, } from 'compass-preferences-model/provider'; import { Button, - ErrorSummary, - Tooltip, - WarningSummary, - Link, css, - spacing, + DropdownMenuButton, + ErrorSummary, Icon, - SpinLoader, - SignalPopover, + Link, PerformanceSignals, - DropdownMenuButton, SegmentedControl, SegmentedControlOption, + SignalPopover, + spacing, + SpinLoader, + Tooltip, } from '@mongodb-js/compass-components'; import { useConnectionInfo } from '@mongodb-js/compass-connections/provider'; import semver from 'semver'; import type { RootState } from '../../modules'; -import { createSearchIndexOpened } from '../../modules/search-indexes'; +import { + isVersionSearchCompatibleForViews, + createSearchIndexOpened, +} from '../../modules/search-indexes'; import { getAtlasSearchIndexesLink } from '../../utils/atlas-search-indexes-link'; import { createIndexOpened } from '../../modules/create-index'; import type { IndexView } from '../../modules/index-view'; @@ -109,7 +111,10 @@ export const IndexesToolbar: React.FunctionComponent = ({ const isSearchManagementActive = usePreference('enableAtlasSearchIndexes'); const { atlasMetadata } = useConnectionInfo(); const showInsights = usePreference('showInsights') && !errorMessage; - const showCreateIndexButton = !isReadonlyView && !readOnly && !errorMessage; + const showCreateIndexButton = + (!isReadonlyView || isVersionSearchCompatibleForViews(serverVersion)) && + !readOnly && + !errorMessage; const refreshButtonIcon = isRefreshing ? (
@@ -123,7 +128,9 @@ export const IndexesToolbar: React.FunctionComponent = ({ className={indexesToolbarContainerStyles} data-testid="indexes-toolbar-container" > - {!isReadonlyView && ( + {(!isReadonlyView || + (isVersionSearchCompatibleForViews(serverVersion) && + isSearchManagementActive)) && (
{showCreateIndexButton && ( @@ -139,7 +146,9 @@ export const IndexesToolbar: React.FunctionComponent = ({ isWritable={isWritable} onCreateRegularIndexClick={onCreateRegularIndexClick} onCreateSearchIndexClick={onCreateSearchIndexClick} - > + isReadonlyView={isReadonlyView} + indexView={indexView} + />
} > @@ -173,6 +182,7 @@ export const IndexesToolbar: React.FunctionComponent = ({ signals={PerformanceSignals.get('too-many-indexes')} /> )} + {isSearchManagementActive && ( = ({ value={indexView} data-testid="indexes-segment-controls" > - - Indexes - - {!isSearchIndexesSupported && ( + {isReadonlyView && ( + + Indexes + + } + > + Readonly views may not contain standard indexes. + + )} + {!isReadonlyView && ( + + Indexes + + )} + {!isSearchIndexesSupported && !isReadonlyView && ( = ({ )} )} - {isSearchIndexesSupported && ( + {(isSearchIndexesSupported || isReadonlyView) && ( = ({
)} - {isReadonlyView ? ( - - ) : ( - !!errorMessage && ( - - ) + {!!errorMessage && isSearchManagementActive && ( + )} ); @@ -259,6 +284,8 @@ type CreateIndexButtonProps = { isWritable: boolean; onCreateRegularIndexClick: () => void; onCreateSearchIndexClick: () => void; + isReadonlyView: boolean; + indexView: IndexView; }; type CreateIndexActions = 'createRegularIndex' | 'createSearchIndex'; @@ -271,6 +298,8 @@ export const CreateIndexButton: React.FunctionComponent< isWritable, onCreateRegularIndexClick, onCreateSearchIndexClick, + isReadonlyView, + indexView, }) => { const onActionDispatch = useCallback( (action: CreateIndexActions) => { @@ -284,7 +313,23 @@ export const CreateIndexButton: React.FunctionComponent< [onCreateRegularIndexClick, onCreateSearchIndexClick] ); - if (isSearchIndexesSupported && isSearchManagementActive) { + if (isReadonlyView && isSearchManagementActive) { + if (indexView === 'search-indexes') { + return ( + + ); + } + + return null; + } + if (!isReadonlyView && isSearchIndexesSupported && isSearchManagementActive) { return ( = { - indexView: props.indexView ?? 'regular-indexes', - regularIndexes: { - ...state.regularIndexes, - ...props.regularIndexes, - }, - searchIndexes: { - ...state.searchIndexes, - ...props.searchIndexes, - }, - }; - - Object.assign(store.getState(), allProps); + const newState = { ...state, ...props }; + Object.assign(store.getState(), newState); } render( @@ -332,5 +320,76 @@ describe('Indexes Component', function () { expect(getSearchIndexesStub.callCount).to.equal(2); }); + + it('renders search indexes list if isReadonlyView 8.1+ and has indexes', async function () { + const getSearchIndexesStub = sinon.stub().resolves(searchIndexes); + const dataProvider = { + getSearchIndexes: getSearchIndexesStub, + }; + await renderIndexes(undefined, dataProvider, { + indexView: 'search-indexes', + isReadonlyView: true, + serverVersion: '8.1.0', + }); + + await waitFor(() => { + expect(screen.getByTestId('search-indexes-list')).to.exist; + }); + }); + + it('renders correct empty state if isReadonlyView 8.1+ and has no indexes', async function () { + const getSearchIndexesStub = sinon.stub().resolves([]); + const dataProvider = { + getSearchIndexes: getSearchIndexesStub, + }; + await renderIndexes(undefined, dataProvider, { + indexView: 'search-indexes', + isReadonlyView: true, + serverVersion: '8.1.0', + }); + + expect(screen.getByText('No search indexes yet')).to.be.visible; + expect(screen.getByText('Create Atlas Search Index')).to.be.visible; + }); + + it('renders correct empty state if isReadonlyView 8.0 and has no indexes', async function () { + const getSearchIndexesStub = sinon.stub().resolves([]); + const dataProvider = { + getSearchIndexes: getSearchIndexesStub, + }; + await renderIndexes(undefined, dataProvider, { + indexView: 'search-indexes', + isReadonlyView: true, + serverVersion: '8.0.0', + }); + + expect( + screen.queryByText( + /Upgrade your cluster or manage search indexes on views in the Atlas UI./i + ) + ).to.exist; + expect(screen.queryByText('No standard indexes')).to.exist; + expect(screen.queryByText('Create Atlas Search Index')).to.not.exist; + }); + + it('renders correct empty state if isReadonlyView <8.0 and has no indexes', async function () { + const getSearchIndexesStub = sinon.stub().resolves([]); + const dataProvider = { + getSearchIndexes: getSearchIndexesStub, + }; + await renderIndexes(undefined, dataProvider, { + indexView: 'search-indexes', + isReadonlyView: true, + serverVersion: '7.0.0', + }); + + expect( + screen.queryByText( + /Upgrade your cluster to create search indexes on views./i + ) + ).to.exist; + expect(screen.queryByText('No standard indexes')).to.exist; + expect(screen.queryByText('Create Atlas Search Index')).to.not.exist; + }); }); }); diff --git a/packages/compass-indexes/src/components/indexes/indexes.tsx b/packages/compass-indexes/src/components/indexes/indexes.tsx index 0e512e13ce2..ce140d022fe 100644 --- a/packages/compass-indexes/src/components/indexes/indexes.tsx +++ b/packages/compass-indexes/src/components/indexes/indexes.tsx @@ -2,19 +2,23 @@ import React from 'react'; import { connect } from 'react-redux'; import { Banner, - Body, Link, WorkspaceContainer, css, spacing, usePersistedState, + EmptyContent, + Body, } from '@mongodb-js/compass-components'; import IndexesToolbar from '../indexes-toolbar/indexes-toolbar'; import RegularIndexesTable from '../regular-indexes-table/regular-indexes-table'; import SearchIndexesTable from '../search-indexes-table/search-indexes-table'; import { refreshRegularIndexes } from '../../modules/regular-indexes'; -import { refreshSearchIndexes } from '../../modules/search-indexes'; +import { + isVersionSearchCompatibleForViews, + refreshSearchIndexes, +} from '../../modules/search-indexes'; import type { State as RegularIndexesState } from '../../modules/regular-indexes'; import type { State as SearchIndexesState } from '../../modules/search-indexes'; import { FetchStatuses } from '../../utils/fetch-status'; @@ -29,6 +33,9 @@ import { usePreference } from 'compass-preferences-model/provider'; import { useConnectionInfo } from '@mongodb-js/compass-connections/provider'; import { getAtlasSearchIndexesLink } from '../../utils/atlas-search-indexes-link'; import CreateIndexModal from '../create-index-modal/create-index-modal'; +import { ZeroGraphic } from '../search-indexes-table/zero-graphic'; +import { ViewVersionIncompatibleBanner } from '../view-version-incompatible-banners/view-version-incompatible-banners'; +import semver from 'semver'; // This constant is used as a trigger to show an insight whenever number of // indexes in a collection is more than what is specified here. @@ -48,6 +55,51 @@ const linkTitle = 'Search and Vector Search.'; const DISMISSED_SEARCH_INDEXES_BANNER_LOCAL_STORAGE_KEY = 'mongodb_compass_dismissedSearchIndexesBanner' as const; +export const MIN_VERSION_FOR_VIEW_SEARCH_COMPATIBILITY_DE = '8.0.0'; +export const isVersionSearchCompatibleForViewsDataExplorer = ( + serverVersion: string +) => { + try { + return semver.gte( + serverVersion, + MIN_VERSION_FOR_VIEW_SEARCH_COMPATIBILITY_DE + ); + } catch { + return false; + } +}; + +const ViewVersionIncompatibleEmptyState = ({ + serverVersion, + enableAtlasSearchIndexes, +}: { + serverVersion: string; + enableAtlasSearchIndexes: boolean; +}) => { + if ( + isVersionSearchCompatibleForViews(serverVersion) && + enableAtlasSearchIndexes + ) { + return null; + } + return ( + + Learn more about views + + } + /> + ); +}; + const AtlasIndexesBanner = ({ namespace, dismissed, @@ -92,6 +144,7 @@ type IndexesProps = { currentIndexesView: IndexView; refreshRegularIndexes: () => void; refreshSearchIndexes: () => void; + serverVersion: string; }; function isRefreshingStatus(status: FetchStatus) { @@ -117,6 +170,7 @@ export function Indexes({ currentIndexesView, refreshRegularIndexes, refreshSearchIndexes, + serverVersion, }: IndexesProps) { const [atlasBannerDismissed, setDismissed] = usePersistedState( DISMISSED_SEARCH_INDEXES_BANNER_LOCAL_STORAGE_KEY, @@ -143,6 +197,7 @@ export function Indexes({ : refreshSearchIndexes; const enableAtlasSearchIndexes = usePreference('enableAtlasSearchIndexes'); + const { atlasMetadata } = useConnectionInfo(); return (
@@ -162,8 +217,17 @@ export function Indexes({ } >
- {!isReadonlyView && !enableAtlasSearchIndexes && ( - + )} + {(!isReadonlyView || + (isVersionSearchCompatibleForViewsDataExplorer(serverVersion) && + !enableAtlasSearchIndexes)) && ( + { @@ -174,8 +238,15 @@ export function Indexes({ {!isReadonlyView && currentIndexesView === 'regular-indexes' && ( )} - {!isReadonlyView && currentIndexesView === 'search-indexes' && ( - + {(!isReadonlyView || + (isVersionSearchCompatibleForViews(serverVersion) && + enableAtlasSearchIndexes)) && + currentIndexesView === 'search-indexes' && } + {isReadonlyView && searchIndexes.indexes.length === 0 && ( + )}
@@ -192,12 +263,14 @@ const mapState = ({ regularIndexes, searchIndexes, indexView, + serverVersion, }: RootState) => ({ namespace, isReadonlyView, regularIndexes, searchIndexes, currentIndexesView: indexView, + serverVersion, }); const mapDispatch = { diff --git a/packages/compass-indexes/src/components/view-version-incompatible-banners/view-version-incompatible-banners.tsx b/packages/compass-indexes/src/components/view-version-incompatible-banners/view-version-incompatible-banners.tsx new file mode 100644 index 00000000000..560edc79e95 --- /dev/null +++ b/packages/compass-indexes/src/components/view-version-incompatible-banners/view-version-incompatible-banners.tsx @@ -0,0 +1,70 @@ +import { + Banner, + BannerVariant, + Button, + css, +} from '@mongodb-js/compass-components'; +import { getAtlasUpgradeClusterLink } from '../../utils/atlas-upgrade-cluster-link'; +import React from 'react'; +import type { AtlasClusterMetadata } from '@mongodb-js/connection-info'; +import { isVersionSearchCompatibleForViews } from '../../modules/search-indexes'; +import { isVersionSearchCompatibleForViewsDataExplorer } from '../indexes/indexes'; + +const viewContentStyles = css({ + display: 'flex', + justifyContent: 'space-between', + alignItems: 'center', + width: '100%', +}); + +export const ViewVersionIncompatibleBanner = ({ + serverVersion, + enableAtlasSearchIndexes, + atlasMetadata, +}: { + serverVersion: string; + enableAtlasSearchIndexes: boolean; + atlasMetadata: AtlasClusterMetadata | undefined; +}) => { + // return if compatible, 8.1+ for compass and 8.0+ for data explorer + if ( + isVersionSearchCompatibleForViews(serverVersion) || + (isVersionSearchCompatibleForViewsDataExplorer(serverVersion) && + !enableAtlasSearchIndexes) + ) { + return null; + } + + const searchIndexOnViewsMinVersion = enableAtlasSearchIndexes ? '8.1' : '8.0'; + // if compass version matches min compatibility for DE, we recommend Atlas UI as well + const recommendedCta = + enableAtlasSearchIndexes && + isVersionSearchCompatibleForViewsDataExplorer(serverVersion) + ? 'Upgrade your cluster or manage search indexes on views in the Atlas UI.' + : 'Upgrade your cluster to create search indexes on views.'; + return ( + + Looking for search indexes? +
+
+ + Your MongoDB version is {serverVersion}. Creating and managing search + indexes on views {enableAtlasSearchIndexes && 'in Compass'} is + supported on MongoDB version {searchIndexOnViewsMinVersion} or higher.{' '} + {recommendedCta} + + {atlasMetadata && ( + + )} +
+
+ ); +}; diff --git a/packages/compass-indexes/src/modules/index-view.spec.ts b/packages/compass-indexes/src/modules/index-view.spec.ts index 9456662562d..a54ccb33186 100644 --- a/packages/compass-indexes/src/modules/index-view.spec.ts +++ b/packages/compass-indexes/src/modules/index-view.spec.ts @@ -1,7 +1,7 @@ import { expect } from 'chai'; import reducer, { - INITIAL_STATE, + COLL_INITIAL_STATE, switchToRegularIndexes, switchToSearchIndexes, } from './index-view'; @@ -10,15 +10,15 @@ describe('index-view view module', function () { describe('#reducer', function () { context('when an action is not valid', function () { it('returns the state', function () { - expect(reducer(INITIAL_STATE, { type: 'test' })).to.equal( - INITIAL_STATE + expect(reducer(COLL_INITIAL_STATE, { type: 'test' })).to.equal( + COLL_INITIAL_STATE ); }); }); context('when an action is switchToRegularIndexes', function () { it('state is regular-indexes', function () { - expect(reducer(INITIAL_STATE, switchToRegularIndexes())).to.equal( + expect(reducer(COLL_INITIAL_STATE, switchToRegularIndexes())).to.equal( 'regular-indexes' ); }); @@ -26,7 +26,7 @@ describe('index-view view module', function () { context('when an action is switchToSearchIndexes', function () { it('state is search-indexes', function () { - expect(reducer(INITIAL_STATE, switchToSearchIndexes())).to.equal( + expect(reducer(COLL_INITIAL_STATE, switchToSearchIndexes())).to.equal( 'search-indexes' ); }); diff --git a/packages/compass-indexes/src/modules/index-view.ts b/packages/compass-indexes/src/modules/index-view.ts index 1abceef58d3..5a48c99e54b 100644 --- a/packages/compass-indexes/src/modules/index-view.ts +++ b/packages/compass-indexes/src/modules/index-view.ts @@ -18,10 +18,11 @@ export type IndexViewChangedAction = { view: IndexView; }; -export const INITIAL_STATE: IndexView = 'regular-indexes'; +export const COLL_INITIAL_STATE: IndexView = 'regular-indexes'; +export const VIEW_INITIAL_STATE: IndexView = 'search-indexes'; export default function reducer( - state = INITIAL_STATE, + state = COLL_INITIAL_STATE, action: AnyAction ): IndexView { // The create index button has a dropdown where you can select regular or diff --git a/packages/compass-indexes/src/modules/search-indexes.ts b/packages/compass-indexes/src/modules/search-indexes.ts index 7925f05a05c..cd25495795e 100644 --- a/packages/compass-indexes/src/modules/search-indexes.ts +++ b/packages/compass-indexes/src/modules/search-indexes.ts @@ -17,6 +17,7 @@ import type { FetchReason } from '../utils/fetch-reason'; import type { IndexesThunkAction } from '.'; import { switchToSearchIndexes } from './index-view'; import type { IndexViewChangedAction } from './index-view'; +import semver from 'semver'; const ATLAS_SEARCH_SERVER_ERRORS: Record = { InvalidIndexSpecificationOption: 'Invalid index definition.', @@ -24,6 +25,18 @@ const ATLAS_SEARCH_SERVER_ERRORS: Record = { 'This index name is already in use. Please choose another one.', }; +const MIN_VERSION_FOR_VIEW_SEARCH_COMPATIBILITY_COMPASS = '8.1.0'; +export const isVersionSearchCompatibleForViews = (serverVersion: string) => { + try { + return semver.gte( + serverVersion, + MIN_VERSION_FOR_VIEW_SEARCH_COMPATIBILITY_COMPASS + ); + } catch { + return false; + } +}; + export enum ActionTypes { // Fetch indexes FetchSearchIndexesStarted = 'compass-indexes/search-indexes/fetch-search-indexes-started', @@ -602,11 +615,15 @@ const fetchIndexes = ( isReadonlyView, isWritable, namespace, + serverVersion, searchIndexes: { status }, } = getState(); - if (isReadonlyView || !isWritable) { - return; + if ( + (isReadonlyView && !isVersionSearchCompatibleForViews(serverVersion)) || + !isWritable + ) { + return; // return if view is not search compatible } // If we are already fetching indexes, we will wait for that diff --git a/packages/compass-indexes/src/stores/store.ts b/packages/compass-indexes/src/stores/store.ts index 07d84d3814e..5e547467495 100644 --- a/packages/compass-indexes/src/stores/store.ts +++ b/packages/compass-indexes/src/stores/store.ts @@ -5,7 +5,8 @@ import reducer from '../modules'; import thunk from 'redux-thunk'; import { writeStateChanged } from '../modules/is-writable'; import { getDescription } from '../modules/description'; -import { INITIAL_STATE as INDEX_LIST_INITIAL_STATE } from '../modules/index-view'; +import { COLL_INITIAL_STATE, VIEW_INITIAL_STATE } from '../modules/index-view'; + import { createIndexOpened } from '../modules/create-index'; import { fetchRegularIndexes, @@ -106,7 +107,7 @@ export function activateIndexesPlugin( serverVersion: options.serverVersion, isReadonlyView: options.isReadonly, isSearchIndexesSupported: options.isSearchIndexesSupported, - indexView: INDEX_LIST_INITIAL_STATE, + indexView: options.isReadonly ? VIEW_INITIAL_STATE : COLL_INITIAL_STATE, collectionStats: extractCollectionStats(collectionModel), }, applyMiddleware( @@ -156,7 +157,8 @@ export function activateIndexesPlugin( }); void store.dispatch(fetchRegularIndexes()); - if (options.isSearchIndexesSupported) { + + if (options.isSearchIndexesSupported || options.isReadonly) { void store.dispatch(fetchSearchIndexes()); } diff --git a/packages/compass-indexes/src/utils/atlas-upgrade-cluster-link.ts b/packages/compass-indexes/src/utils/atlas-upgrade-cluster-link.ts new file mode 100644 index 00000000000..1fbb95351f8 --- /dev/null +++ b/packages/compass-indexes/src/utils/atlas-upgrade-cluster-link.ts @@ -0,0 +1,7 @@ +export function getAtlasUpgradeClusterLink({ + clusterName, +}: { + clusterName: string; +}) { + return `#/clusters/edit/${encodeURIComponent(clusterName)}`; +} diff --git a/packages/compass/README.md b/packages/compass/README.md index 89accf51c27..d52e6f2dfd0 100644 --- a/packages/compass/README.md +++ b/packages/compass/README.md @@ -67,7 +67,7 @@ For contributing, please refer to Is there anything else you’d like to see in Compass? Let us know by submitting suggestions in out [feedback -forum](https://feedback.mongodb.com/forums/924283-compass). +forum](https://feedback.mongodb.com/). # License diff --git a/packages/compass/src/app/utils/view-search-queryable.ts b/packages/compass/src/app/utils/view-search-queryable.ts new file mode 100644 index 00000000000..b6a1fa8d433 --- /dev/null +++ b/packages/compass/src/app/utils/view-search-queryable.ts @@ -0,0 +1,30 @@ +export const isPipelineSearchQueryable = ( + pipeline: Array> +): boolean => { + for (const stage of pipeline) { + const stageKey = Object.keys(stage)[0]; + + // Check if the stage is $addFields, $set, or $match + if ( + !( + stageKey === '$addFields' || + stageKey === '$set' || + stageKey === '$match' + ) + ) { + return false; + } + + // If the stage is $match, check if uses $expr + if (stageKey === '$match') { + const matchStage = stage['$match']; + const matchKeys = Object.keys(matchStage); + + if (!(matchKeys.length === 1 && matchKeys.includes('$expr'))) { + return false; + } + } + } + + return true; +}; diff --git a/packages/compass/src/main/menu.ts b/packages/compass/src/main/menu.ts index 6cffaad0022..e3e3662b284 100644 --- a/packages/compass/src/main/menu.ts +++ b/packages/compass/src/main/menu.ts @@ -254,9 +254,7 @@ function feedbackForumLink(): MenuItemConstructorOptions { return { label: `&Suggest a Feature`, click() { - void shell.openExternal( - 'https://feedback.mongodb.com/forums/924283-compass' - ); + void shell.openExternal('https://feedback.mongodb.com/'); }, }; } From fe7c78113e1a3819accc0703565ff8207379e795 Mon Sep 17 00:00:00 2001 From: Darshana Venkatesh Date: Mon, 18 Aug 2025 15:59:47 -0700 Subject: [PATCH 02/22] add version incompatible banner --- .../indexes-toolbar/indexes-toolbar.tsx | 28 +++++++-- .../src/components/indexes/indexes.tsx | 60 ++++++++++++++++--- .../src/modules/collection-stats.ts | 5 +- 3 files changed, 78 insertions(+), 15 deletions(-) diff --git a/packages/compass-indexes/src/components/indexes-toolbar/indexes-toolbar.tsx b/packages/compass-indexes/src/components/indexes-toolbar/indexes-toolbar.tsx index 973dc517641..71b5f4582f5 100644 --- a/packages/compass-indexes/src/components/indexes-toolbar/indexes-toolbar.tsx +++ b/packages/compass-indexes/src/components/indexes-toolbar/indexes-toolbar.tsx @@ -31,6 +31,8 @@ import { getAtlasSearchIndexesLink } from '../../utils/atlas-search-indexes-link import { createIndexOpened } from '../../modules/create-index'; import type { IndexView } from '../../modules/index-view'; import { indexViewChanged } from '../../modules/index-view'; +import { CollectionStats } from '../../modules/collection-stats'; +import { isPipelineSearchQueryable } from 'mongodb-compass/src/app/utils/view-search-queryable'; const toolbarButtonsContainer = css({ display: 'flex', @@ -88,6 +90,7 @@ type IndexesToolbarProps = { isSearchIndexesSupported: boolean; // via withPreferences: readOnly?: boolean; + collectionStats: CollectionStats; }; export const IndexesToolbar: React.FunctionComponent = ({ @@ -107,6 +110,7 @@ export const IndexesToolbar: React.FunctionComponent = ({ onIndexViewChanged, serverVersion, readOnly, // preferences readOnly. + collectionStats, }) => { const isSearchManagementActive = usePreference('enableAtlasSearchIndexes'); const { atlasMetadata } = useConnectionInfo(); @@ -122,7 +126,14 @@ export const IndexesToolbar: React.FunctionComponent = ({ ) : ( ); - + const isViewPipelineSearchQueryable = + isReadonlyView && + collectionStats?.pipeline && + isPipelineSearchQueryable( + collectionStats.pipeline as Array> + ); + const pipelineNotSearchQueryableDescription = + 'Search indexes can only be created on views containing $addFields, $set or $match stages with the $expr operator.'; return (
= ({
{showCreateIndexButton && ( = ({ onCreateSearchIndexClick={onCreateSearchIndexClick} isReadonlyView={isReadonlyView} indexView={indexView} + isViewPipelineSearchQueryable={ + isViewPipelineSearchQueryable + } />
} > - {writeStateDescription} + {(!isWritable && writeStateDescription) || + (!isViewPipelineSearchQueryable && + pipelineNotSearchQueryableDescription)} )} + } > - Create Atlas Search Index - + Search indexes can only be created on views containing $addFields, + $set or $match stages with the $expr operator. + } callToActionLink={ @@ -283,6 +300,7 @@ export const SearchIndexesTable: React.FunctionComponent< namespace, indexes, isWritable, + collectionStats, readOnly, status, onOpenCreateModalClick, @@ -302,7 +320,13 @@ export const SearchIndexesTable: React.FunctionComponent< onSearchIndexesClosed(tabId); }; }, [tabId, onSearchIndexesOpened, onSearchIndexesClosed]); - + const isViewPipelineSearchQueryable = + (readOnly && + collectionStats?.pipeline && + isPipelineSearchQueryable( + collectionStats.pipeline as Array> + )) ?? + true; const data = useMemo[]>( () => indexes.map((index) => { @@ -384,7 +408,12 @@ export const SearchIndexesTable: React.FunctionComponent< } if (indexes.length === 0) { - return ; + return ( + + ); } const canModifyIndex = isWritable && !readOnly; @@ -399,9 +428,15 @@ export const SearchIndexesTable: React.FunctionComponent< ); }; -const mapState = ({ searchIndexes, isWritable, namespace }: RootState) => ({ +const mapState = ({ + searchIndexes, + isWritable, + namespace, + collectionStats, +}: RootState) => ({ namespace, isWritable, + collectionStats, indexes: searchIndexes.indexes, status: searchIndexes.status, }); From 80ba8916e211d217c4e7b1b20e1134da0f2aed9f Mon Sep 17 00:00:00 2001 From: Darshana Venkatesh Date: Mon, 18 Aug 2025 17:10:46 -0700 Subject: [PATCH 04/22] fix incorrect readonly --- .../search-indexes-table/search-indexes-table.tsx | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/packages/compass-indexes/src/components/search-indexes-table/search-indexes-table.tsx b/packages/compass-indexes/src/components/search-indexes-table/search-indexes-table.tsx index 39cdfc97c86..cda2ec0f6eb 100644 --- a/packages/compass-indexes/src/components/search-indexes-table/search-indexes-table.tsx +++ b/packages/compass-indexes/src/components/search-indexes-table/search-indexes-table.tsx @@ -41,13 +41,13 @@ import { useConnectionInfo } from '@mongodb-js/compass-connections/provider'; import { useWorkspaceTabId } from '@mongodb-js/compass-workspaces/provider'; import type { CollectionStats } from '../../modules/collection-stats'; import { isPipelineSearchQueryable } from 'mongodb-compass/src/app/utils/view-search-queryable'; -import { CreateIndexButton } from '../indexes-toolbar/indexes-toolbar'; type SearchIndexesTableProps = { namespace: string; indexes: SearchIndex[]; isWritable?: boolean; readOnly?: boolean; + isReadonlyView: boolean; collectionStats?: CollectionStats; status: FetchStatus; onDropIndexClick: (name: string) => void; @@ -308,6 +308,7 @@ export const SearchIndexesTable: React.FunctionComponent< onDropIndexClick, onSearchIndexesOpened, onSearchIndexesClosed, + isReadonlyView, }) => { const { openCollectionWorkspace } = useOpenWorkspace(); const { id: connectionId } = useConnectionInfo(); @@ -321,7 +322,7 @@ export const SearchIndexesTable: React.FunctionComponent< }; }, [tabId, onSearchIndexesOpened, onSearchIndexesClosed]); const isViewPipelineSearchQueryable = - (readOnly && + (isReadonlyView && collectionStats?.pipeline && isPipelineSearchQueryable( collectionStats.pipeline as Array> @@ -433,10 +434,12 @@ const mapState = ({ isWritable, namespace, collectionStats, + isReadonlyView, }: RootState) => ({ namespace, isWritable, collectionStats, + isReadonlyView, indexes: searchIndexes.indexes, status: searchIndexes.status, }); From fd085b6245750250159e85b3e0a3a668fd57d066 Mon Sep 17 00:00:00 2001 From: Darshana Venkatesh Date: Tue, 19 Aug 2025 15:37:40 -0700 Subject: [PATCH 05/22] add tests --- .../src/modules/search-indexes.ts | 2 +- .../src/modules/update-view.spec.ts | 33 ++++ .../src/modules/update-view.ts | 4 +- .../indexes-toolbar/indexes-toolbar.spec.tsx | 28 +++- .../indexes-toolbar/indexes-toolbar.tsx | 6 +- .../src/components/indexes/indexes.spec.tsx | 152 +++++++++++------- .../src/components/indexes/indexes.tsx | 6 +- .../search-indexes-table.spec.tsx | 20 +++ .../view-version-incompatible-banners.tsx | 5 +- .../app/utils/view-search-queryable.spec.ts | 69 ++++++++ .../src/app/utils/view-search-queryable.ts | 12 +- 11 files changed, 260 insertions(+), 77 deletions(-) create mode 100644 packages/compass/src/app/utils/view-search-queryable.spec.ts diff --git a/packages/compass-aggregations/src/modules/search-indexes.ts b/packages/compass-aggregations/src/modules/search-indexes.ts index 5bbf314bfd8..341f1d0f283 100644 --- a/packages/compass-aggregations/src/modules/search-indexes.ts +++ b/packages/compass-aggregations/src/modules/search-indexes.ts @@ -90,7 +90,7 @@ export const fetchIndexes = ( searchIndexes: { status }, } = getState(); - const namespace = viewNamespace || collectionNamespace; // fetch indexes for view if passed in + const namespace = viewNamespace || collectionNamespace; if ( !dataService || diff --git a/packages/compass-aggregations/src/modules/update-view.spec.ts b/packages/compass-aggregations/src/modules/update-view.spec.ts index 4e0c6603d4f..fdab54aa4a2 100644 --- a/packages/compass-aggregations/src/modules/update-view.spec.ts +++ b/packages/compass-aggregations/src/modules/update-view.spec.ts @@ -10,6 +10,9 @@ import { } from '@mongodb-js/compass-connections/provider'; import { createDefaultConnectionInfo } from '@mongodb-js/testing-library-compass'; +// Importing this to stub showConfirmation +import * as updateViewSlice from './update-view'; + const TEST_CONNECTION_INFO = { ...createDefaultConnectionInfo(), title: '' }; describe('update-view module', function () { @@ -48,15 +51,18 @@ describe('update-view module', function () { let stateMock: any; let getStateMock: () => any; let updateCollectionFake = sinon.fake(); + let showConfirmationStub: sinon.SinonStub; beforeEach(async function () { dispatchFake = sinon.fake(); updateCollectionFake = sinon.fake.resolves(undefined); + showConfirmationStub = sinon.stub(updateViewSlice, 'showConfirmation'); stateMock = { pipelineBuilder: { pipelineMode: 'builder-ui' }, focusMode: { isEnabled: false }, namespace: 'aa.bb', editViewName: 'aa.bb', + searchIndexes: { indexes: [{ name: 'index1' }] }, dataService: { dataService: { updateCollection: updateCollectionFake, @@ -69,12 +75,39 @@ describe('update-view module', function () { await runUpdateView(dispatchFake, getStateMock, thunkArg as any); }); + afterEach(function () { + showConfirmationStub.restore(); + }); + it('first it calls to dismiss any existing error', function () { expect(dispatchFake.firstCall.args[0]).to.deep.equal({ type: 'aggregations/update-view/DISMISS_VIEW_UPDATE_ERROR', }); }); + it('shows confirmation banner when search indexes are present', async function () { + showConfirmationStub.resolves(true); + + const runUpdateView = updateView(); + await runUpdateView(dispatchFake, getStateMock, thunkArg as any); + + expect(showConfirmationStub.calledOnce).to.be.true; + expect(showConfirmationStub.firstCall.args[0]).to.deep.include({ + title: `Are you sure you want to update the view?`, + buttonText: 'Update', + }); + }); + + it('does not update view if not confirmed', async function () { + getStateMock = () => stateMock; + showConfirmationStub.resolves(false); + + const runUpdateView = updateView(); + await runUpdateView(dispatchFake, getStateMock, thunkArg as any); + + expect(updateCollectionFake.calledOnce).to.be.false; + }); + it('calls the data service to update the view for the provided ns', function () { expect(updateCollectionFake.firstCall.args[0]).to.equal('aa.bb'); expect(updateCollectionFake.firstCall.args[1]).to.deep.equal({ diff --git a/packages/compass-aggregations/src/modules/update-view.ts b/packages/compass-aggregations/src/modules/update-view.ts index d1b01f964d0..c6b9c43a26e 100644 --- a/packages/compass-aggregations/src/modules/update-view.ts +++ b/packages/compass-aggregations/src/modules/update-view.ts @@ -8,7 +8,7 @@ import { import type { PipelineBuilderThunkAction } from '.'; import { isAction } from '../utils/is-action'; import type { AnyAction } from 'redux'; -import { showConfirmation } from '@mongodb-js/compass-components'; +import { showConfirmation as showConfirmationModal } from '@mongodb-js/compass-components'; import { fetchIndexes } from './search-indexes'; import { isPipelineSearchQueryable } from 'mongodb-compass/src/app/utils/view-search-queryable'; @@ -76,6 +76,8 @@ export const dismissViewError = (): DismissViewUpdateErrorAction => ({ type: DISMISS_VIEW_UPDATE_ERROR, }); +//Exporting this for test only to stub it and set its value +export const showConfirmation = showConfirmationModal; /** * Updates a view. * diff --git a/packages/compass-indexes/src/components/indexes-toolbar/indexes-toolbar.spec.tsx b/packages/compass-indexes/src/components/indexes-toolbar/indexes-toolbar.spec.tsx index c9a8a7bcddb..4766549c1c1 100644 --- a/packages/compass-indexes/src/components/indexes-toolbar/indexes-toolbar.spec.tsx +++ b/packages/compass-indexes/src/components/indexes-toolbar/indexes-toolbar.spec.tsx @@ -13,6 +13,8 @@ import { IndexesToolbar } from './indexes-toolbar'; import type { PreferencesAccess } from 'compass-preferences-model'; import { createSandboxFromDefaultPreferences } from 'compass-preferences-model'; import { PreferencesProvider } from 'compass-preferences-model/provider'; +import type { Document } from 'mongodb'; +//import type {Document} from "mongodb"; describe('IndexesToolbar Component', function () { before(cleanup); @@ -153,10 +155,34 @@ describe('IndexesToolbar Component', function () { expect(screen.getByText('Create Search Index')).to.be.visible; }); - it('should not render the refresh button', function () { + it('should render the refresh button', function () { expect(screen.queryByText('Refresh')).to.be.visible; }); }); + + describe('and pipeline is not queryable', function () { + it('should disable the create search index button', function () { + const pipelineMock: Document[] = [ + { $project: { newField: 'testValue' } }, + ]; + const mockCollectionStats = { pipeline: pipelineMock }; + + renderIndexesToolbar({ + isReadonlyView: true, + serverVersion: '8.1.0', + indexView: 'search-indexes', + collectionStats: mockCollectionStats, + }); + + expect(screen.getByText('Create Search Index')).to.be.visible; + expect( + screen + .getByText('Create Search Index') + .closest('button') + ?.getAttribute('aria-disabled') + ).to.equal('true'); + }); + }); }); describe('when it is preferences ReadOnly', function () { diff --git a/packages/compass-indexes/src/components/indexes-toolbar/indexes-toolbar.tsx b/packages/compass-indexes/src/components/indexes-toolbar/indexes-toolbar.tsx index eddb23fdb5c..9406b646f78 100644 --- a/packages/compass-indexes/src/components/indexes-toolbar/indexes-toolbar.tsx +++ b/packages/compass-indexes/src/components/indexes-toolbar/indexes-toolbar.tsx @@ -31,7 +31,7 @@ import { getAtlasSearchIndexesLink } from '../../utils/atlas-search-indexes-link import { createIndexOpened } from '../../modules/create-index'; import type { IndexView } from '../../modules/index-view'; import { indexViewChanged } from '../../modules/index-view'; -import { CollectionStats } from '../../modules/collection-stats'; +import type { CollectionStats } from '../../modules/collection-stats'; import { isPipelineSearchQueryable } from 'mongodb-compass/src/app/utils/view-search-queryable'; const toolbarButtonsContainer = css({ @@ -129,9 +129,7 @@ export const IndexesToolbar: React.FunctionComponent = ({ const isViewPipelineSearchQueryable = (isReadonlyView && collectionStats?.pipeline && - isPipelineSearchQueryable( - collectionStats.pipeline as Array> - )) ?? + isPipelineSearchQueryable(collectionStats.pipeline as Document[])) ?? true; const pipelineNotSearchQueryableDescription = 'Search indexes can only be created on views containing $addFields, $set or $match stages with the $expr operator.'; diff --git a/packages/compass-indexes/src/components/indexes/indexes.spec.tsx b/packages/compass-indexes/src/components/indexes/indexes.spec.tsx index adad0f84c45..370e79e0edd 100644 --- a/packages/compass-indexes/src/components/indexes/indexes.spec.tsx +++ b/packages/compass-indexes/src/components/indexes/indexes.spec.tsx @@ -19,6 +19,7 @@ import Indexes from './indexes'; import { setupStore } from '../../../test/setup-store'; import { searchIndexes } from '../../../test/fixtures/search-indexes'; import type { RootState } from '../../modules'; +import type { Document } from 'mongodb'; const renderIndexes = async ( options: Partial = {}, @@ -321,75 +322,108 @@ describe('Indexes Component', function () { expect(getSearchIndexesStub.callCount).to.equal(2); }); - it('renders search indexes list if isReadonlyView 8.1+ and has indexes', async function () { - const getSearchIndexesStub = sinon.stub().resolves(searchIndexes); - const dataProvider = { - getSearchIndexes: getSearchIndexesStub, - }; - await renderIndexes(undefined, dataProvider, { - indexView: 'search-indexes', - isReadonlyView: true, - serverVersion: '8.1.0', - }); + describe('when isReadonly view', function () { + it('renders ViewVersionIncompatibleBanner if view version is <8.0', async function () { + await renderIndexes(undefined, undefined, { + isReadonlyView: true, + serverVersion: '8.0.0', + indexView: 'search-indexes', + }); - await waitFor(() => { - expect(screen.getByTestId('search-indexes-list')).to.exist; + expect(screen.getByTestId('view-version-incompatible-banner')).to.exist; }); - }); - it('renders correct empty state if isReadonlyView 8.1+ and has no indexes', async function () { - const getSearchIndexesStub = sinon.stub().resolves([]); - const dataProvider = { - getSearchIndexes: getSearchIndexesStub, - }; - await renderIndexes(undefined, dataProvider, { - indexView: 'search-indexes', - isReadonlyView: true, - serverVersion: '8.1.0', + it('renders ViewNotSearchCompatibleBanner if view pipeline is not queryable', async function () { + const pipelineMock: Document[] = [ + { $project: { newField: 'testValue' } }, + ]; + const mockCollectionStats = { + index_count: 0, + index_size: 0, + pipeline: pipelineMock, + }; + await renderIndexes(undefined, undefined, { + isReadonlyView: true, + serverVersion: '8.1.0', + indexView: 'search-indexes', + collectionStats: mockCollectionStats, + }); + + expect( + screen.getByTestId('view-not-search-compatible-banner') + ).to.exist; }); - expect(screen.getByText('No search indexes yet')).to.be.visible; - expect(screen.getByText('Create Atlas Search Index')).to.be.visible; - }); - - it('renders correct empty state if isReadonlyView 8.0 and has no indexes', async function () { - const getSearchIndexesStub = sinon.stub().resolves([]); - const dataProvider = { - getSearchIndexes: getSearchIndexesStub, - }; - await renderIndexes(undefined, dataProvider, { - indexView: 'search-indexes', - isReadonlyView: true, - serverVersion: '8.0.0', + it('renders search indexes list if 8.1+ and has indexes', async function () { + const getSearchIndexesStub = sinon.stub().resolves(searchIndexes); + const dataProvider = { + getSearchIndexes: getSearchIndexesStub, + }; + await renderIndexes(undefined, dataProvider, { + indexView: 'search-indexes', + isReadonlyView: true, + serverVersion: '8.1.0', + }); + + await waitFor(() => { + expect(screen.getByTestId('search-indexes-list')).to.exist; + }); }); - expect( - screen.queryByText( - /Upgrade your cluster or manage search indexes on views in the Atlas UI./i - ) - ).to.exist; - expect(screen.queryByText('No standard indexes')).to.exist; - expect(screen.queryByText('Create Atlas Search Index')).to.not.exist; - }); + it('renders correct empty state if 8.1+ and has no indexes', async function () { + const getSearchIndexesStub = sinon.stub().resolves([]); + const dataProvider = { + getSearchIndexes: getSearchIndexesStub, + }; + await renderIndexes(undefined, dataProvider, { + indexView: 'search-indexes', + isReadonlyView: true, + serverVersion: '8.1.0', + }); + + expect(screen.getByText('No search indexes yet')).to.be.visible; + expect(screen.getByText('Create Atlas Search Index')).to.be.visible; + }); - it('renders correct empty state if isReadonlyView <8.0 and has no indexes', async function () { - const getSearchIndexesStub = sinon.stub().resolves([]); - const dataProvider = { - getSearchIndexes: getSearchIndexesStub, - }; - await renderIndexes(undefined, dataProvider, { - indexView: 'search-indexes', - isReadonlyView: true, - serverVersion: '7.0.0', + it('renders correct empty state if 8.0 and has no indexes', async function () { + const getSearchIndexesStub = sinon.stub().resolves([]); + const dataProvider = { + getSearchIndexes: getSearchIndexesStub, + }; + await renderIndexes(undefined, dataProvider, { + indexView: 'search-indexes', + isReadonlyView: true, + serverVersion: '8.0.0', + }); + + expect( + screen.queryByText( + /Upgrade your cluster or manage search indexes on views in the Atlas UI./i + ) + ).to.exist; + expect(screen.queryByText('No standard indexes')).to.exist; + expect(screen.queryByText('Create Atlas Search Index')).to.not.exist; }); - expect( - screen.queryByText( - /Upgrade your cluster to create search indexes on views./i - ) - ).to.exist; - expect(screen.queryByText('No standard indexes')).to.exist; - expect(screen.queryByText('Create Atlas Search Index')).to.not.exist; + it('renders correct empty state if <8.0 and has no indexes', async function () { + const getSearchIndexesStub = sinon.stub().resolves([]); + const dataProvider = { + getSearchIndexes: getSearchIndexesStub, + }; + await renderIndexes(undefined, dataProvider, { + indexView: 'search-indexes', + isReadonlyView: true, + serverVersion: '7.0.0', + }); + + expect( + screen.queryByText( + /Upgrade your cluster to create search indexes on views./i + ) + ).to.exist; + expect(screen.queryByText('No standard indexes')).to.exist; + expect(screen.queryByText('Create Atlas Search Index')).to.not.exist; + }); }); }); }); diff --git a/packages/compass-indexes/src/components/indexes/indexes.tsx b/packages/compass-indexes/src/components/indexes/indexes.tsx index 3569bc39ddd..c75a5df7a32 100644 --- a/packages/compass-indexes/src/components/indexes/indexes.tsx +++ b/packages/compass-indexes/src/components/indexes/indexes.tsx @@ -114,7 +114,7 @@ const ViewNotSearchCompatibleBanner = ({ const variant = hasNoSearchIndexes || !enableAtlasSearchIndexes ? 'warning' : 'danger'; return ( - + {!enableAtlasSearchIndexes && ( <> Looking for search indexes?
@@ -234,9 +234,7 @@ export function Indexes({ const isViewPipelineSearchQueryable = (isReadonlyView && collectionStats?.pipeline && - isPipelineSearchQueryable( - collectionStats.pipeline as Array> - )) ?? + isPipelineSearchQueryable(collectionStats.pipeline as Document[])) ?? true; const getBanner = () => { diff --git a/packages/compass-indexes/src/components/search-indexes-table/search-indexes-table.spec.tsx b/packages/compass-indexes/src/components/search-indexes-table/search-indexes-table.spec.tsx index 86cf6bcce31..912c4c3536c 100644 --- a/packages/compass-indexes/src/components/search-indexes-table/search-indexes-table.spec.tsx +++ b/packages/compass-indexes/src/components/search-indexes-table/search-indexes-table.spec.tsx @@ -128,6 +128,26 @@ describe('SearchIndexesTable Component', function () { expect(openCreateSpy.callCount).to.equal(1); }); + it('renders the zero state with button disabled if there are no indexes and isReadOnlyView with non searchable pipeline', function () { + const pipelineMock: Document[] = [{ $project: { newField: 'testValue' } }]; + const mockCollectionStats = { pipeline: pipelineMock }; + renderIndexList({ + indexes: [], + isReadonlyView: true, + collectionStats: mockCollectionStats, + }); + + expect(() => { + screen.getByTestId('search-indexes-list'); + }).to.throw; + + const button = screen.getByTestId('create-atlas-search-index-button'); + expect(button).to.exist; + expect(button.closest('button')?.getAttribute('aria-disabled')).to.equal( + 'true' + ); + }); + context('renders list with action', function () { it('renders drop action and shows modal when clicked', function () { const onDropIndexSpy = sinon.spy(); diff --git a/packages/compass-indexes/src/components/view-version-incompatible-banners/view-version-incompatible-banners.tsx b/packages/compass-indexes/src/components/view-version-incompatible-banners/view-version-incompatible-banners.tsx index 560edc79e95..9d45ebd95b9 100644 --- a/packages/compass-indexes/src/components/view-version-incompatible-banners/view-version-incompatible-banners.tsx +++ b/packages/compass-indexes/src/components/view-version-incompatible-banners/view-version-incompatible-banners.tsx @@ -43,7 +43,10 @@ export const ViewVersionIncompatibleBanner = ({ ? 'Upgrade your cluster or manage search indexes on views in the Atlas UI.' : 'Upgrade your cluster to create search indexes on views.'; return ( - + Looking for search indexes?
diff --git a/packages/compass/src/app/utils/view-search-queryable.spec.ts b/packages/compass/src/app/utils/view-search-queryable.spec.ts new file mode 100644 index 00000000000..f41af259da4 --- /dev/null +++ b/packages/compass/src/app/utils/view-search-queryable.spec.ts @@ -0,0 +1,69 @@ +import { expect } from 'chai'; +import { isPipelineSearchQueryable } from './view-search-queryable'; // Adjust the import path as necessary +import type { Document } from 'mongodb'; + +describe('isPipelineSearchQueryable', () => { + it('should return true for a valid pipeline with $addFields stage', () => { + const pipeline: Document[] = [{ $addFields: { testField: 'testValue' } }]; + expect(isPipelineSearchQueryable(pipeline)).to.equal(true); + }); + + it('should return true for a valid pipeline with $set stage', () => { + const pipeline: Document[] = [{ $set: { testField: 'testValue' } }]; + expect(isPipelineSearchQueryable(pipeline)).to.equal(true); + }); + + it('should return true for a valid pipeline with $match stage using $expr', () => { + const pipeline: Document[] = [ + { $match: { $expr: { $eq: ['$field', 'value'] } } }, + ]; + expect(isPipelineSearchQueryable(pipeline)).to.equal(true); + }); + + it('should return false for a pipeline with an unsupported stage', () => { + const pipeline: Document[] = [{ $group: { _id: '$field' } }]; + expect(isPipelineSearchQueryable(pipeline)).to.equal(false); + }); + + it('should return false for a $match stage without $expr', () => { + const pipeline: Document[] = [{ $match: { nonExprKey: 'someValue' } }]; + expect(isPipelineSearchQueryable(pipeline)).to.equal(false); + }); + + it('should return false for a $match stage with $expr and additional fields', () => { + const pipeline: Document[] = [ + { + $match: { $expr: { $eq: ['$field', 'value'] }, anotherField: 'value' }, + }, + ]; + expect(isPipelineSearchQueryable(pipeline)).to.equal(false); + }); + + it('should return true for an empty pipeline', () => { + const pipeline: Document[] = []; + expect(isPipelineSearchQueryable(pipeline)).to.equal(true); + }); + + it('should return false if any stage in the pipeline is invalid', () => { + const pipeline: Document[] = [ + { $addFields: { testField: 'testValue' } }, + { $match: { $expr: { $eq: ['$field', 'value'] } } }, + { $group: { _id: '$field' } }, + ]; + expect(isPipelineSearchQueryable(pipeline)).to.equal(false); + }); + + it('should handle a pipeline with multiple valid stages', () => { + const pipeline: Document[] = [ + { $addFields: { field1: 'value1' } }, + { $match: { $expr: { $eq: ['$field', 'value'] } } }, + { $set: { field2: 'value2' } }, + ]; + expect(isPipelineSearchQueryable(pipeline)).to.equal(true); + }); + + it('should return false for a $match stage with no conditions', () => { + const pipeline: Document[] = [{ $match: {} }]; + expect(isPipelineSearchQueryable(pipeline)).to.equal(false); + }); +}); diff --git a/packages/compass/src/app/utils/view-search-queryable.ts b/packages/compass/src/app/utils/view-search-queryable.ts index b6a1fa8d433..a48d66d1d0c 100644 --- a/packages/compass/src/app/utils/view-search-queryable.ts +++ b/packages/compass/src/app/utils/view-search-queryable.ts @@ -1,6 +1,6 @@ -export const isPipelineSearchQueryable = ( - pipeline: Array> -): boolean => { +import type { Document } from 'mongodb'; + +export const isPipelineSearchQueryable = (pipeline: Document[]): boolean => { for (const stage of pipeline) { const stageKey = Object.keys(stage)[0]; @@ -15,10 +15,10 @@ export const isPipelineSearchQueryable = ( return false; } - // If the stage is $match, check if uses $expr + // If the stage is $match, check if it uses $expr if (stageKey === '$match') { - const matchStage = stage['$match']; - const matchKeys = Object.keys(matchStage); + const matchStage = stage['$match'] as Document; + const matchKeys = Object.keys(matchStage || {}); if (!(matchKeys.length === 1 && matchKeys.includes('$expr'))) { return false; From 894cb5042de001bdd28f748ec69eb7af204a663a Mon Sep 17 00:00:00 2001 From: Darshana Venkatesh Date: Tue, 19 Aug 2025 15:58:15 -0700 Subject: [PATCH 06/22] add missing default params --- .../components/indexes-toolbar/indexes-toolbar.spec.tsx | 7 ++++++- .../search-indexes-table/search-indexes-table.spec.tsx | 7 ++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/packages/compass-indexes/src/components/indexes-toolbar/indexes-toolbar.spec.tsx b/packages/compass-indexes/src/components/indexes-toolbar/indexes-toolbar.spec.tsx index 4766549c1c1..3674fa255dc 100644 --- a/packages/compass-indexes/src/components/indexes-toolbar/indexes-toolbar.spec.tsx +++ b/packages/compass-indexes/src/components/indexes-toolbar/indexes-toolbar.spec.tsx @@ -41,6 +41,7 @@ describe('IndexesToolbar Component', function () { onRefreshIndexes={() => {}} isSearchIndexesSupported={false} isRefreshing={false} + collectionStats={{ index_count: 0, index_size: 0, pipeline: [] }} onIndexViewChanged={() => {}} onCreateRegularIndexClick={() => {}} onCreateSearchIndexClick={() => {}} @@ -165,7 +166,11 @@ describe('IndexesToolbar Component', function () { const pipelineMock: Document[] = [ { $project: { newField: 'testValue' } }, ]; - const mockCollectionStats = { pipeline: pipelineMock }; + const mockCollectionStats = { + index_count: 0, + index_size: 0, + pipeline: pipelineMock, + }; renderIndexesToolbar({ isReadonlyView: true, diff --git a/packages/compass-indexes/src/components/search-indexes-table/search-indexes-table.spec.tsx b/packages/compass-indexes/src/components/search-indexes-table/search-indexes-table.spec.tsx index 912c4c3536c..19adcd7fda6 100644 --- a/packages/compass-indexes/src/components/search-indexes-table/search-indexes-table.spec.tsx +++ b/packages/compass-indexes/src/components/search-indexes-table/search-indexes-table.spec.tsx @@ -29,6 +29,7 @@ const renderIndexList = ( status="READY" isWritable={true} readOnly={false} + isReadonlyView={false} onDropIndexClick={noop} onEditIndexClick={noop} onOpenCreateModalClick={noop} @@ -130,7 +131,11 @@ describe('SearchIndexesTable Component', function () { it('renders the zero state with button disabled if there are no indexes and isReadOnlyView with non searchable pipeline', function () { const pipelineMock: Document[] = [{ $project: { newField: 'testValue' } }]; - const mockCollectionStats = { pipeline: pipelineMock }; + const mockCollectionStats = { + index_count: 0, + index_size: 0, + pipeline: pipelineMock, + }; renderIndexList({ indexes: [], isReadonlyView: true, From d99f756649a92559b242be4e719552b73f8f3c16 Mon Sep 17 00:00:00 2001 From: Darshana Venkatesh Date: Tue, 19 Aug 2025 16:51:00 -0700 Subject: [PATCH 07/22] move isPipelineSearchQueryable into compass-utils and update dependencies --- package-lock.json | 2 ++ packages/compass-aggregations/src/modules/update-view.ts | 2 +- packages/compass-indexes/package.json | 1 + .../src/components/indexes-toolbar/indexes-toolbar.tsx | 2 +- packages/compass-indexes/src/components/indexes/indexes.tsx | 2 +- .../components/search-indexes-table/search-indexes-table.tsx | 2 +- packages/compass-utils/src/index.ts | 1 + .../utils => compass-utils/src}/view-search-queryable.spec.ts | 0 .../app/utils => compass-utils/src}/view-search-queryable.ts | 0 9 files changed, 8 insertions(+), 4 deletions(-) rename packages/{compass/src/app/utils => compass-utils/src}/view-search-queryable.spec.ts (100%) rename packages/{compass/src/app/utils => compass-utils/src}/view-search-queryable.ts (100%) diff --git a/package-lock.json b/package-lock.json index 4b7f8036c82..6eb9002c4f4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -46809,6 +46809,7 @@ "@mongodb-js/compass-field-store": "^9.45.0", "@mongodb-js/compass-logging": "^1.7.11", "@mongodb-js/compass-telemetry": "^1.13.0", + "@mongodb-js/compass-utils": "^0.9.10", "@mongodb-js/compass-workspaces": "^0.51.0", "@mongodb-js/connection-info": "^0.17.1", "@mongodb-js/mongodb-constants": "^0.12.2", @@ -58871,6 +58872,7 @@ "@mongodb-js/compass-field-store": "^9.45.0", "@mongodb-js/compass-logging": "^1.7.11", "@mongodb-js/compass-telemetry": "^1.13.0", + "@mongodb-js/compass-utils": "^0.9.10", "@mongodb-js/compass-workspaces": "^0.51.0", "@mongodb-js/connection-info": "^0.17.1", "@mongodb-js/eslint-config-compass": "^1.4.6", diff --git a/packages/compass-aggregations/src/modules/update-view.ts b/packages/compass-aggregations/src/modules/update-view.ts index c6b9c43a26e..65d4c904a2c 100644 --- a/packages/compass-aggregations/src/modules/update-view.ts +++ b/packages/compass-aggregations/src/modules/update-view.ts @@ -10,7 +10,7 @@ import { isAction } from '../utils/is-action'; import type { AnyAction } from 'redux'; import { showConfirmation as showConfirmationModal } from '@mongodb-js/compass-components'; import { fetchIndexes } from './search-indexes'; -import { isPipelineSearchQueryable } from 'mongodb-compass/src/app/utils/view-search-queryable'; +import { isPipelineSearchQueryable } from '@mongodb-js/compass-utils'; export type UpdateViewState = null | string; diff --git a/packages/compass-indexes/package.json b/packages/compass-indexes/package.json index ed0a5cfb671..0c3a63ba506 100644 --- a/packages/compass-indexes/package.json +++ b/packages/compass-indexes/package.json @@ -79,6 +79,7 @@ "@mongodb-js/mongodb-constants": "^0.12.2", "@mongodb-js/shell-bson-parser": "^1.2.0", "@mongodb-js/connection-info": "^0.17.1", + "@mongodb-js/compass-utils": "^0.9.10", "bson": "^6.10.4", "compass-preferences-model": "^2.50.0", "lodash": "^4.17.21", diff --git a/packages/compass-indexes/src/components/indexes-toolbar/indexes-toolbar.tsx b/packages/compass-indexes/src/components/indexes-toolbar/indexes-toolbar.tsx index 9406b646f78..556936a5117 100644 --- a/packages/compass-indexes/src/components/indexes-toolbar/indexes-toolbar.tsx +++ b/packages/compass-indexes/src/components/indexes-toolbar/indexes-toolbar.tsx @@ -32,7 +32,7 @@ import { createIndexOpened } from '../../modules/create-index'; import type { IndexView } from '../../modules/index-view'; import { indexViewChanged } from '../../modules/index-view'; import type { CollectionStats } from '../../modules/collection-stats'; -import { isPipelineSearchQueryable } from 'mongodb-compass/src/app/utils/view-search-queryable'; +import { isPipelineSearchQueryable } from '@mongodb-js/compass-utils'; const toolbarButtonsContainer = css({ display: 'flex', diff --git a/packages/compass-indexes/src/components/indexes/indexes.tsx b/packages/compass-indexes/src/components/indexes/indexes.tsx index c75a5df7a32..33a6c1fd400 100644 --- a/packages/compass-indexes/src/components/indexes/indexes.tsx +++ b/packages/compass-indexes/src/components/indexes/indexes.tsx @@ -37,8 +37,8 @@ import { ZeroGraphic } from '../search-indexes-table/zero-graphic'; import { ViewVersionIncompatibleBanner } from '../view-version-incompatible-banners/view-version-incompatible-banners'; import semver from 'semver'; import type { SearchIndex } from 'mongodb-data-service'; -import { isPipelineSearchQueryable } from 'mongodb-compass/src/app/utils/view-search-queryable'; import type { CollectionStats } from '../../modules/collection-stats'; +import { isPipelineSearchQueryable } from '@mongodb-js/compass-utils'; // This constant is used as a trigger to show an insight whenever number of // indexes in a collection is more than what is specified here. diff --git a/packages/compass-indexes/src/components/search-indexes-table/search-indexes-table.tsx b/packages/compass-indexes/src/components/search-indexes-table/search-indexes-table.tsx index cda2ec0f6eb..a0d4a07c57d 100644 --- a/packages/compass-indexes/src/components/search-indexes-table/search-indexes-table.tsx +++ b/packages/compass-indexes/src/components/search-indexes-table/search-indexes-table.tsx @@ -40,7 +40,7 @@ import BadgeWithIconLink from '../indexes-table/badge-with-icon-link'; import { useConnectionInfo } from '@mongodb-js/compass-connections/provider'; import { useWorkspaceTabId } from '@mongodb-js/compass-workspaces/provider'; import type { CollectionStats } from '../../modules/collection-stats'; -import { isPipelineSearchQueryable } from 'mongodb-compass/src/app/utils/view-search-queryable'; +import { isPipelineSearchQueryable } from '@mongodb-js/compass-utils'; type SearchIndexesTableProps = { namespace: string; diff --git a/packages/compass-utils/src/index.ts b/packages/compass-utils/src/index.ts index 477608e14dc..95ee0e87251 100644 --- a/packages/compass-utils/src/index.ts +++ b/packages/compass-utils/src/index.ts @@ -8,3 +8,4 @@ export { isCancelError, throwIfAborted, } from './cancellable-promise'; +export { isPipelineSearchQueryable } from './view-search-queryable'; diff --git a/packages/compass/src/app/utils/view-search-queryable.spec.ts b/packages/compass-utils/src/view-search-queryable.spec.ts similarity index 100% rename from packages/compass/src/app/utils/view-search-queryable.spec.ts rename to packages/compass-utils/src/view-search-queryable.spec.ts diff --git a/packages/compass/src/app/utils/view-search-queryable.ts b/packages/compass-utils/src/view-search-queryable.ts similarity index 100% rename from packages/compass/src/app/utils/view-search-queryable.ts rename to packages/compass-utils/src/view-search-queryable.ts From d245b89cd124b949e0cdf0fdacbbe88c1032def8 Mon Sep 17 00:00:00 2001 From: Darshana Venkatesh Date: Tue, 19 Aug 2025 17:01:25 -0700 Subject: [PATCH 08/22] add mongodb to dependencies in compass-utils --- package-lock.json | 60 ++++++++++++++++++++++++++++- packages/compass-utils/package.json | 3 +- 2 files changed, 61 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 6eb9002c4f4..4926e7b913d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -48225,7 +48225,8 @@ "license": "SSPL", "dependencies": { "@electron/remote": "^2.1.3", - "electron": "^37.2.6" + "electron": "^37.2.6", + "mongodb": "^6.18.0" }, "devDependencies": { "@mongodb-js/eslint-config-compass": "^1.4.6", @@ -48244,6 +48245,52 @@ "typescript": "^5.8.3" } }, + "packages/compass-utils/node_modules/mongodb": { + "version": "6.18.0", + "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-6.18.0.tgz", + "integrity": "sha512-fO5ttN9VC8P0F5fqtQmclAkgXZxbIkYRTUi1j8JO6IYwvamkhtYDilJr35jOPELR49zqCJgXZWwCtW7B+TM8vQ==", + "license": "Apache-2.0", + "dependencies": { + "@mongodb-js/saslprep": "^1.1.9", + "bson": "^6.10.4", + "mongodb-connection-string-url": "^3.0.0" + }, + "engines": { + "node": ">=16.20.1" + }, + "peerDependencies": { + "@aws-sdk/credential-providers": "^3.188.0", + "@mongodb-js/zstd": "^1.1.0 || ^2.0.0", + "gcp-metadata": "^5.2.0", + "kerberos": "^2.0.1", + "mongodb-client-encryption": ">=6.0.0 <7", + "snappy": "^7.2.2", + "socks": "^2.7.1" + }, + "peerDependenciesMeta": { + "@aws-sdk/credential-providers": { + "optional": true + }, + "@mongodb-js/zstd": { + "optional": true + }, + "gcp-metadata": { + "optional": true + }, + "kerberos": { + "optional": true + }, + "mongodb-client-encryption": { + "optional": true + }, + "snappy": { + "optional": true + }, + "socks": { + "optional": true + } + } + }, "packages/compass-utils/node_modules/sinon": { "version": "9.2.4", "resolved": "https://registry.npmjs.org/sinon/-/sinon-9.2.4.tgz", @@ -60164,11 +60211,22 @@ "electron": "^37.2.6", "gen-esm-wrapper": "^1.1.0", "mocha": "^10.2.0", + "mongodb": "^6.18.0", "nyc": "^15.1.0", "sinon": "^9.2.3", "typescript": "^5.8.3" }, "dependencies": { + "mongodb": { + "version": "6.18.0", + "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-6.18.0.tgz", + "integrity": "sha512-fO5ttN9VC8P0F5fqtQmclAkgXZxbIkYRTUi1j8JO6IYwvamkhtYDilJr35jOPELR49zqCJgXZWwCtW7B+TM8vQ==", + "requires": { + "@mongodb-js/saslprep": "^1.1.9", + "bson": "^6.10.4", + "mongodb-connection-string-url": "^3.0.0" + } + }, "sinon": { "version": "9.2.4", "resolved": "https://registry.npmjs.org/sinon/-/sinon-9.2.4.tgz", diff --git a/packages/compass-utils/package.json b/packages/compass-utils/package.json index 19cc353cf5d..c4e7f0da8a4 100644 --- a/packages/compass-utils/package.json +++ b/packages/compass-utils/package.json @@ -67,6 +67,7 @@ }, "dependencies": { "@electron/remote": "^2.1.3", - "electron": "^37.2.6" + "electron": "^37.2.6", + "mongodb": "^6.18.0" } } From af80a53d5799ea9d7b135b75791a9d354e170050 Mon Sep 17 00:00:00 2001 From: Darshana Venkatesh Date: Tue, 19 Aug 2025 17:25:21 -0700 Subject: [PATCH 09/22] make isSearchPipelineQueryable true for not read only views --- .../src/components/indexes-toolbar/indexes-toolbar.tsx | 8 ++++---- .../compass-indexes/src/components/indexes/indexes.tsx | 8 ++++---- .../search-indexes-table/search-indexes-table.tsx | 10 ++++------ 3 files changed, 12 insertions(+), 14 deletions(-) diff --git a/packages/compass-indexes/src/components/indexes-toolbar/indexes-toolbar.tsx b/packages/compass-indexes/src/components/indexes-toolbar/indexes-toolbar.tsx index 556936a5117..09cb76268ef 100644 --- a/packages/compass-indexes/src/components/indexes-toolbar/indexes-toolbar.tsx +++ b/packages/compass-indexes/src/components/indexes-toolbar/indexes-toolbar.tsx @@ -33,6 +33,7 @@ import type { IndexView } from '../../modules/index-view'; import { indexViewChanged } from '../../modules/index-view'; import type { CollectionStats } from '../../modules/collection-stats'; import { isPipelineSearchQueryable } from '@mongodb-js/compass-utils'; +import type { Document } from 'mongodb'; const toolbarButtonsContainer = css({ display: 'flex', @@ -127,10 +128,9 @@ export const IndexesToolbar: React.FunctionComponent = ({ ); const isViewPipelineSearchQueryable = - (isReadonlyView && - collectionStats?.pipeline && - isPipelineSearchQueryable(collectionStats.pipeline as Document[])) ?? - true; + isReadonlyView && collectionStats?.pipeline + ? isPipelineSearchQueryable(collectionStats.pipeline as Document[]) + : true; const pipelineNotSearchQueryableDescription = 'Search indexes can only be created on views containing $addFields, $set or $match stages with the $expr operator.'; return ( diff --git a/packages/compass-indexes/src/components/indexes/indexes.tsx b/packages/compass-indexes/src/components/indexes/indexes.tsx index 33a6c1fd400..73925cc36f0 100644 --- a/packages/compass-indexes/src/components/indexes/indexes.tsx +++ b/packages/compass-indexes/src/components/indexes/indexes.tsx @@ -39,6 +39,7 @@ import semver from 'semver'; import type { SearchIndex } from 'mongodb-data-service'; import type { CollectionStats } from '../../modules/collection-stats'; import { isPipelineSearchQueryable } from '@mongodb-js/compass-utils'; +import type { Document } from 'mongodb'; // This constant is used as a trigger to show an insight whenever number of // indexes in a collection is more than what is specified here. @@ -232,10 +233,9 @@ export function Indexes({ const enableAtlasSearchIndexes = usePreference('enableAtlasSearchIndexes'); const { atlasMetadata } = useConnectionInfo(); const isViewPipelineSearchQueryable = - (isReadonlyView && - collectionStats?.pipeline && - isPipelineSearchQueryable(collectionStats.pipeline as Document[])) ?? - true; + isReadonlyView && collectionStats?.pipeline + ? isPipelineSearchQueryable(collectionStats.pipeline as Document[]) + : true; const getBanner = () => { if (isReadonlyView) { diff --git a/packages/compass-indexes/src/components/search-indexes-table/search-indexes-table.tsx b/packages/compass-indexes/src/components/search-indexes-table/search-indexes-table.tsx index a0d4a07c57d..70bab46eab2 100644 --- a/packages/compass-indexes/src/components/search-indexes-table/search-indexes-table.tsx +++ b/packages/compass-indexes/src/components/search-indexes-table/search-indexes-table.tsx @@ -322,12 +322,10 @@ export const SearchIndexesTable: React.FunctionComponent< }; }, [tabId, onSearchIndexesOpened, onSearchIndexesClosed]); const isViewPipelineSearchQueryable = - (isReadonlyView && - collectionStats?.pipeline && - isPipelineSearchQueryable( - collectionStats.pipeline as Array> - )) ?? - true; + isReadonlyView && collectionStats?.pipeline + ? isPipelineSearchQueryable(collectionStats.pipeline as Document[]) + : true; + const data = useMemo[]>( () => indexes.map((index) => { From 6f36bf16d47abf8c0dbc933baddfc1243ad78812 Mon Sep 17 00:00:00 2001 From: Darshana Venkatesh Date: Tue, 19 Aug 2025 23:36:30 -0700 Subject: [PATCH 10/22] fix update-view.spec.ts --- .../src/modules/update-view.spec.ts | 22 ++++++++++--------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/packages/compass-aggregations/src/modules/update-view.spec.ts b/packages/compass-aggregations/src/modules/update-view.spec.ts index fdab54aa4a2..938a1ec5468 100644 --- a/packages/compass-aggregations/src/modules/update-view.spec.ts +++ b/packages/compass-aggregations/src/modules/update-view.spec.ts @@ -56,13 +56,15 @@ describe('update-view module', function () { beforeEach(async function () { dispatchFake = sinon.fake(); updateCollectionFake = sinon.fake.resolves(undefined); - showConfirmationStub = sinon.stub(updateViewSlice, 'showConfirmation'); + showConfirmationStub = sinon + .stub(updateViewSlice, 'showConfirmation') + .resolves(true); stateMock = { pipelineBuilder: { pipelineMode: 'builder-ui' }, + searchIndexes: { indexes: [{ name: 'index1' }] }, focusMode: { isEnabled: false }, namespace: 'aa.bb', editViewName: 'aa.bb', - searchIndexes: { indexes: [{ name: 'index1' }] }, dataService: { dataService: { updateCollection: updateCollectionFake, @@ -70,24 +72,22 @@ describe('update-view module', function () { }, }; getStateMock = () => stateMock; - - const runUpdateView = updateView(); - await runUpdateView(dispatchFake, getStateMock, thunkArg as any); }); afterEach(function () { showConfirmationStub.restore(); }); - it('first it calls to dismiss any existing error', function () { + it('first it calls to dismiss any existing error', async function () { + const runUpdateView = updateView(); + await runUpdateView(dispatchFake, getStateMock, thunkArg as any); + expect(dispatchFake.firstCall.args[0]).to.deep.equal({ type: 'aggregations/update-view/DISMISS_VIEW_UPDATE_ERROR', }); }); it('shows confirmation banner when search indexes are present', async function () { - showConfirmationStub.resolves(true); - const runUpdateView = updateView(); await runUpdateView(dispatchFake, getStateMock, thunkArg as any); @@ -99,7 +99,6 @@ describe('update-view module', function () { }); it('does not update view if not confirmed', async function () { - getStateMock = () => stateMock; showConfirmationStub.resolves(false); const runUpdateView = updateView(); @@ -108,7 +107,10 @@ describe('update-view module', function () { expect(updateCollectionFake.calledOnce).to.be.false; }); - it('calls the data service to update the view for the provided ns', function () { + it('calls the data service to update the view for the provided ns', async function () { + const runUpdateView = updateView(); + await runUpdateView(dispatchFake, getStateMock, thunkArg as any); + expect(updateCollectionFake.firstCall.args[0]).to.equal('aa.bb'); expect(updateCollectionFake.firstCall.args[1]).to.deep.equal({ viewOn: 'bb', From 3bd25a5dee1b6e317f83e64f30c41770dee702dd Mon Sep 17 00:00:00 2001 From: Darshana Venkatesh Date: Tue, 19 Aug 2025 23:39:13 -0700 Subject: [PATCH 11/22] add negative test case --- .../compass-aggregations/src/modules/update-view.spec.ts | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/packages/compass-aggregations/src/modules/update-view.spec.ts b/packages/compass-aggregations/src/modules/update-view.spec.ts index 938a1ec5468..5396e543bdd 100644 --- a/packages/compass-aggregations/src/modules/update-view.spec.ts +++ b/packages/compass-aggregations/src/modules/update-view.spec.ts @@ -87,6 +87,15 @@ describe('update-view module', function () { }); }); + it('does not shows confirmation banner if search indexes are not present', async function () { + stateMock.searchIndexes.indexes = []; + + const runUpdateView = updateView(); + await runUpdateView(dispatchFake, getStateMock, thunkArg as any); + + expect(showConfirmationStub.calledOnce).to.be.false; + }); + it('shows confirmation banner when search indexes are present', async function () { const runUpdateView = updateView(); await runUpdateView(dispatchFake, getStateMock, thunkArg as any); From ba3063da723a37d04485f47eedd0d716e1e1aa6f Mon Sep 17 00:00:00 2001 From: Darshana Venkatesh Date: Wed, 20 Aug 2025 01:02:07 -0700 Subject: [PATCH 12/22] remove async --- packages/compass-aggregations/src/modules/update-view.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/compass-aggregations/src/modules/update-view.spec.ts b/packages/compass-aggregations/src/modules/update-view.spec.ts index 5396e543bdd..47130478e0b 100644 --- a/packages/compass-aggregations/src/modules/update-view.spec.ts +++ b/packages/compass-aggregations/src/modules/update-view.spec.ts @@ -53,7 +53,7 @@ describe('update-view module', function () { let updateCollectionFake = sinon.fake(); let showConfirmationStub: sinon.SinonStub; - beforeEach(async function () { + beforeEach(function () { dispatchFake = sinon.fake(); updateCollectionFake = sinon.fake.resolves(undefined); showConfirmationStub = sinon From 082bd3c634f683fbc080bc148fc169a80ad5e50e Mon Sep 17 00:00:00 2001 From: Darshana Venkatesh Date: Thu, 21 Aug 2025 23:43:39 -0700 Subject: [PATCH 13/22] just introduce new function to return whether has search indexes --- package-lock.json | 133 ++++++++++-------- packages/compass-aggregations/package.json | 2 +- .../src/modules/search-indexes.ts | 27 +++- .../src/modules/update-view.spec.ts | 12 +- .../src/modules/update-view.ts | 6 +- .../compass-aggregations/src/stores/store.ts | 7 +- packages/compass-collection/package.json | 2 +- packages/compass-editor/package.json | 2 +- packages/compass-indexes/package.json | 2 +- .../indexes-toolbar/indexes-toolbar.tsx | 15 +- .../src/components/indexes/indexes.tsx | 34 ++--- .../view-version-incompatible-banners.tsx | 15 +- .../src/modules/search-indexes.ts | 19 +-- packages/compass-query-bar/package.json | 2 +- .../compass-schema-validation/package.json | 2 +- packages/compass-sidebar/package.json | 2 +- 16 files changed, 162 insertions(+), 120 deletions(-) diff --git a/package-lock.json b/package-lock.json index 506ece3b301..a7ef21d2db6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -43903,7 +43903,7 @@ "@mongodb-js/compass-utils": "^0.9.10", "@mongodb-js/compass-workspaces": "^0.51.0", "@mongodb-js/explain-plan-helper": "^1.4.17", - "@mongodb-js/mongodb-constants": "^0.12.2", + "@mongodb-js/mongodb-constants": "^0.14.0", "@mongodb-js/my-queries-storage": "^0.37.0", "@mongodb-js/shell-bson-parser": "^1.2.0", "bson": "^6.10.4", @@ -43947,12 +43947,15 @@ } }, "packages/compass-aggregations/node_modules/@mongodb-js/mongodb-constants": { - "version": "0.12.2", - "resolved": "https://registry.npmjs.org/@mongodb-js/mongodb-constants/-/mongodb-constants-0.12.2.tgz", - "integrity": "sha512-gAlknLOI4qbBjkPsLSe1tmL5ImZvnm3/7z55JseOytjKx2FQWfBKSx2gI871ppB7onnamzpounn+TUje3sNs/w==", + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/@mongodb-js/mongodb-constants/-/mongodb-constants-0.14.0.tgz", + "integrity": "sha512-AuaKso7Bfq29dSXUZZMSDWR088Klz6SkL1mmzhjykA3VylfU3XwHhY1/AcPOsi0vSzn+2mQN87LKQKXp1plp2Q==", "license": "Apache-2.0", "dependencies": { "semver": "^7.7.1" + }, + "peerDependencies": { + "bson": "^6.10.3" } }, "packages/compass-aggregations/node_modules/@mongodb-js/shell-bson-parser": { @@ -44365,7 +44368,7 @@ "@mongodb-js/compass-telemetry": "^1.13.0", "@mongodb-js/compass-workspaces": "^0.51.0", "@mongodb-js/connection-info": "^0.17.1", - "@mongodb-js/mongodb-constants": "^0.12.2", + "@mongodb-js/mongodb-constants": "^0.14.0", "compass-preferences-model": "^2.50.0", "hadron-document": "^8.9.5", "mongodb": "^6.17.0", @@ -44401,12 +44404,15 @@ } }, "packages/compass-collection/node_modules/@mongodb-js/mongodb-constants": { - "version": "0.12.2", - "resolved": "https://registry.npmjs.org/@mongodb-js/mongodb-constants/-/mongodb-constants-0.12.2.tgz", - "integrity": "sha512-gAlknLOI4qbBjkPsLSe1tmL5ImZvnm3/7z55JseOytjKx2FQWfBKSx2gI871ppB7onnamzpounn+TUje3sNs/w==", + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/@mongodb-js/mongodb-constants/-/mongodb-constants-0.14.0.tgz", + "integrity": "sha512-AuaKso7Bfq29dSXUZZMSDWR088Klz6SkL1mmzhjykA3VylfU3XwHhY1/AcPOsi0vSzn+2mQN87LKQKXp1plp2Q==", "license": "Apache-2.0", "dependencies": { "semver": "^7.7.1" + }, + "peerDependencies": { + "bson": "^6.10.3" } }, "packages/compass-collection/node_modules/diff": { @@ -46002,7 +46008,7 @@ "@codemirror/view": "^6.38.0", "@lezer/highlight": "^1.2.1", "@mongodb-js/compass-components": "^1.48.0", - "@mongodb-js/mongodb-constants": "^0.12.2", + "@mongodb-js/mongodb-constants": "^0.14.0", "mongodb-query-parser": "^4.3.0", "polished": "^4.2.2", "prettier": "^2.7.1", @@ -46027,12 +46033,15 @@ } }, "packages/compass-editor/node_modules/@mongodb-js/mongodb-constants": { - "version": "0.12.2", - "resolved": "https://registry.npmjs.org/@mongodb-js/mongodb-constants/-/mongodb-constants-0.12.2.tgz", - "integrity": "sha512-gAlknLOI4qbBjkPsLSe1tmL5ImZvnm3/7z55JseOytjKx2FQWfBKSx2gI871ppB7onnamzpounn+TUje3sNs/w==", + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/@mongodb-js/mongodb-constants/-/mongodb-constants-0.14.0.tgz", + "integrity": "sha512-AuaKso7Bfq29dSXUZZMSDWR088Klz6SkL1mmzhjykA3VylfU3XwHhY1/AcPOsi0vSzn+2mQN87LKQKXp1plp2Q==", "license": "Apache-2.0", "dependencies": { "semver": "^7.7.1" + }, + "peerDependencies": { + "bson": "^6.10.3" } }, "packages/compass-editor/node_modules/@mongodb-js/shell-bson-parser": { @@ -46813,7 +46822,7 @@ "@mongodb-js/compass-utils": "^0.9.10", "@mongodb-js/compass-workspaces": "^0.51.0", "@mongodb-js/connection-info": "^0.17.1", - "@mongodb-js/mongodb-constants": "^0.12.2", + "@mongodb-js/mongodb-constants": "^0.14.0", "@mongodb-js/shell-bson-parser": "^1.2.0", "bson": "^6.10.4", "compass-preferences-model": "^2.50.0", @@ -46851,12 +46860,15 @@ } }, "packages/compass-indexes/node_modules/@mongodb-js/mongodb-constants": { - "version": "0.12.2", - "resolved": "https://registry.npmjs.org/@mongodb-js/mongodb-constants/-/mongodb-constants-0.12.2.tgz", - "integrity": "sha512-gAlknLOI4qbBjkPsLSe1tmL5ImZvnm3/7z55JseOytjKx2FQWfBKSx2gI871ppB7onnamzpounn+TUje3sNs/w==", + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/@mongodb-js/mongodb-constants/-/mongodb-constants-0.14.0.tgz", + "integrity": "sha512-AuaKso7Bfq29dSXUZZMSDWR088Klz6SkL1mmzhjykA3VylfU3XwHhY1/AcPOsi0vSzn+2mQN87LKQKXp1plp2Q==", "license": "Apache-2.0", "dependencies": { "semver": "^7.7.1" + }, + "peerDependencies": { + "bson": "^6.10.3" } }, "packages/compass-indexes/node_modules/@mongodb-js/shell-bson-parser": { @@ -47268,7 +47280,7 @@ "@mongodb-js/compass-generative-ai": "^0.50.0", "@mongodb-js/compass-logging": "^1.7.11", "@mongodb-js/compass-telemetry": "^1.13.0", - "@mongodb-js/mongodb-constants": "^0.12.2", + "@mongodb-js/mongodb-constants": "^0.14.0", "@mongodb-js/my-queries-storage": "^0.37.0", "bson": "^6.10.4", "compass-preferences-model": "^2.50.0", @@ -47303,12 +47315,15 @@ } }, "packages/compass-query-bar/node_modules/@mongodb-js/mongodb-constants": { - "version": "0.12.2", - "resolved": "https://registry.npmjs.org/@mongodb-js/mongodb-constants/-/mongodb-constants-0.12.2.tgz", - "integrity": "sha512-gAlknLOI4qbBjkPsLSe1tmL5ImZvnm3/7z55JseOytjKx2FQWfBKSx2gI871ppB7onnamzpounn+TUje3sNs/w==", + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/@mongodb-js/mongodb-constants/-/mongodb-constants-0.14.0.tgz", + "integrity": "sha512-AuaKso7Bfq29dSXUZZMSDWR088Klz6SkL1mmzhjykA3VylfU3XwHhY1/AcPOsi0vSzn+2mQN87LKQKXp1plp2Q==", "license": "Apache-2.0", "dependencies": { "semver": "^7.7.1" + }, + "peerDependencies": { + "bson": "^6.10.3" } }, "packages/compass-query-bar/node_modules/@mongodb-js/shell-bson-parser": { @@ -47527,7 +47542,7 @@ "@mongodb-js/compass-schema": "^6.71.0", "@mongodb-js/compass-telemetry": "^1.13.0", "@mongodb-js/compass-workspaces": "^0.51.0", - "@mongodb-js/mongodb-constants": "^0.12.2", + "@mongodb-js/mongodb-constants": "^0.14.0", "bson": "^6.10.4", "compass-preferences-model": "^2.50.0", "javascript-stringify": "^2.0.1", @@ -47561,12 +47576,15 @@ } }, "packages/compass-schema-validation/node_modules/@mongodb-js/mongodb-constants": { - "version": "0.12.2", - "resolved": "https://registry.npmjs.org/@mongodb-js/mongodb-constants/-/mongodb-constants-0.12.2.tgz", - "integrity": "sha512-gAlknLOI4qbBjkPsLSe1tmL5ImZvnm3/7z55JseOytjKx2FQWfBKSx2gI871ppB7onnamzpounn+TUje3sNs/w==", + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/@mongodb-js/mongodb-constants/-/mongodb-constants-0.14.0.tgz", + "integrity": "sha512-AuaKso7Bfq29dSXUZZMSDWR088Klz6SkL1mmzhjykA3VylfU3XwHhY1/AcPOsi0vSzn+2mQN87LKQKXp1plp2Q==", "license": "Apache-2.0", "dependencies": { "semver": "^7.7.1" + }, + "peerDependencies": { + "bson": "^6.10.3" } }, "packages/compass-schema-validation/node_modules/@mongodb-js/shell-bson-parser": { @@ -47806,7 +47824,7 @@ "@mongodb-js/compass-telemetry": "^1.13.0", "@mongodb-js/compass-workspaces": "^0.51.0", "@mongodb-js/connection-info": "^0.17.1", - "@mongodb-js/mongodb-constants": "^0.12.2", + "@mongodb-js/mongodb-constants": "^0.14.0", "compass-preferences-model": "^2.50.0", "lodash": "^4.17.21", "mongodb": "^6.17.0", @@ -47842,12 +47860,15 @@ } }, "packages/compass-sidebar/node_modules/@mongodb-js/mongodb-constants": { - "version": "0.12.2", - "resolved": "https://registry.npmjs.org/@mongodb-js/mongodb-constants/-/mongodb-constants-0.12.2.tgz", - "integrity": "sha512-gAlknLOI4qbBjkPsLSe1tmL5ImZvnm3/7z55JseOytjKx2FQWfBKSx2gI871ppB7onnamzpounn+TUje3sNs/w==", + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/@mongodb-js/mongodb-constants/-/mongodb-constants-0.14.0.tgz", + "integrity": "sha512-AuaKso7Bfq29dSXUZZMSDWR088Klz6SkL1mmzhjykA3VylfU3XwHhY1/AcPOsi0vSzn+2mQN87LKQKXp1plp2Q==", "license": "Apache-2.0", "dependencies": { "semver": "^7.7.1" + }, + "peerDependencies": { + "bson": "^6.10.3" } }, "packages/compass-sidebar/node_modules/semver": { @@ -56827,7 +56848,7 @@ "@mongodb-js/eslint-config-compass": "^1.4.6", "@mongodb-js/explain-plan-helper": "^1.4.17", "@mongodb-js/mocha-config-compass": "^1.7.0", - "@mongodb-js/mongodb-constants": "^0.12.2", + "@mongodb-js/mongodb-constants": "^0.14.0", "@mongodb-js/my-queries-storage": "^0.37.0", "@mongodb-js/prettier-config-compass": "^1.2.8", "@mongodb-js/shell-bson-parser": "^1.2.0", @@ -56867,9 +56888,9 @@ }, "dependencies": { "@mongodb-js/mongodb-constants": { - "version": "0.12.2", - "resolved": "https://registry.npmjs.org/@mongodb-js/mongodb-constants/-/mongodb-constants-0.12.2.tgz", - "integrity": "sha512-gAlknLOI4qbBjkPsLSe1tmL5ImZvnm3/7z55JseOytjKx2FQWfBKSx2gI871ppB7onnamzpounn+TUje3sNs/w==", + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/@mongodb-js/mongodb-constants/-/mongodb-constants-0.14.0.tgz", + "integrity": "sha512-AuaKso7Bfq29dSXUZZMSDWR088Klz6SkL1mmzhjykA3VylfU3XwHhY1/AcPOsi0vSzn+2mQN87LKQKXp1plp2Q==", "requires": { "semver": "^7.7.1" } @@ -57193,7 +57214,7 @@ "@mongodb-js/connection-info": "^0.17.1", "@mongodb-js/eslint-config-compass": "^1.4.6", "@mongodb-js/mocha-config-compass": "^1.7.0", - "@mongodb-js/mongodb-constants": "^0.12.2", + "@mongodb-js/mongodb-constants": "^0.14.0", "@mongodb-js/prettier-config-compass": "^1.2.8", "@mongodb-js/testing-library-compass": "^1.3.9", "@mongodb-js/tsconfig-compass": "^1.2.9", @@ -57225,9 +57246,9 @@ }, "dependencies": { "@mongodb-js/mongodb-constants": { - "version": "0.12.2", - "resolved": "https://registry.npmjs.org/@mongodb-js/mongodb-constants/-/mongodb-constants-0.12.2.tgz", - "integrity": "sha512-gAlknLOI4qbBjkPsLSe1tmL5ImZvnm3/7z55JseOytjKx2FQWfBKSx2gI871ppB7onnamzpounn+TUje3sNs/w==", + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/@mongodb-js/mongodb-constants/-/mongodb-constants-0.14.0.tgz", + "integrity": "sha512-AuaKso7Bfq29dSXUZZMSDWR088Klz6SkL1mmzhjykA3VylfU3XwHhY1/AcPOsi0vSzn+2mQN87LKQKXp1plp2Q==", "requires": { "semver": "^7.7.1" } @@ -58289,7 +58310,7 @@ "@mongodb-js/compass-components": "^1.48.0", "@mongodb-js/eslint-config-compass": "^1.4.6", "@mongodb-js/mocha-config-compass": "^1.7.0", - "@mongodb-js/mongodb-constants": "^0.12.2", + "@mongodb-js/mongodb-constants": "^0.14.0", "@mongodb-js/prettier-config-compass": "^1.2.8", "@mongodb-js/testing-library-compass": "^1.3.9", "@mongodb-js/tsconfig-compass": "^1.2.9", @@ -58310,9 +58331,9 @@ }, "dependencies": { "@mongodb-js/mongodb-constants": { - "version": "0.12.2", - "resolved": "https://registry.npmjs.org/@mongodb-js/mongodb-constants/-/mongodb-constants-0.12.2.tgz", - "integrity": "sha512-gAlknLOI4qbBjkPsLSe1tmL5ImZvnm3/7z55JseOytjKx2FQWfBKSx2gI871ppB7onnamzpounn+TUje3sNs/w==", + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/@mongodb-js/mongodb-constants/-/mongodb-constants-0.14.0.tgz", + "integrity": "sha512-AuaKso7Bfq29dSXUZZMSDWR088Klz6SkL1mmzhjykA3VylfU3XwHhY1/AcPOsi0vSzn+2mQN87LKQKXp1plp2Q==", "requires": { "semver": "^7.7.1" } @@ -58926,7 +58947,7 @@ "@mongodb-js/connection-info": "^0.17.1", "@mongodb-js/eslint-config-compass": "^1.4.6", "@mongodb-js/mocha-config-compass": "^1.7.0", - "@mongodb-js/mongodb-constants": "^0.12.2", + "@mongodb-js/mongodb-constants": "^0.14.0", "@mongodb-js/prettier-config-compass": "^1.2.8", "@mongodb-js/shell-bson-parser": "^1.2.0", "@mongodb-js/testing-library-compass": "^1.3.9", @@ -58960,9 +58981,9 @@ }, "dependencies": { "@mongodb-js/mongodb-constants": { - "version": "0.12.2", - "resolved": "https://registry.npmjs.org/@mongodb-js/mongodb-constants/-/mongodb-constants-0.12.2.tgz", - "integrity": "sha512-gAlknLOI4qbBjkPsLSe1tmL5ImZvnm3/7z55JseOytjKx2FQWfBKSx2gI871ppB7onnamzpounn+TUje3sNs/w==", + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/@mongodb-js/mongodb-constants/-/mongodb-constants-0.14.0.tgz", + "integrity": "sha512-AuaKso7Bfq29dSXUZZMSDWR088Klz6SkL1mmzhjykA3VylfU3XwHhY1/AcPOsi0vSzn+2mQN87LKQKXp1plp2Q==", "requires": { "semver": "^7.7.1" } @@ -59231,7 +59252,7 @@ "@mongodb-js/compass-telemetry": "^1.13.0", "@mongodb-js/eslint-config-compass": "^1.4.6", "@mongodb-js/mocha-config-compass": "^1.7.0", - "@mongodb-js/mongodb-constants": "^0.12.2", + "@mongodb-js/mongodb-constants": "^0.14.0", "@mongodb-js/my-queries-storage": "^0.37.0", "@mongodb-js/prettier-config-compass": "^1.2.8", "@mongodb-js/testing-library-compass": "^1.3.9", @@ -59262,9 +59283,9 @@ }, "dependencies": { "@mongodb-js/mongodb-constants": { - "version": "0.12.2", - "resolved": "https://registry.npmjs.org/@mongodb-js/mongodb-constants/-/mongodb-constants-0.12.2.tgz", - "integrity": "sha512-gAlknLOI4qbBjkPsLSe1tmL5ImZvnm3/7z55JseOytjKx2FQWfBKSx2gI871ppB7onnamzpounn+TUje3sNs/w==", + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/@mongodb-js/mongodb-constants/-/mongodb-constants-0.14.0.tgz", + "integrity": "sha512-AuaKso7Bfq29dSXUZZMSDWR088Klz6SkL1mmzhjykA3VylfU3XwHhY1/AcPOsi0vSzn+2mQN87LKQKXp1plp2Q==", "requires": { "semver": "^7.7.1" } @@ -59476,7 +59497,7 @@ "@mongodb-js/compass-workspaces": "^0.51.0", "@mongodb-js/eslint-config-compass": "^1.4.6", "@mongodb-js/mocha-config-compass": "^1.7.0", - "@mongodb-js/mongodb-constants": "^0.12.2", + "@mongodb-js/mongodb-constants": "^0.14.0", "@mongodb-js/prettier-config-compass": "^1.2.8", "@mongodb-js/testing-library-compass": "^1.3.9", "@mongodb-js/tsconfig-compass": "^1.2.9", @@ -59506,9 +59527,9 @@ }, "dependencies": { "@mongodb-js/mongodb-constants": { - "version": "0.12.2", - "resolved": "https://registry.npmjs.org/@mongodb-js/mongodb-constants/-/mongodb-constants-0.12.2.tgz", - "integrity": "sha512-gAlknLOI4qbBjkPsLSe1tmL5ImZvnm3/7z55JseOytjKx2FQWfBKSx2gI871ppB7onnamzpounn+TUje3sNs/w==", + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/@mongodb-js/mongodb-constants/-/mongodb-constants-0.14.0.tgz", + "integrity": "sha512-AuaKso7Bfq29dSXUZZMSDWR088Klz6SkL1mmzhjykA3VylfU3XwHhY1/AcPOsi0vSzn+2mQN87LKQKXp1plp2Q==", "requires": { "semver": "^7.7.1" } @@ -59853,7 +59874,7 @@ "@mongodb-js/connection-info": "^0.17.1", "@mongodb-js/eslint-config-compass": "^1.4.6", "@mongodb-js/mocha-config-compass": "^1.7.0", - "@mongodb-js/mongodb-constants": "^0.12.2", + "@mongodb-js/mongodb-constants": "^0.14.0", "@mongodb-js/prettier-config-compass": "^1.2.8", "@mongodb-js/testing-library-compass": "^1.3.9", "@mongodb-js/tsconfig-compass": "^1.2.9", @@ -59885,9 +59906,9 @@ }, "dependencies": { "@mongodb-js/mongodb-constants": { - "version": "0.12.2", - "resolved": "https://registry.npmjs.org/@mongodb-js/mongodb-constants/-/mongodb-constants-0.12.2.tgz", - "integrity": "sha512-gAlknLOI4qbBjkPsLSe1tmL5ImZvnm3/7z55JseOytjKx2FQWfBKSx2gI871ppB7onnamzpounn+TUje3sNs/w==", + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/@mongodb-js/mongodb-constants/-/mongodb-constants-0.14.0.tgz", + "integrity": "sha512-AuaKso7Bfq29dSXUZZMSDWR088Klz6SkL1mmzhjykA3VylfU3XwHhY1/AcPOsi0vSzn+2mQN87LKQKXp1plp2Q==", "requires": { "semver": "^7.7.1" } diff --git a/packages/compass-aggregations/package.json b/packages/compass-aggregations/package.json index f2bcab6251d..30c27a57503 100644 --- a/packages/compass-aggregations/package.json +++ b/packages/compass-aggregations/package.json @@ -72,7 +72,7 @@ "@mongodb-js/compass-utils": "^0.9.10", "@mongodb-js/compass-workspaces": "^0.51.0", "@mongodb-js/explain-plan-helper": "^1.4.17", - "@mongodb-js/mongodb-constants": "^0.12.2", + "@mongodb-js/mongodb-constants": "^0.14.0", "@mongodb-js/my-queries-storage": "^0.37.0", "@mongodb-js/shell-bson-parser": "^1.2.0", "bson": "^6.10.4", diff --git a/packages/compass-aggregations/src/modules/search-indexes.ts b/packages/compass-aggregations/src/modules/search-indexes.ts index 341f1d0f283..82fcc85e556 100644 --- a/packages/compass-aggregations/src/modules/search-indexes.ts +++ b/packages/compass-aggregations/src/modules/search-indexes.ts @@ -80,11 +80,10 @@ const reducer: Reducer = (state = INITIAL_STATE, action) => { return state; }; -export const fetchIndexes = ( - viewNamespace?: string -): PipelineBuilderThunkAction> => { +export const fetchIndexes = (): PipelineBuilderThunkAction> => { return async (dispatch, getState) => { const { + editViewName: viewNamespace, namespace: collectionNamespace, dataService: { dataService }, searchIndexes: { status }, @@ -127,4 +126,26 @@ export const createSearchIndex = (): PipelineBuilderThunkAction => { }; }; +/** + * Checks whether a namespace has existing search indexes + * + * @param namespace - collection/view namespace + * @param dataService - dataService instance + * @returns whether namespace has existing search indexes + */ +export const namespaceHasSearchIndexes = async ( + namespace: string, + dataService: { getSearchIndexes?: (ns: string) => Promise } +): Promise => { + try { + if (!dataService.getSearchIndexes) { + throw new Error('Cannot get search indexes in this environment'); + } + const indexes = await dataService.getSearchIndexes(namespace); + return indexes.length > 0; + } catch { + throw new Error('Error occured fetching indexes'); + } +}; + export default reducer; diff --git a/packages/compass-aggregations/src/modules/update-view.spec.ts b/packages/compass-aggregations/src/modules/update-view.spec.ts index 47130478e0b..86ad7a55282 100644 --- a/packages/compass-aggregations/src/modules/update-view.spec.ts +++ b/packages/compass-aggregations/src/modules/update-view.spec.ts @@ -12,6 +12,7 @@ import { createDefaultConnectionInfo } from '@mongodb-js/testing-library-compass // Importing this to stub showConfirmation import * as updateViewSlice from './update-view'; +import * as searchIndexesSlice from './search-indexes'; const TEST_CONNECTION_INFO = { ...createDefaultConnectionInfo(), title: '' }; @@ -52,6 +53,7 @@ describe('update-view module', function () { let getStateMock: () => any; let updateCollectionFake = sinon.fake(); let showConfirmationStub: sinon.SinonStub; + let namespaceHasSearchIndexesStub: sinon.SinonStub; beforeEach(function () { dispatchFake = sinon.fake(); @@ -59,9 +61,13 @@ describe('update-view module', function () { showConfirmationStub = sinon .stub(updateViewSlice, 'showConfirmation') .resolves(true); + + namespaceHasSearchIndexesStub = sinon + .stub(searchIndexesSlice, 'namespaceHasSearchIndexes') + .resolves(true); + stateMock = { pipelineBuilder: { pipelineMode: 'builder-ui' }, - searchIndexes: { indexes: [{ name: 'index1' }] }, focusMode: { isEnabled: false }, namespace: 'aa.bb', editViewName: 'aa.bb', @@ -76,6 +82,7 @@ describe('update-view module', function () { afterEach(function () { showConfirmationStub.restore(); + namespaceHasSearchIndexesStub.restore(); }); it('first it calls to dismiss any existing error', async function () { @@ -88,8 +95,7 @@ describe('update-view module', function () { }); it('does not shows confirmation banner if search indexes are not present', async function () { - stateMock.searchIndexes.indexes = []; - + namespaceHasSearchIndexesStub.resolves(false); const runUpdateView = updateView(); await runUpdateView(dispatchFake, getStateMock, thunkArg as any); diff --git a/packages/compass-aggregations/src/modules/update-view.ts b/packages/compass-aggregations/src/modules/update-view.ts index 65d4c904a2c..e650ed4c296 100644 --- a/packages/compass-aggregations/src/modules/update-view.ts +++ b/packages/compass-aggregations/src/modules/update-view.ts @@ -9,7 +9,7 @@ import type { PipelineBuilderThunkAction } from '.'; import { isAction } from '../utils/is-action'; import type { AnyAction } from 'redux'; import { showConfirmation as showConfirmationModal } from '@mongodb-js/compass-components'; -import { fetchIndexes } from './search-indexes'; +import { namespaceHasSearchIndexes } from './search-indexes'; import { isPipelineSearchQueryable } from '@mongodb-js/compass-utils'; export type UpdateViewState = null | string; @@ -113,9 +113,7 @@ export const updateView = (): PipelineBuilderThunkAction> => { pipelineBuilder ); - // confirmation banner if indexes present - await dispatch(fetchIndexes(viewNamespace)); - if (state.searchIndexes.indexes.length > 0) { + if (ds && (await namespaceHasSearchIndexes(viewNamespace, ds))) { const pipelineIsSearchQueryable = isPipelineSearchQueryable(viewPipeline); const confirmed = await showConfirmation({ title: `Are you sure you want to update the view?`, diff --git a/packages/compass-aggregations/src/stores/store.ts b/packages/compass-aggregations/src/stores/store.ts index 6111aa30702..6c3072b1ff0 100644 --- a/packages/compass-aggregations/src/stores/store.ts +++ b/packages/compass-aggregations/src/stores/store.ts @@ -22,7 +22,10 @@ import { setCollections, } from '../modules/collections-fields'; import type { CollectionInfo } from '../modules/collections-fields'; -import { INITIAL_STATE as SEARCH_INDEXES_INITIAL_STATE } from '../modules/search-indexes'; +import { + fetchIndexes, + INITIAL_STATE as SEARCH_INDEXES_INITIAL_STATE, +} from '../modules/search-indexes'; import { INITIAL_PANEL_OPEN_LOCAL_STORAGE_KEY } from '../modules/side-panel'; import type { DataService } from '../modules/data-service'; import type { WorkspacesService } from '@mongodb-js/compass-workspaces/provider'; @@ -196,6 +199,8 @@ export function activateAggregationsPlugin( void store.dispatch(refreshInputDocuments()); }; + void store.dispatch(fetchIndexes()); + on(localAppRegistry, 'generate-aggregation-from-query', (data) => { store.dispatch(generateAggregationFromQuery(data)); }); diff --git a/packages/compass-collection/package.json b/packages/compass-collection/package.json index 7a29fa00f77..182aedd0e81 100644 --- a/packages/compass-collection/package.json +++ b/packages/compass-collection/package.json @@ -56,7 +56,7 @@ "@mongodb-js/compass-telemetry": "^1.13.0", "@mongodb-js/compass-workspaces": "^0.51.0", "@mongodb-js/connection-info": "^0.17.1", - "@mongodb-js/mongodb-constants": "^0.12.2", + "@mongodb-js/mongodb-constants": "^0.14.0", "compass-preferences-model": "^2.50.0", "hadron-document": "^8.9.5", "mongodb": "^6.17.0", diff --git a/packages/compass-editor/package.json b/packages/compass-editor/package.json index 4b7772f3696..7b0c1f3f226 100644 --- a/packages/compass-editor/package.json +++ b/packages/compass-editor/package.json @@ -73,7 +73,7 @@ "@codemirror/view": "^6.38.0", "@lezer/highlight": "^1.2.1", "@mongodb-js/compass-components": "^1.48.0", - "@mongodb-js/mongodb-constants": "^0.12.2", + "@mongodb-js/mongodb-constants": "^0.14.0", "mongodb-query-parser": "^4.3.0", "polished": "^4.2.2", "prettier": "^2.7.1", diff --git a/packages/compass-indexes/package.json b/packages/compass-indexes/package.json index 0c3a63ba506..2cbaf67048f 100644 --- a/packages/compass-indexes/package.json +++ b/packages/compass-indexes/package.json @@ -76,7 +76,7 @@ "@mongodb-js/compass-logging": "^1.7.11", "@mongodb-js/compass-telemetry": "^1.13.0", "@mongodb-js/compass-workspaces": "^0.51.0", - "@mongodb-js/mongodb-constants": "^0.12.2", + "@mongodb-js/mongodb-constants": "^0.14.0", "@mongodb-js/shell-bson-parser": "^1.2.0", "@mongodb-js/connection-info": "^0.17.1", "@mongodb-js/compass-utils": "^0.9.10", diff --git a/packages/compass-indexes/src/components/indexes-toolbar/indexes-toolbar.tsx b/packages/compass-indexes/src/components/indexes-toolbar/indexes-toolbar.tsx index 09cb76268ef..3a529d3b8d6 100644 --- a/packages/compass-indexes/src/components/indexes-toolbar/indexes-toolbar.tsx +++ b/packages/compass-indexes/src/components/indexes-toolbar/indexes-toolbar.tsx @@ -23,10 +23,7 @@ import { useConnectionInfo } from '@mongodb-js/compass-connections/provider'; import semver from 'semver'; import type { RootState } from '../../modules'; -import { - isVersionSearchCompatibleForViews, - createSearchIndexOpened, -} from '../../modules/search-indexes'; +import { createSearchIndexOpened } from '../../modules/search-indexes'; import { getAtlasSearchIndexesLink } from '../../utils/atlas-search-indexes-link'; import { createIndexOpened } from '../../modules/create-index'; import type { IndexView } from '../../modules/index-view'; @@ -34,6 +31,7 @@ import { indexViewChanged } from '../../modules/index-view'; import type { CollectionStats } from '../../modules/collection-stats'; import { isPipelineSearchQueryable } from '@mongodb-js/compass-utils'; import type { Document } from 'mongodb'; +import { VIEW_PIPELINE_UTILS } from '@mongodb-js/mongodb-constants'; const toolbarButtonsContainer = css({ display: 'flex', @@ -117,7 +115,10 @@ export const IndexesToolbar: React.FunctionComponent = ({ const { atlasMetadata } = useConnectionInfo(); const showInsights = usePreference('showInsights') && !errorMessage; const showCreateIndexButton = - (!isReadonlyView || isVersionSearchCompatibleForViews(serverVersion)) && + (!isReadonlyView || + VIEW_PIPELINE_UTILS.isVersionSearchCompatibleForViewsCompass( + serverVersion + )) && !readOnly && !errorMessage; const refreshButtonIcon = isRefreshing ? ( @@ -139,7 +140,9 @@ export const IndexesToolbar: React.FunctionComponent = ({ data-testid="indexes-toolbar-container" > {(!isReadonlyView || - (isVersionSearchCompatibleForViews(serverVersion) && + (VIEW_PIPELINE_UTILS.isVersionSearchCompatibleForViewsCompass( + serverVersion + ) && isSearchManagementActive)) && (
diff --git a/packages/compass-indexes/src/components/indexes/indexes.tsx b/packages/compass-indexes/src/components/indexes/indexes.tsx index 73925cc36f0..9128ad5bad3 100644 --- a/packages/compass-indexes/src/components/indexes/indexes.tsx +++ b/packages/compass-indexes/src/components/indexes/indexes.tsx @@ -15,10 +15,8 @@ import IndexesToolbar from '../indexes-toolbar/indexes-toolbar'; import RegularIndexesTable from '../regular-indexes-table/regular-indexes-table'; import SearchIndexesTable from '../search-indexes-table/search-indexes-table'; import { refreshRegularIndexes } from '../../modules/regular-indexes'; -import { - isVersionSearchCompatibleForViews, - refreshSearchIndexes, -} from '../../modules/search-indexes'; +import { refreshSearchIndexes } from '../../modules/search-indexes'; +import { VIEW_PIPELINE_UTILS } from '@mongodb-js/mongodb-constants'; import type { State as RegularIndexesState } from '../../modules/regular-indexes'; import type { State as SearchIndexesState } from '../../modules/search-indexes'; import { FetchStatuses } from '../../utils/fetch-status'; @@ -59,20 +57,6 @@ const linkTitle = 'Search and Vector Search.'; const DISMISSED_SEARCH_INDEXES_BANNER_LOCAL_STORAGE_KEY = 'mongodb_compass_dismissedSearchIndexesBanner' as const; -export const MIN_VERSION_FOR_VIEW_SEARCH_COMPATIBILITY_DE = '8.0.0'; -export const isVersionSearchCompatibleForViewsDataExplorer = ( - serverVersion: string -) => { - try { - return semver.gte( - serverVersion, - MIN_VERSION_FOR_VIEW_SEARCH_COMPATIBILITY_DE - ); - } catch { - return false; - } -}; - const ViewVersionIncompatibleEmptyState = ({ serverVersion, enableAtlasSearchIndexes, @@ -81,7 +65,9 @@ const ViewVersionIncompatibleEmptyState = ({ enableAtlasSearchIndexes: boolean; }) => { if ( - isVersionSearchCompatibleForViews(serverVersion) && + VIEW_PIPELINE_UTILS.isVersionSearchCompatibleForViewsCompass( + serverVersion + ) && enableAtlasSearchIndexes ) { return null; @@ -239,7 +225,11 @@ export function Indexes({ const getBanner = () => { if (isReadonlyView) { - if (!isVersionSearchCompatibleForViews(serverVersion)) { + if ( + !VIEW_PIPELINE_UTILS.isVersionSearchCompatibleForViewsCompass( + serverVersion + ) + ) { return ( )} {(!isReadonlyView || - (isVersionSearchCompatibleForViews(serverVersion) && + (VIEW_PIPELINE_UTILS.isVersionSearchCompatibleForViewsCompass( + serverVersion + ) && enableAtlasSearchIndexes)) && currentIndexesView === 'search-indexes' && } {isReadonlyView && searchIndexes.indexes.length === 0 && ( diff --git a/packages/compass-indexes/src/components/view-version-incompatible-banners/view-version-incompatible-banners.tsx b/packages/compass-indexes/src/components/view-version-incompatible-banners/view-version-incompatible-banners.tsx index 9d45ebd95b9..b7a2af66b5d 100644 --- a/packages/compass-indexes/src/components/view-version-incompatible-banners/view-version-incompatible-banners.tsx +++ b/packages/compass-indexes/src/components/view-version-incompatible-banners/view-version-incompatible-banners.tsx @@ -7,8 +7,7 @@ import { import { getAtlasUpgradeClusterLink } from '../../utils/atlas-upgrade-cluster-link'; import React from 'react'; import type { AtlasClusterMetadata } from '@mongodb-js/connection-info'; -import { isVersionSearchCompatibleForViews } from '../../modules/search-indexes'; -import { isVersionSearchCompatibleForViewsDataExplorer } from '../indexes/indexes'; +import { VIEW_PIPELINE_UTILS } from '@mongodb-js/mongodb-constants'; const viewContentStyles = css({ display: 'flex', @@ -28,8 +27,12 @@ export const ViewVersionIncompatibleBanner = ({ }) => { // return if compatible, 8.1+ for compass and 8.0+ for data explorer if ( - isVersionSearchCompatibleForViews(serverVersion) || - (isVersionSearchCompatibleForViewsDataExplorer(serverVersion) && + VIEW_PIPELINE_UTILS.isVersionSearchCompatibleForViewsCompass( + serverVersion + ) || + (VIEW_PIPELINE_UTILS.isVersionSearchCompatibleForViewsDataExplorer( + serverVersion + ) && !enableAtlasSearchIndexes) ) { return null; @@ -39,7 +42,9 @@ export const ViewVersionIncompatibleBanner = ({ // if compass version matches min compatibility for DE, we recommend Atlas UI as well const recommendedCta = enableAtlasSearchIndexes && - isVersionSearchCompatibleForViewsDataExplorer(serverVersion) + VIEW_PIPELINE_UTILS.isVersionSearchCompatibleForViewsDataExplorer( + serverVersion + ) ? 'Upgrade your cluster or manage search indexes on views in the Atlas UI.' : 'Upgrade your cluster to create search indexes on views.'; return ( diff --git a/packages/compass-indexes/src/modules/search-indexes.ts b/packages/compass-indexes/src/modules/search-indexes.ts index cd25495795e..0261ef62711 100644 --- a/packages/compass-indexes/src/modules/search-indexes.ts +++ b/packages/compass-indexes/src/modules/search-indexes.ts @@ -17,7 +17,7 @@ import type { FetchReason } from '../utils/fetch-reason'; import type { IndexesThunkAction } from '.'; import { switchToSearchIndexes } from './index-view'; import type { IndexViewChangedAction } from './index-view'; -import semver from 'semver'; +import { VIEW_PIPELINE_UTILS } from '@mongodb-js/mongodb-constants'; const ATLAS_SEARCH_SERVER_ERRORS: Record = { InvalidIndexSpecificationOption: 'Invalid index definition.', @@ -25,18 +25,6 @@ const ATLAS_SEARCH_SERVER_ERRORS: Record = { 'This index name is already in use. Please choose another one.', }; -const MIN_VERSION_FOR_VIEW_SEARCH_COMPATIBILITY_COMPASS = '8.1.0'; -export const isVersionSearchCompatibleForViews = (serverVersion: string) => { - try { - return semver.gte( - serverVersion, - MIN_VERSION_FOR_VIEW_SEARCH_COMPATIBILITY_COMPASS - ); - } catch { - return false; - } -}; - export enum ActionTypes { // Fetch indexes FetchSearchIndexesStarted = 'compass-indexes/search-indexes/fetch-search-indexes-started', @@ -620,7 +608,10 @@ const fetchIndexes = ( } = getState(); if ( - (isReadonlyView && !isVersionSearchCompatibleForViews(serverVersion)) || + (isReadonlyView && + !VIEW_PIPELINE_UTILS.isVersionSearchCompatibleForViewsCompass( + serverVersion + )) || !isWritable ) { return; // return if view is not search compatible diff --git a/packages/compass-query-bar/package.json b/packages/compass-query-bar/package.json index 5ac0ab83504..734e6b4e9b3 100644 --- a/packages/compass-query-bar/package.json +++ b/packages/compass-query-bar/package.json @@ -76,7 +76,7 @@ "@mongodb-js/compass-generative-ai": "^0.50.0", "@mongodb-js/compass-logging": "^1.7.11", "@mongodb-js/compass-telemetry": "^1.13.0", - "@mongodb-js/mongodb-constants": "^0.12.2", + "@mongodb-js/mongodb-constants": "^0.14.0", "@mongodb-js/my-queries-storage": "^0.37.0", "bson": "^6.10.4", "compass-preferences-model": "^2.50.0", diff --git a/packages/compass-schema-validation/package.json b/packages/compass-schema-validation/package.json index cf3be658f80..58b78d85056 100644 --- a/packages/compass-schema-validation/package.json +++ b/packages/compass-schema-validation/package.json @@ -78,7 +78,7 @@ "@mongodb-js/compass-schema": "^6.71.0", "@mongodb-js/compass-telemetry": "^1.13.0", "@mongodb-js/compass-workspaces": "^0.51.0", - "@mongodb-js/mongodb-constants": "^0.12.2", + "@mongodb-js/mongodb-constants": "^0.14.0", "bson": "^6.10.4", "compass-preferences-model": "^2.50.0", "javascript-stringify": "^2.0.1", diff --git a/packages/compass-sidebar/package.json b/packages/compass-sidebar/package.json index d0c23da01b3..eb288604c49 100644 --- a/packages/compass-sidebar/package.json +++ b/packages/compass-sidebar/package.json @@ -59,7 +59,7 @@ "@mongodb-js/compass-telemetry": "^1.13.0", "@mongodb-js/compass-workspaces": "^0.51.0", "@mongodb-js/connection-info": "^0.17.1", - "@mongodb-js/mongodb-constants": "^0.12.2", + "@mongodb-js/mongodb-constants": "^0.14.0", "compass-preferences-model": "^2.50.0", "lodash": "^4.17.21", "mongodb": "^6.17.0", From 2bf679d4d1a9066e079800acf47c1d02f359797c Mon Sep 17 00:00:00 2001 From: Darshana Venkatesh Date: Fri, 22 Aug 2025 00:11:14 -0700 Subject: [PATCH 14/22] remove compass-utils dep --- package-lock.json | 2 - packages/compass-aggregations/package.json | 1 - .../src/modules/update-view.ts | 5 +- .../src/components/indexes/indexes.tsx | 5 +- packages/compass-utils/src/index.ts | 1 - .../src/view-search-queryable.spec.ts | 69 ------------------- .../src/view-search-queryable.ts | 30 -------- 7 files changed, 6 insertions(+), 107 deletions(-) delete mode 100644 packages/compass-utils/src/view-search-queryable.spec.ts delete mode 100644 packages/compass-utils/src/view-search-queryable.ts diff --git a/package-lock.json b/package-lock.json index a7ef21d2db6..8875b9ac432 100644 --- a/package-lock.json +++ b/package-lock.json @@ -43900,7 +43900,6 @@ "@mongodb-js/compass-generative-ai": "^0.50.0", "@mongodb-js/compass-logging": "^1.7.11", "@mongodb-js/compass-telemetry": "^1.13.0", - "@mongodb-js/compass-utils": "^0.9.10", "@mongodb-js/compass-workspaces": "^0.51.0", "@mongodb-js/explain-plan-helper": "^1.4.17", "@mongodb-js/mongodb-constants": "^0.14.0", @@ -56843,7 +56842,6 @@ "@mongodb-js/compass-generative-ai": "^0.50.0", "@mongodb-js/compass-logging": "^1.7.11", "@mongodb-js/compass-telemetry": "^1.13.0", - "@mongodb-js/compass-utils": "^0.9.10", "@mongodb-js/compass-workspaces": "^0.51.0", "@mongodb-js/eslint-config-compass": "^1.4.6", "@mongodb-js/explain-plan-helper": "^1.4.17", diff --git a/packages/compass-aggregations/package.json b/packages/compass-aggregations/package.json index 30c27a57503..498505304e4 100644 --- a/packages/compass-aggregations/package.json +++ b/packages/compass-aggregations/package.json @@ -69,7 +69,6 @@ "@mongodb-js/compass-generative-ai": "^0.50.0", "@mongodb-js/compass-logging": "^1.7.11", "@mongodb-js/compass-telemetry": "^1.13.0", - "@mongodb-js/compass-utils": "^0.9.10", "@mongodb-js/compass-workspaces": "^0.51.0", "@mongodb-js/explain-plan-helper": "^1.4.17", "@mongodb-js/mongodb-constants": "^0.14.0", diff --git a/packages/compass-aggregations/src/modules/update-view.ts b/packages/compass-aggregations/src/modules/update-view.ts index e650ed4c296..d25069f162a 100644 --- a/packages/compass-aggregations/src/modules/update-view.ts +++ b/packages/compass-aggregations/src/modules/update-view.ts @@ -10,7 +10,7 @@ import { isAction } from '../utils/is-action'; import type { AnyAction } from 'redux'; import { showConfirmation as showConfirmationModal } from '@mongodb-js/compass-components'; import { namespaceHasSearchIndexes } from './search-indexes'; -import { isPipelineSearchQueryable } from '@mongodb-js/compass-utils'; +import { VIEW_PIPELINE_UTILS } from '@mongodb-js/mongodb-constants'; export type UpdateViewState = null | string; @@ -114,7 +114,8 @@ export const updateView = (): PipelineBuilderThunkAction> => { ); if (ds && (await namespaceHasSearchIndexes(viewNamespace, ds))) { - const pipelineIsSearchQueryable = isPipelineSearchQueryable(viewPipeline); + const pipelineIsSearchQueryable = + VIEW_PIPELINE_UTILS.isPipelineSearchQueryable(viewPipeline); const confirmed = await showConfirmation({ title: `Are you sure you want to update the view?`, description: pipelineIsSearchQueryable diff --git a/packages/compass-indexes/src/components/indexes/indexes.tsx b/packages/compass-indexes/src/components/indexes/indexes.tsx index 9128ad5bad3..1870fedd28a 100644 --- a/packages/compass-indexes/src/components/indexes/indexes.tsx +++ b/packages/compass-indexes/src/components/indexes/indexes.tsx @@ -36,7 +36,6 @@ import { ViewVersionIncompatibleBanner } from '../view-version-incompatible-bann import semver from 'semver'; import type { SearchIndex } from 'mongodb-data-service'; import type { CollectionStats } from '../../modules/collection-stats'; -import { isPipelineSearchQueryable } from '@mongodb-js/compass-utils'; import type { Document } from 'mongodb'; // This constant is used as a trigger to show an insight whenever number of @@ -220,7 +219,9 @@ export function Indexes({ const { atlasMetadata } = useConnectionInfo(); const isViewPipelineSearchQueryable = isReadonlyView && collectionStats?.pipeline - ? isPipelineSearchQueryable(collectionStats.pipeline as Document[]) + ? VIEW_PIPELINE_UTILS.isPipelineSearchQueryable( + collectionStats.pipeline as Document[] + ) : true; const getBanner = () => { diff --git a/packages/compass-utils/src/index.ts b/packages/compass-utils/src/index.ts index 95ee0e87251..477608e14dc 100644 --- a/packages/compass-utils/src/index.ts +++ b/packages/compass-utils/src/index.ts @@ -8,4 +8,3 @@ export { isCancelError, throwIfAborted, } from './cancellable-promise'; -export { isPipelineSearchQueryable } from './view-search-queryable'; diff --git a/packages/compass-utils/src/view-search-queryable.spec.ts b/packages/compass-utils/src/view-search-queryable.spec.ts deleted file mode 100644 index f41af259da4..00000000000 --- a/packages/compass-utils/src/view-search-queryable.spec.ts +++ /dev/null @@ -1,69 +0,0 @@ -import { expect } from 'chai'; -import { isPipelineSearchQueryable } from './view-search-queryable'; // Adjust the import path as necessary -import type { Document } from 'mongodb'; - -describe('isPipelineSearchQueryable', () => { - it('should return true for a valid pipeline with $addFields stage', () => { - const pipeline: Document[] = [{ $addFields: { testField: 'testValue' } }]; - expect(isPipelineSearchQueryable(pipeline)).to.equal(true); - }); - - it('should return true for a valid pipeline with $set stage', () => { - const pipeline: Document[] = [{ $set: { testField: 'testValue' } }]; - expect(isPipelineSearchQueryable(pipeline)).to.equal(true); - }); - - it('should return true for a valid pipeline with $match stage using $expr', () => { - const pipeline: Document[] = [ - { $match: { $expr: { $eq: ['$field', 'value'] } } }, - ]; - expect(isPipelineSearchQueryable(pipeline)).to.equal(true); - }); - - it('should return false for a pipeline with an unsupported stage', () => { - const pipeline: Document[] = [{ $group: { _id: '$field' } }]; - expect(isPipelineSearchQueryable(pipeline)).to.equal(false); - }); - - it('should return false for a $match stage without $expr', () => { - const pipeline: Document[] = [{ $match: { nonExprKey: 'someValue' } }]; - expect(isPipelineSearchQueryable(pipeline)).to.equal(false); - }); - - it('should return false for a $match stage with $expr and additional fields', () => { - const pipeline: Document[] = [ - { - $match: { $expr: { $eq: ['$field', 'value'] }, anotherField: 'value' }, - }, - ]; - expect(isPipelineSearchQueryable(pipeline)).to.equal(false); - }); - - it('should return true for an empty pipeline', () => { - const pipeline: Document[] = []; - expect(isPipelineSearchQueryable(pipeline)).to.equal(true); - }); - - it('should return false if any stage in the pipeline is invalid', () => { - const pipeline: Document[] = [ - { $addFields: { testField: 'testValue' } }, - { $match: { $expr: { $eq: ['$field', 'value'] } } }, - { $group: { _id: '$field' } }, - ]; - expect(isPipelineSearchQueryable(pipeline)).to.equal(false); - }); - - it('should handle a pipeline with multiple valid stages', () => { - const pipeline: Document[] = [ - { $addFields: { field1: 'value1' } }, - { $match: { $expr: { $eq: ['$field', 'value'] } } }, - { $set: { field2: 'value2' } }, - ]; - expect(isPipelineSearchQueryable(pipeline)).to.equal(true); - }); - - it('should return false for a $match stage with no conditions', () => { - const pipeline: Document[] = [{ $match: {} }]; - expect(isPipelineSearchQueryable(pipeline)).to.equal(false); - }); -}); diff --git a/packages/compass-utils/src/view-search-queryable.ts b/packages/compass-utils/src/view-search-queryable.ts deleted file mode 100644 index a48d66d1d0c..00000000000 --- a/packages/compass-utils/src/view-search-queryable.ts +++ /dev/null @@ -1,30 +0,0 @@ -import type { Document } from 'mongodb'; - -export const isPipelineSearchQueryable = (pipeline: Document[]): boolean => { - for (const stage of pipeline) { - const stageKey = Object.keys(stage)[0]; - - // Check if the stage is $addFields, $set, or $match - if ( - !( - stageKey === '$addFields' || - stageKey === '$set' || - stageKey === '$match' - ) - ) { - return false; - } - - // If the stage is $match, check if it uses $expr - if (stageKey === '$match') { - const matchStage = stage['$match'] as Document; - const matchKeys = Object.keys(matchStage || {}); - - if (!(matchKeys.length === 1 && matchKeys.includes('$expr'))) { - return false; - } - } - } - - return true; -}; From e2d2f27a759e6d29e9c345cbecb4e0abc5c4eb7a Mon Sep 17 00:00:00 2001 From: Darshana Venkatesh Date: Fri, 22 Aug 2025 00:29:26 -0700 Subject: [PATCH 15/22] remove compass utils changes and cleanup --- package-lock.json | 60 +------------------ .../src/modules/search-indexes.ts | 4 -- .../compass-aggregations/src/stores/store.ts | 7 +-- .../indexes-toolbar/indexes-toolbar.spec.tsx | 1 - .../indexes-toolbar/indexes-toolbar.tsx | 5 +- .../src/components/indexes/indexes.tsx | 8 ++- .../search-indexes-table.tsx | 6 +- packages/compass-utils/package.json | 3 +- 8 files changed, 15 insertions(+), 79 deletions(-) diff --git a/package-lock.json b/package-lock.json index 8875b9ac432..0d7884bcc13 100644 --- a/package-lock.json +++ b/package-lock.json @@ -48246,8 +48246,7 @@ "license": "SSPL", "dependencies": { "@electron/remote": "^2.1.3", - "electron": "^37.2.6", - "mongodb": "^6.18.0" + "electron": "^37.2.6" }, "devDependencies": { "@mongodb-js/eslint-config-compass": "^1.4.6", @@ -48266,52 +48265,6 @@ "typescript": "^5.8.3" } }, - "packages/compass-utils/node_modules/mongodb": { - "version": "6.18.0", - "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-6.18.0.tgz", - "integrity": "sha512-fO5ttN9VC8P0F5fqtQmclAkgXZxbIkYRTUi1j8JO6IYwvamkhtYDilJr35jOPELR49zqCJgXZWwCtW7B+TM8vQ==", - "license": "Apache-2.0", - "dependencies": { - "@mongodb-js/saslprep": "^1.1.9", - "bson": "^6.10.4", - "mongodb-connection-string-url": "^3.0.0" - }, - "engines": { - "node": ">=16.20.1" - }, - "peerDependencies": { - "@aws-sdk/credential-providers": "^3.188.0", - "@mongodb-js/zstd": "^1.1.0 || ^2.0.0", - "gcp-metadata": "^5.2.0", - "kerberos": "^2.0.1", - "mongodb-client-encryption": ">=6.0.0 <7", - "snappy": "^7.2.2", - "socks": "^2.7.1" - }, - "peerDependenciesMeta": { - "@aws-sdk/credential-providers": { - "optional": true - }, - "@mongodb-js/zstd": { - "optional": true - }, - "gcp-metadata": { - "optional": true - }, - "kerberos": { - "optional": true - }, - "mongodb-client-encryption": { - "optional": true - }, - "snappy": { - "optional": true - }, - "socks": { - "optional": true - } - } - }, "packages/compass-utils/node_modules/sinon": { "version": "9.2.4", "resolved": "https://registry.npmjs.org/sinon/-/sinon-9.2.4.tgz", @@ -60232,22 +60185,11 @@ "electron": "^37.2.6", "gen-esm-wrapper": "^1.1.0", "mocha": "^10.2.0", - "mongodb": "^6.18.0", "nyc": "^15.1.0", "sinon": "^9.2.3", "typescript": "^5.8.3" }, "dependencies": { - "mongodb": { - "version": "6.18.0", - "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-6.18.0.tgz", - "integrity": "sha512-fO5ttN9VC8P0F5fqtQmclAkgXZxbIkYRTUi1j8JO6IYwvamkhtYDilJr35jOPELR49zqCJgXZWwCtW7B+TM8vQ==", - "requires": { - "@mongodb-js/saslprep": "^1.1.9", - "bson": "^6.10.4", - "mongodb-connection-string-url": "^3.0.0" - } - }, "sinon": { "version": "9.2.4", "resolved": "https://registry.npmjs.org/sinon/-/sinon-9.2.4.tgz", diff --git a/packages/compass-aggregations/src/modules/search-indexes.ts b/packages/compass-aggregations/src/modules/search-indexes.ts index 82fcc85e556..97ec575c576 100644 --- a/packages/compass-aggregations/src/modules/search-indexes.ts +++ b/packages/compass-aggregations/src/modules/search-indexes.ts @@ -83,14 +83,10 @@ const reducer: Reducer = (state = INITIAL_STATE, action) => { export const fetchIndexes = (): PipelineBuilderThunkAction> => { return async (dispatch, getState) => { const { - editViewName: viewNamespace, - namespace: collectionNamespace, dataService: { dataService }, searchIndexes: { status }, } = getState(); - const namespace = viewNamespace || collectionNamespace; - if ( !dataService || status === SearchIndexesStatuses.LOADING || diff --git a/packages/compass-aggregations/src/stores/store.ts b/packages/compass-aggregations/src/stores/store.ts index 6c3072b1ff0..6111aa30702 100644 --- a/packages/compass-aggregations/src/stores/store.ts +++ b/packages/compass-aggregations/src/stores/store.ts @@ -22,10 +22,7 @@ import { setCollections, } from '../modules/collections-fields'; import type { CollectionInfo } from '../modules/collections-fields'; -import { - fetchIndexes, - INITIAL_STATE as SEARCH_INDEXES_INITIAL_STATE, -} from '../modules/search-indexes'; +import { INITIAL_STATE as SEARCH_INDEXES_INITIAL_STATE } from '../modules/search-indexes'; import { INITIAL_PANEL_OPEN_LOCAL_STORAGE_KEY } from '../modules/side-panel'; import type { DataService } from '../modules/data-service'; import type { WorkspacesService } from '@mongodb-js/compass-workspaces/provider'; @@ -199,8 +196,6 @@ export function activateAggregationsPlugin( void store.dispatch(refreshInputDocuments()); }; - void store.dispatch(fetchIndexes()); - on(localAppRegistry, 'generate-aggregation-from-query', (data) => { store.dispatch(generateAggregationFromQuery(data)); }); diff --git a/packages/compass-indexes/src/components/indexes-toolbar/indexes-toolbar.spec.tsx b/packages/compass-indexes/src/components/indexes-toolbar/indexes-toolbar.spec.tsx index 3674fa255dc..2d0d296635e 100644 --- a/packages/compass-indexes/src/components/indexes-toolbar/indexes-toolbar.spec.tsx +++ b/packages/compass-indexes/src/components/indexes-toolbar/indexes-toolbar.spec.tsx @@ -14,7 +14,6 @@ import type { PreferencesAccess } from 'compass-preferences-model'; import { createSandboxFromDefaultPreferences } from 'compass-preferences-model'; import { PreferencesProvider } from 'compass-preferences-model/provider'; import type { Document } from 'mongodb'; -//import type {Document} from "mongodb"; describe('IndexesToolbar Component', function () { before(cleanup); diff --git a/packages/compass-indexes/src/components/indexes-toolbar/indexes-toolbar.tsx b/packages/compass-indexes/src/components/indexes-toolbar/indexes-toolbar.tsx index 3a529d3b8d6..cb522741e3e 100644 --- a/packages/compass-indexes/src/components/indexes-toolbar/indexes-toolbar.tsx +++ b/packages/compass-indexes/src/components/indexes-toolbar/indexes-toolbar.tsx @@ -29,7 +29,6 @@ import { createIndexOpened } from '../../modules/create-index'; import type { IndexView } from '../../modules/index-view'; import { indexViewChanged } from '../../modules/index-view'; import type { CollectionStats } from '../../modules/collection-stats'; -import { isPipelineSearchQueryable } from '@mongodb-js/compass-utils'; import type { Document } from 'mongodb'; import { VIEW_PIPELINE_UTILS } from '@mongodb-js/mongodb-constants'; @@ -130,7 +129,9 @@ export const IndexesToolbar: React.FunctionComponent = ({ ); const isViewPipelineSearchQueryable = isReadonlyView && collectionStats?.pipeline - ? isPipelineSearchQueryable(collectionStats.pipeline as Document[]) + ? VIEW_PIPELINE_UTILS.isPipelineSearchQueryable( + collectionStats.pipeline as Document[] + ) : true; const pipelineNotSearchQueryableDescription = 'Search indexes can only be created on views containing $addFields, $set or $match stages with the $expr operator.'; diff --git a/packages/compass-indexes/src/components/indexes/indexes.tsx b/packages/compass-indexes/src/components/indexes/indexes.tsx index 1870fedd28a..da67e6ba1b0 100644 --- a/packages/compass-indexes/src/components/indexes/indexes.tsx +++ b/packages/compass-indexes/src/components/indexes/indexes.tsx @@ -33,7 +33,6 @@ import { getAtlasSearchIndexesLink } from '../../utils/atlas-search-indexes-link import CreateIndexModal from '../create-index-modal/create-index-modal'; import { ZeroGraphic } from '../search-indexes-table/zero-graphic'; import { ViewVersionIncompatibleBanner } from '../view-version-incompatible-banners/view-version-incompatible-banners'; -import semver from 'semver'; import type { SearchIndex } from 'mongodb-data-service'; import type { CollectionStats } from '../../modules/collection-stats'; import type { Document } from 'mongodb'; @@ -79,7 +78,7 @@ const ViewVersionIncompatibleEmptyState = ({ cannot create, drop or re-build indexes on a standard view directly, nor get a list of indexes on the view." callToActionLink={ Learn more about views @@ -110,7 +109,10 @@ const ViewNotSearchCompatibleBanner = ({ $addFields, $set or $match stages with the $expr operator are compatible with search indexes.{' '} {!hasNoSearchIndexes && 'Edit the view to rebuild search indexes.'}{' '} - + Learn more. diff --git a/packages/compass-indexes/src/components/search-indexes-table/search-indexes-table.tsx b/packages/compass-indexes/src/components/search-indexes-table/search-indexes-table.tsx index 70bab46eab2..4cf4dde8173 100644 --- a/packages/compass-indexes/src/components/search-indexes-table/search-indexes-table.tsx +++ b/packages/compass-indexes/src/components/search-indexes-table/search-indexes-table.tsx @@ -40,7 +40,7 @@ import BadgeWithIconLink from '../indexes-table/badge-with-icon-link'; import { useConnectionInfo } from '@mongodb-js/compass-connections/provider'; import { useWorkspaceTabId } from '@mongodb-js/compass-workspaces/provider'; import type { CollectionStats } from '../../modules/collection-stats'; -import { isPipelineSearchQueryable } from '@mongodb-js/compass-utils'; +import { VIEW_PIPELINE_UTILS } from '@mongodb-js/mongodb-constants'; type SearchIndexesTableProps = { namespace: string; @@ -323,7 +323,9 @@ export const SearchIndexesTable: React.FunctionComponent< }, [tabId, onSearchIndexesOpened, onSearchIndexesClosed]); const isViewPipelineSearchQueryable = isReadonlyView && collectionStats?.pipeline - ? isPipelineSearchQueryable(collectionStats.pipeline as Document[]) + ? VIEW_PIPELINE_UTILS.isPipelineSearchQueryable( + collectionStats.pipeline as Document[] + ) : true; const data = useMemo[]>( diff --git a/packages/compass-utils/package.json b/packages/compass-utils/package.json index c4e7f0da8a4..19cc353cf5d 100644 --- a/packages/compass-utils/package.json +++ b/packages/compass-utils/package.json @@ -67,7 +67,6 @@ }, "dependencies": { "@electron/remote": "^2.1.3", - "electron": "^37.2.6", - "mongodb": "^6.18.0" + "electron": "^37.2.6" } } From 434f636f629da98beea6e1608d5453b46d70abac Mon Sep 17 00:00:00 2001 From: Darshana Venkatesh Date: Fri, 22 Aug 2025 00:31:13 -0700 Subject: [PATCH 16/22] update lock file --- package-lock.json | 2 ++ packages/compass-aggregations/package.json | 1 + 2 files changed, 3 insertions(+) diff --git a/package-lock.json b/package-lock.json index 0d7884bcc13..015ed32ad89 100644 --- a/package-lock.json +++ b/package-lock.json @@ -43900,6 +43900,7 @@ "@mongodb-js/compass-generative-ai": "^0.50.0", "@mongodb-js/compass-logging": "^1.7.11", "@mongodb-js/compass-telemetry": "^1.13.0", + "@mongodb-js/compass-utils": "^0.9.10", "@mongodb-js/compass-workspaces": "^0.51.0", "@mongodb-js/explain-plan-helper": "^1.4.17", "@mongodb-js/mongodb-constants": "^0.14.0", @@ -56795,6 +56796,7 @@ "@mongodb-js/compass-generative-ai": "^0.50.0", "@mongodb-js/compass-logging": "^1.7.11", "@mongodb-js/compass-telemetry": "^1.13.0", + "@mongodb-js/compass-utils": "^0.9.10", "@mongodb-js/compass-workspaces": "^0.51.0", "@mongodb-js/eslint-config-compass": "^1.4.6", "@mongodb-js/explain-plan-helper": "^1.4.17", diff --git a/packages/compass-aggregations/package.json b/packages/compass-aggregations/package.json index 498505304e4..30c27a57503 100644 --- a/packages/compass-aggregations/package.json +++ b/packages/compass-aggregations/package.json @@ -69,6 +69,7 @@ "@mongodb-js/compass-generative-ai": "^0.50.0", "@mongodb-js/compass-logging": "^1.7.11", "@mongodb-js/compass-telemetry": "^1.13.0", + "@mongodb-js/compass-utils": "^0.9.10", "@mongodb-js/compass-workspaces": "^0.51.0", "@mongodb-js/explain-plan-helper": "^1.4.17", "@mongodb-js/mongodb-constants": "^0.14.0", From 598efb24b4021b11a48dcd4ad2af34ff1a8a7633 Mon Sep 17 00:00:00 2001 From: Darshana Venkatesh Date: Fri, 22 Aug 2025 00:36:46 -0700 Subject: [PATCH 17/22] fix accidental remove --- package-lock.json | 2 -- packages/compass-aggregations/src/modules/search-indexes.ts | 1 + packages/compass-indexes/package.json | 1 - 3 files changed, 1 insertion(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 015ed32ad89..ffbba33c013 100644 --- a/package-lock.json +++ b/package-lock.json @@ -46819,7 +46819,6 @@ "@mongodb-js/compass-field-store": "^9.45.0", "@mongodb-js/compass-logging": "^1.7.11", "@mongodb-js/compass-telemetry": "^1.13.0", - "@mongodb-js/compass-utils": "^0.9.10", "@mongodb-js/compass-workspaces": "^0.51.0", "@mongodb-js/connection-info": "^0.17.1", "@mongodb-js/mongodb-constants": "^0.14.0", @@ -58895,7 +58894,6 @@ "@mongodb-js/compass-field-store": "^9.45.0", "@mongodb-js/compass-logging": "^1.7.11", "@mongodb-js/compass-telemetry": "^1.13.0", - "@mongodb-js/compass-utils": "^0.9.10", "@mongodb-js/compass-workspaces": "^0.51.0", "@mongodb-js/connection-info": "^0.17.1", "@mongodb-js/eslint-config-compass": "^1.4.6", diff --git a/packages/compass-aggregations/src/modules/search-indexes.ts b/packages/compass-aggregations/src/modules/search-indexes.ts index 97ec575c576..27bc79fa40a 100644 --- a/packages/compass-aggregations/src/modules/search-indexes.ts +++ b/packages/compass-aggregations/src/modules/search-indexes.ts @@ -83,6 +83,7 @@ const reducer: Reducer = (state = INITIAL_STATE, action) => { export const fetchIndexes = (): PipelineBuilderThunkAction> => { return async (dispatch, getState) => { const { + namespace, dataService: { dataService }, searchIndexes: { status }, } = getState(); diff --git a/packages/compass-indexes/package.json b/packages/compass-indexes/package.json index 2cbaf67048f..b82fdea6334 100644 --- a/packages/compass-indexes/package.json +++ b/packages/compass-indexes/package.json @@ -79,7 +79,6 @@ "@mongodb-js/mongodb-constants": "^0.14.0", "@mongodb-js/shell-bson-parser": "^1.2.0", "@mongodb-js/connection-info": "^0.17.1", - "@mongodb-js/compass-utils": "^0.9.10", "bson": "^6.10.4", "compass-preferences-model": "^2.50.0", "lodash": "^4.17.21", From 285d349dc90e01d39c4f56af35e01b8880ce3bf4 Mon Sep 17 00:00:00 2001 From: Darshana Venkatesh Date: Fri, 22 Aug 2025 00:57:09 -0700 Subject: [PATCH 18/22] fix stage.spec.ts --- .../src/utils/stage.spec.ts | 29 ++++++++++++------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/packages/compass-aggregations/src/utils/stage.spec.ts b/packages/compass-aggregations/src/utils/stage.spec.ts index dcca20b6cb4..01e24f18d3b 100644 --- a/packages/compass-aggregations/src/utils/stage.spec.ts +++ b/packages/compass-aggregations/src/utils/stage.spec.ts @@ -66,6 +66,24 @@ describe('utils', function () { expect(searchMeta.length).to.be.equal(1); }); + it('returns $search stage for a view', function () { + const search = filterStageOperators({ + ...filter, + sourceName: 'simple.sample', + }).filter((o) => o.name === '$search'); + + expect(search.length).to.be.equal(1); + }); + + it('returns $searchMeta stage for a view', function () { + const searchMeta = filterStageOperators({ + ...filter, + sourceName: 'simple.sample', + }).filter((o) => o.name === '$searchMeta'); + + expect(searchMeta.length).to.be.equal(1); + }); + // $documents only works for db.aggregate, not coll.aggregate it('does not return $documents stage for a regular collection', function () { const documents = filterStageOperators({ ...filter }).filter( @@ -97,17 +115,6 @@ describe('utils', function () { expect(searchStages.length).to.be.equal(0); }); - - it('does not return full-text search stages for views', function () { - const searchStages = filterStageOperators({ - ...filter, - sourceName: 'simple.sample', - }).filter((o) => - ['$search', '$searchMeta', '$documents'].includes(o.name) - ); - - expect(searchStages.length).to.be.equal(0); - }); }); context('when on-prem', function () { From 784087c684daf6db5c54667e651909d75993acfb Mon Sep 17 00:00:00 2001 From: Darshana Venkatesh Date: Fri, 22 Aug 2025 08:17:41 -0700 Subject: [PATCH 19/22] return false instead of errror --- packages/compass-aggregations/src/modules/search-indexes.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/compass-aggregations/src/modules/search-indexes.ts b/packages/compass-aggregations/src/modules/search-indexes.ts index 27bc79fa40a..3347ce41593 100644 --- a/packages/compass-aggregations/src/modules/search-indexes.ts +++ b/packages/compass-aggregations/src/modules/search-indexes.ts @@ -141,7 +141,7 @@ export const namespaceHasSearchIndexes = async ( const indexes = await dataService.getSearchIndexes(namespace); return indexes.length > 0; } catch { - throw new Error('Error occured fetching indexes'); + return false; } }; From 4c205964a08f847134b21d376f0e560480f61edc Mon Sep 17 00:00:00 2001 From: Darshana Venkatesh Date: Fri, 22 Aug 2025 08:28:38 -0700 Subject: [PATCH 20/22] check 8.0+ --- packages/compass-aggregations/src/modules/update-view.ts | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/packages/compass-aggregations/src/modules/update-view.ts b/packages/compass-aggregations/src/modules/update-view.ts index d25069f162a..d7b60d50c33 100644 --- a/packages/compass-aggregations/src/modules/update-view.ts +++ b/packages/compass-aggregations/src/modules/update-view.ts @@ -101,6 +101,7 @@ export const updateView = (): PipelineBuilderThunkAction> => { const state = getState(); const ds = state.dataService.dataService; const viewNamespace = state.editViewName; + const serverVersion = state.serverVersion; if (!viewNamespace) { return; @@ -113,7 +114,13 @@ export const updateView = (): PipelineBuilderThunkAction> => { pipelineBuilder ); - if (ds && (await namespaceHasSearchIndexes(viewNamespace, ds))) { + if ( + VIEW_PIPELINE_UTILS.isVersionSearchCompatibleForViewsDataExplorer( + serverVersion + ) && + ds && + (await namespaceHasSearchIndexes(viewNamespace, ds)) + ) { const pipelineIsSearchQueryable = VIEW_PIPELINE_UTILS.isPipelineSearchQueryable(viewPipeline); const confirmed = await showConfirmation({ From af2b6507b83e75036031f0e9ce41a99f1db00ac5 Mon Sep 17 00:00:00 2001 From: Darshana Venkatesh Date: Fri, 22 Aug 2025 08:29:57 -0700 Subject: [PATCH 21/22] fix test --- packages/compass-aggregations/src/modules/update-view.spec.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/compass-aggregations/src/modules/update-view.spec.ts b/packages/compass-aggregations/src/modules/update-view.spec.ts index 86ad7a55282..e033d4b2a9e 100644 --- a/packages/compass-aggregations/src/modules/update-view.spec.ts +++ b/packages/compass-aggregations/src/modules/update-view.spec.ts @@ -76,6 +76,7 @@ describe('update-view module', function () { updateCollection: updateCollectionFake, }, }, + serverVersion: '8.1.0', }; getStateMock = () => stateMock; }); From 06f36214187e5beab8acc017abf3946f2236bb1d Mon Sep 17 00:00:00 2001 From: Darshana Venkatesh Date: Fri, 22 Aug 2025 09:17:26 -0700 Subject: [PATCH 22/22] update package-lock --- package-lock.json | 502 ++++++++++++++++++++-------------------------- 1 file changed, 219 insertions(+), 283 deletions(-) diff --git a/package-lock.json b/package-lock.json index ffbba33c013..33189503724 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8598,6 +8598,118 @@ "url": "https://opencollective.com/node-fetch" } }, + "node_modules/@mongodb-js/diagramming": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/@mongodb-js/diagramming/-/diagramming-1.3.5.tgz", + "integrity": "sha512-s4mrOUj10Fpole5V5zUSgj6GqD+CYsxSQuTo3oi2gu8zGR6GHlKrYilIj3mC6mO7UHktyPeHEE8ARmF8aHUcQA==", + "license": "MIT", + "dependencies": { + "@emotion/react": "^11.14.0", + "@emotion/styled": "^11.14.0", + "@leafygreen-ui/icon": "^13.2.0", + "@leafygreen-ui/leafygreen-provider": "^5.0.0", + "@leafygreen-ui/palette": "^5.0.0", + "@leafygreen-ui/tokens": "^3.0.0", + "@leafygreen-ui/typography": "^20.1.4", + "@xyflow/react": "12.5.1", + "d3-path": "^3.1.0", + "elkjs": "^0.10.0", + "react": "17.0.2", + "react-dom": "17.0.2" + } + }, + "node_modules/@mongodb-js/diagramming/node_modules/@leafygreen-ui/emotion": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@leafygreen-ui/emotion/-/emotion-5.0.0.tgz", + "integrity": "sha512-MOfouBCmHuFa6UObhUl03CUFqXvD2PP+nI7CLk0ny8/UKOLgAX4N+JuuSX606u+Efxk4lI2m3FZiyCrfi6oeFQ==", + "license": "Apache-2.0", + "dependencies": { + "@emotion/css": "^11.1.3", + "@emotion/server": "^11.4.0" + } + }, + "node_modules/@mongodb-js/diagramming/node_modules/@leafygreen-ui/hooks": { + "version": "9.1.1", + "resolved": "https://registry.npmjs.org/@leafygreen-ui/hooks/-/hooks-9.1.1.tgz", + "integrity": "sha512-WVAu5NgFo5eALb7Z2E8v2mEaUtiGXsOrOGX8fLHSU75Xs343SGWllwxqqGnhf+bbUNlSXBAbprHAD3/Yn4QcyQ==", + "license": "Apache-2.0", + "dependencies": { + "@leafygreen-ui/lib": "^15.2.0", + "@leafygreen-ui/tokens": "^3.1.2", + "lodash": "^4.17.21" + } + }, + "node_modules/@mongodb-js/diagramming/node_modules/@leafygreen-ui/leafygreen-provider": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@leafygreen-ui/leafygreen-provider/-/leafygreen-provider-5.0.2.tgz", + "integrity": "sha512-mLD7ziluM0ZoTlzoauu6AeA3vGVlf9JilUjmWZEcZeRfzJcIyF48PoL7Mj23AqY1k1PNcJHhlK9ALpIzpI33ug==", + "license": "Apache-2.0", + "dependencies": { + "@leafygreen-ui/hooks": "^9.1.1", + "@leafygreen-ui/lib": "^15.2.0", + "react-transition-group": "^4.4.5" + } + }, + "node_modules/@mongodb-js/diagramming/node_modules/@leafygreen-ui/lib": { + "version": "15.2.0", + "resolved": "https://registry.npmjs.org/@leafygreen-ui/lib/-/lib-15.2.0.tgz", + "integrity": "sha512-wrVJGaqACcYWE/xPHHJREpRvkoy4Biwim1SUuq0hs/lXf6cEMg7MD9x2fUDJ9v6tQmLiFuwRXbJiXrvVXkz4Lg==", + "license": "Apache-2.0", + "dependencies": { + "lodash": "^4.17.21" + }, + "peerDependencies": { + "react": "^17.0.0 || ^18.0.0" + } + }, + "node_modules/@mongodb-js/diagramming/node_modules/@leafygreen-ui/palette": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@leafygreen-ui/palette/-/palette-5.0.0.tgz", + "integrity": "sha512-RHQy165X7lKMlNU+2BkvGCNuo8fP3bS5NVOJ6thSKingoksYrz1a6SNAzuHDIkww+njf0GaKiXYT64og2Xm4Fw==", + "license": "Apache-2.0" + }, + "node_modules/@mongodb-js/diagramming/node_modules/@leafygreen-ui/tokens": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/@leafygreen-ui/tokens/-/tokens-3.2.1.tgz", + "integrity": "sha512-FJwgN9zRFa/1Lrw3teuBdTF+Fi/IAdpaNuUUEiVIissHK4Py8Dsc6HJhWKBOocBj5dEw78cRDgnqSVFvU6EjMg==", + "license": "Apache-2.0", + "dependencies": { + "@leafygreen-ui/emotion": "^5.0.0", + "@leafygreen-ui/lib": "^15.2.0", + "@leafygreen-ui/palette": "^5.0.0", + "polished": "^4.2.2" + } + }, + "node_modules/@mongodb-js/diagramming/node_modules/@xyflow/react": { + "version": "12.5.1", + "resolved": "https://registry.npmjs.org/@xyflow/react/-/react-12.5.1.tgz", + "integrity": "sha512-jMKQVqGwCz0x6pUyvxTIuCMbyehfua7CfEEWDj29zQSHigQpCy0/5d8aOmZrqK4cwur/pVHLQomT6Rm10gXfHg==", + "license": "MIT", + "dependencies": { + "@xyflow/system": "0.0.53", + "classcat": "^5.0.3", + "zustand": "^4.4.0" + }, + "peerDependencies": { + "react": ">=17", + "react-dom": ">=17" + } + }, + "node_modules/@mongodb-js/diagramming/node_modules/@xyflow/system": { + "version": "0.0.53", + "resolved": "https://registry.npmjs.org/@xyflow/system/-/system-0.0.53.tgz", + "integrity": "sha512-QTWieiTtvNYyQAz1fxpzgtUGXNpnhfh6vvZa7dFWpWS2KOz6bEHODo/DTK3s07lDu0Bq0Db5lx/5M5mNjb9VDQ==", + "license": "MIT", + "dependencies": { + "@types/d3-drag": "^3.0.7", + "@types/d3-selection": "^3.0.10", + "@types/d3-transition": "^3.0.8", + "@types/d3-zoom": "^3.0.8", + "d3-drag": "^3.0.0", + "d3-selection": "^3.0.0", + "d3-zoom": "^3.0.0" + } + }, "node_modules/@mongodb-js/dl-center": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/@mongodb-js/dl-center/-/dl-center-1.3.0.tgz", @@ -15510,38 +15622,6 @@ "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==" }, - "node_modules/@xyflow/react": { - "version": "12.8.1", - "resolved": "https://registry.npmjs.org/@xyflow/react/-/react-12.8.1.tgz", - "integrity": "sha512-t5Rame4Gc/540VcOZd28yFe9Xd8lyjKUX+VTiyb1x4ykNXZH5zyDmsu+lj9je2O/jGBVb0pj1Vjcxrxyn+Xk2g==", - "license": "MIT", - "dependencies": { - "@xyflow/system": "0.0.65", - "classcat": "^5.0.3", - "zustand": "^4.4.0" - }, - "peerDependencies": { - "react": ">=17", - "react-dom": ">=17" - } - }, - "node_modules/@xyflow/system": { - "version": "0.0.65", - "resolved": "https://registry.npmjs.org/@xyflow/system/-/system-0.0.65.tgz", - "integrity": "sha512-AliQPQeurQMoNlOdySnRoDQl9yDSA/1Lqi47Eo0m98lHcfrTdD9jK75H0tiGj+0qRC10SKNUXyMkT0KL0opg4g==", - "license": "MIT", - "dependencies": { - "@types/d3-drag": "^3.0.7", - "@types/d3-interpolate": "^3.0.4", - "@types/d3-selection": "^3.0.10", - "@types/d3-transition": "^3.0.8", - "@types/d3-zoom": "^3.0.8", - "d3-drag": "^3.0.0", - "d3-interpolate": "^3.0.1", - "d3-selection": "^3.0.0", - "d3-zoom": "^3.0.0" - } - }, "node_modules/@yarnpkg/lockfile": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@yarnpkg/lockfile/-/lockfile-1.1.0.tgz", @@ -18435,25 +18515,17 @@ } }, "node_modules/cli-progress": { - "version": "3.9.1", - "resolved": "https://registry.npmjs.org/cli-progress/-/cli-progress-3.9.1.tgz", - "integrity": "sha512-AXxiCe2a0Lm0VN+9L0jzmfQSkcZm5EYspfqXKaSIQKqIk+0hnkZ3/v1E9B39mkD6vYhKih3c/RPsJBSwq9O99Q==", + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/cli-progress/-/cli-progress-3.12.0.tgz", + "integrity": "sha512-tRkV3HJ1ASwm19THiiLIXLO7Im7wlTuKnvkYaTkyoAPefqjNg7W7DHKUlGRxy9vxDvbyCYQkQozvptuMkGCg8A==", + "license": "MIT", "dependencies": { - "colors": "^1.1.2", - "string-width": "^4.2.0" + "string-width": "^4.2.3" }, "engines": { "node": ">=4" } }, - "node_modules/cli-progress/node_modules/colors": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", - "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==", - "engines": { - "node": ">=0.1.90" - } - }, "node_modules/cli-spinners": { "version": "2.6.1", "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.6.1.tgz", @@ -45337,112 +45409,6 @@ "xvfb-maybe": "^0.2.1" } }, - "packages/compass-data-modeling/node_modules/@leafygreen-ui/emotion": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/@leafygreen-ui/emotion/-/emotion-5.0.0.tgz", - "integrity": "sha512-MOfouBCmHuFa6UObhUl03CUFqXvD2PP+nI7CLk0ny8/UKOLgAX4N+JuuSX606u+Efxk4lI2m3FZiyCrfi6oeFQ==", - "license": "Apache-2.0", - "dependencies": { - "@emotion/css": "^11.1.3", - "@emotion/server": "^11.4.0" - } - }, - "packages/compass-data-modeling/node_modules/@leafygreen-ui/hooks": { - "version": "9.1.1", - "resolved": "https://registry.npmjs.org/@leafygreen-ui/hooks/-/hooks-9.1.1.tgz", - "integrity": "sha512-WVAu5NgFo5eALb7Z2E8v2mEaUtiGXsOrOGX8fLHSU75Xs343SGWllwxqqGnhf+bbUNlSXBAbprHAD3/Yn4QcyQ==", - "license": "Apache-2.0", - "dependencies": { - "@leafygreen-ui/lib": "^15.2.0", - "@leafygreen-ui/tokens": "^3.1.2", - "lodash": "^4.17.21" - } - }, - "packages/compass-data-modeling/node_modules/@leafygreen-ui/hooks/node_modules/@leafygreen-ui/lib": { - "version": "15.2.0", - "resolved": "https://registry.npmjs.org/@leafygreen-ui/lib/-/lib-15.2.0.tgz", - "integrity": "sha512-wrVJGaqACcYWE/xPHHJREpRvkoy4Biwim1SUuq0hs/lXf6cEMg7MD9x2fUDJ9v6tQmLiFuwRXbJiXrvVXkz4Lg==", - "license": "Apache-2.0", - "dependencies": { - "lodash": "^4.17.21" - }, - "peerDependencies": { - "react": "^17.0.0 || ^18.0.0" - } - }, - "packages/compass-data-modeling/node_modules/@leafygreen-ui/leafygreen-provider": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/@leafygreen-ui/leafygreen-provider/-/leafygreen-provider-5.0.2.tgz", - "integrity": "sha512-mLD7ziluM0ZoTlzoauu6AeA3vGVlf9JilUjmWZEcZeRfzJcIyF48PoL7Mj23AqY1k1PNcJHhlK9ALpIzpI33ug==", - "license": "Apache-2.0", - "dependencies": { - "@leafygreen-ui/hooks": "^9.1.1", - "@leafygreen-ui/lib": "^15.2.0", - "react-transition-group": "^4.4.5" - } - }, - "packages/compass-data-modeling/node_modules/@leafygreen-ui/leafygreen-provider/node_modules/@leafygreen-ui/lib": { - "version": "15.2.0", - "resolved": "https://registry.npmjs.org/@leafygreen-ui/lib/-/lib-15.2.0.tgz", - "integrity": "sha512-wrVJGaqACcYWE/xPHHJREpRvkoy4Biwim1SUuq0hs/lXf6cEMg7MD9x2fUDJ9v6tQmLiFuwRXbJiXrvVXkz4Lg==", - "license": "Apache-2.0", - "dependencies": { - "lodash": "^4.17.21" - }, - "peerDependencies": { - "react": "^17.0.0 || ^18.0.0" - } - }, - "packages/compass-data-modeling/node_modules/@leafygreen-ui/palette": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/@leafygreen-ui/palette/-/palette-5.0.0.tgz", - "integrity": "sha512-RHQy165X7lKMlNU+2BkvGCNuo8fP3bS5NVOJ6thSKingoksYrz1a6SNAzuHDIkww+njf0GaKiXYT64og2Xm4Fw==", - "license": "Apache-2.0" - }, - "packages/compass-data-modeling/node_modules/@leafygreen-ui/tokens": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/@leafygreen-ui/tokens/-/tokens-3.2.1.tgz", - "integrity": "sha512-FJwgN9zRFa/1Lrw3teuBdTF+Fi/IAdpaNuUUEiVIissHK4Py8Dsc6HJhWKBOocBj5dEw78cRDgnqSVFvU6EjMg==", - "license": "Apache-2.0", - "dependencies": { - "@leafygreen-ui/emotion": "^5.0.0", - "@leafygreen-ui/lib": "^15.2.0", - "@leafygreen-ui/palette": "^5.0.0", - "polished": "^4.2.2" - } - }, - "packages/compass-data-modeling/node_modules/@leafygreen-ui/tokens/node_modules/@leafygreen-ui/lib": { - "version": "15.2.0", - "resolved": "https://registry.npmjs.org/@leafygreen-ui/lib/-/lib-15.2.0.tgz", - "integrity": "sha512-wrVJGaqACcYWE/xPHHJREpRvkoy4Biwim1SUuq0hs/lXf6cEMg7MD9x2fUDJ9v6tQmLiFuwRXbJiXrvVXkz4Lg==", - "license": "Apache-2.0", - "dependencies": { - "lodash": "^4.17.21" - }, - "peerDependencies": { - "react": "^17.0.0 || ^18.0.0" - } - }, - "packages/compass-data-modeling/node_modules/@mongodb-js/diagramming": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/@mongodb-js/diagramming/-/diagramming-1.3.3.tgz", - "integrity": "sha512-wE5MXYgLPDdB9MQnPuggCP8A4sHKR0goRSiFxR7yQyaUT1VSuugKv/PObF6CarOpAq9+WYyl1I1vU9ea4D5Tng==", - "license": "MIT", - "dependencies": { - "@emotion/react": "^11.14.0", - "@emotion/styled": "^11.14.0", - "@leafygreen-ui/icon": "^13.2.0", - "@leafygreen-ui/leafygreen-provider": "^5.0.0", - "@leafygreen-ui/palette": "^5.0.0", - "@leafygreen-ui/tokens": "^3.0.0", - "@leafygreen-ui/typography": "^20.1.4", - "@xyflow/react": "^12.5.1", - "d3-path": "^3.1.0", - "elkjs": "^0.10.0", - "react": "17.0.2", - "react-dom": "17.0.2" - } - }, "packages/compass-data-modeling/node_modules/@sinonjs/commons": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.1.tgz", @@ -57992,100 +57958,6 @@ "xvfb-maybe": "^0.2.1" }, "dependencies": { - "@leafygreen-ui/emotion": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/@leafygreen-ui/emotion/-/emotion-5.0.0.tgz", - "integrity": "sha512-MOfouBCmHuFa6UObhUl03CUFqXvD2PP+nI7CLk0ny8/UKOLgAX4N+JuuSX606u+Efxk4lI2m3FZiyCrfi6oeFQ==", - "requires": { - "@emotion/css": "^11.1.3", - "@emotion/server": "^11.4.0" - } - }, - "@leafygreen-ui/hooks": { - "version": "9.1.1", - "resolved": "https://registry.npmjs.org/@leafygreen-ui/hooks/-/hooks-9.1.1.tgz", - "integrity": "sha512-WVAu5NgFo5eALb7Z2E8v2mEaUtiGXsOrOGX8fLHSU75Xs343SGWllwxqqGnhf+bbUNlSXBAbprHAD3/Yn4QcyQ==", - "requires": { - "@leafygreen-ui/lib": "^15.2.0", - "@leafygreen-ui/tokens": "^3.1.2", - "lodash": "^4.17.21" - }, - "dependencies": { - "@leafygreen-ui/lib": { - "version": "15.2.0", - "resolved": "https://registry.npmjs.org/@leafygreen-ui/lib/-/lib-15.2.0.tgz", - "integrity": "sha512-wrVJGaqACcYWE/xPHHJREpRvkoy4Biwim1SUuq0hs/lXf6cEMg7MD9x2fUDJ9v6tQmLiFuwRXbJiXrvVXkz4Lg==", - "requires": { - "lodash": "^4.17.21" - } - } - } - }, - "@leafygreen-ui/leafygreen-provider": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/@leafygreen-ui/leafygreen-provider/-/leafygreen-provider-5.0.2.tgz", - "integrity": "sha512-mLD7ziluM0ZoTlzoauu6AeA3vGVlf9JilUjmWZEcZeRfzJcIyF48PoL7Mj23AqY1k1PNcJHhlK9ALpIzpI33ug==", - "requires": { - "@leafygreen-ui/hooks": "^9.1.1", - "@leafygreen-ui/lib": "^15.2.0", - "react-transition-group": "^4.4.5" - }, - "dependencies": { - "@leafygreen-ui/lib": { - "version": "15.2.0", - "resolved": "https://registry.npmjs.org/@leafygreen-ui/lib/-/lib-15.2.0.tgz", - "integrity": "sha512-wrVJGaqACcYWE/xPHHJREpRvkoy4Biwim1SUuq0hs/lXf6cEMg7MD9x2fUDJ9v6tQmLiFuwRXbJiXrvVXkz4Lg==", - "requires": { - "lodash": "^4.17.21" - } - } - } - }, - "@leafygreen-ui/palette": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/@leafygreen-ui/palette/-/palette-5.0.0.tgz", - "integrity": "sha512-RHQy165X7lKMlNU+2BkvGCNuo8fP3bS5NVOJ6thSKingoksYrz1a6SNAzuHDIkww+njf0GaKiXYT64og2Xm4Fw==" - }, - "@leafygreen-ui/tokens": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/@leafygreen-ui/tokens/-/tokens-3.2.1.tgz", - "integrity": "sha512-FJwgN9zRFa/1Lrw3teuBdTF+Fi/IAdpaNuUUEiVIissHK4Py8Dsc6HJhWKBOocBj5dEw78cRDgnqSVFvU6EjMg==", - "requires": { - "@leafygreen-ui/emotion": "^5.0.0", - "@leafygreen-ui/lib": "^15.2.0", - "@leafygreen-ui/palette": "^5.0.0", - "polished": "^4.2.2" - }, - "dependencies": { - "@leafygreen-ui/lib": { - "version": "15.2.0", - "resolved": "https://registry.npmjs.org/@leafygreen-ui/lib/-/lib-15.2.0.tgz", - "integrity": "sha512-wrVJGaqACcYWE/xPHHJREpRvkoy4Biwim1SUuq0hs/lXf6cEMg7MD9x2fUDJ9v6tQmLiFuwRXbJiXrvVXkz4Lg==", - "requires": { - "lodash": "^4.17.21" - } - } - } - }, - "@mongodb-js/diagramming": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/@mongodb-js/diagramming/-/diagramming-1.3.3.tgz", - "integrity": "sha512-wE5MXYgLPDdB9MQnPuggCP8A4sHKR0goRSiFxR7yQyaUT1VSuugKv/PObF6CarOpAq9+WYyl1I1vU9ea4D5Tng==", - "requires": { - "@emotion/react": "^11.14.0", - "@emotion/styled": "^11.14.0", - "@leafygreen-ui/icon": "^13.2.0", - "@leafygreen-ui/leafygreen-provider": "^5.0.0", - "@leafygreen-ui/palette": "^5.0.0", - "@leafygreen-ui/tokens": "^3.0.0", - "@leafygreen-ui/typography": "^20.1.4", - "@xyflow/react": "^12.5.1", - "d3-path": "^3.1.0", - "elkjs": "^0.10.0", - "react": "17.0.2", - "react-dom": "17.0.2" - } - }, "@sinonjs/commons": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.1.tgz", @@ -61022,6 +60894,104 @@ } } }, + "@mongodb-js/diagramming": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/@mongodb-js/diagramming/-/diagramming-1.3.5.tgz", + "integrity": "sha512-s4mrOUj10Fpole5V5zUSgj6GqD+CYsxSQuTo3oi2gu8zGR6GHlKrYilIj3mC6mO7UHktyPeHEE8ARmF8aHUcQA==", + "requires": { + "@emotion/react": "^11.14.0", + "@emotion/styled": "^11.14.0", + "@leafygreen-ui/icon": "^13.2.0", + "@leafygreen-ui/leafygreen-provider": "^5.0.0", + "@leafygreen-ui/palette": "^5.0.0", + "@leafygreen-ui/tokens": "^3.0.0", + "@leafygreen-ui/typography": "^20.1.4", + "@xyflow/react": "12.5.1", + "d3-path": "^3.1.0", + "elkjs": "^0.10.0", + "react": "^17.0.2", + "react-dom": "^17.0.2" + }, + "dependencies": { + "@leafygreen-ui/emotion": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@leafygreen-ui/emotion/-/emotion-5.0.0.tgz", + "integrity": "sha512-MOfouBCmHuFa6UObhUl03CUFqXvD2PP+nI7CLk0ny8/UKOLgAX4N+JuuSX606u+Efxk4lI2m3FZiyCrfi6oeFQ==", + "requires": { + "@emotion/css": "^11.1.3", + "@emotion/server": "^11.4.0" + } + }, + "@leafygreen-ui/hooks": { + "version": "9.1.1", + "resolved": "https://registry.npmjs.org/@leafygreen-ui/hooks/-/hooks-9.1.1.tgz", + "integrity": "sha512-WVAu5NgFo5eALb7Z2E8v2mEaUtiGXsOrOGX8fLHSU75Xs343SGWllwxqqGnhf+bbUNlSXBAbprHAD3/Yn4QcyQ==", + "requires": { + "@leafygreen-ui/lib": "^15.2.0", + "@leafygreen-ui/tokens": "^3.1.2", + "lodash": "^4.17.21" + } + }, + "@leafygreen-ui/leafygreen-provider": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@leafygreen-ui/leafygreen-provider/-/leafygreen-provider-5.0.2.tgz", + "integrity": "sha512-mLD7ziluM0ZoTlzoauu6AeA3vGVlf9JilUjmWZEcZeRfzJcIyF48PoL7Mj23AqY1k1PNcJHhlK9ALpIzpI33ug==", + "requires": { + "@leafygreen-ui/hooks": "^9.1.1", + "@leafygreen-ui/lib": "^15.2.0", + "react-transition-group": "^4.4.5" + } + }, + "@leafygreen-ui/lib": { + "version": "15.2.0", + "resolved": "https://registry.npmjs.org/@leafygreen-ui/lib/-/lib-15.2.0.tgz", + "integrity": "sha512-wrVJGaqACcYWE/xPHHJREpRvkoy4Biwim1SUuq0hs/lXf6cEMg7MD9x2fUDJ9v6tQmLiFuwRXbJiXrvVXkz4Lg==", + "requires": { + "lodash": "^4.17.21" + } + }, + "@leafygreen-ui/palette": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@leafygreen-ui/palette/-/palette-5.0.0.tgz", + "integrity": "sha512-RHQy165X7lKMlNU+2BkvGCNuo8fP3bS5NVOJ6thSKingoksYrz1a6SNAzuHDIkww+njf0GaKiXYT64og2Xm4Fw==" + }, + "@leafygreen-ui/tokens": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/@leafygreen-ui/tokens/-/tokens-3.2.1.tgz", + "integrity": "sha512-FJwgN9zRFa/1Lrw3teuBdTF+Fi/IAdpaNuUUEiVIissHK4Py8Dsc6HJhWKBOocBj5dEw78cRDgnqSVFvU6EjMg==", + "requires": { + "@leafygreen-ui/emotion": "^5.0.0", + "@leafygreen-ui/lib": "^15.2.0", + "@leafygreen-ui/palette": "^5.0.0", + "polished": "^4.2.2" + } + }, + "@xyflow/react": { + "version": "12.5.1", + "resolved": "https://registry.npmjs.org/@xyflow/react/-/react-12.5.1.tgz", + "integrity": "sha512-jMKQVqGwCz0x6pUyvxTIuCMbyehfua7CfEEWDj29zQSHigQpCy0/5d8aOmZrqK4cwur/pVHLQomT6Rm10gXfHg==", + "requires": { + "@xyflow/system": "0.0.53", + "classcat": "^5.0.3", + "zustand": "^4.4.0" + } + }, + "@xyflow/system": { + "version": "0.0.53", + "resolved": "https://registry.npmjs.org/@xyflow/system/-/system-0.0.53.tgz", + "integrity": "sha512-QTWieiTtvNYyQAz1fxpzgtUGXNpnhfh6vvZa7dFWpWS2KOz6bEHODo/DTK3s07lDu0Bq0Db5lx/5M5mNjb9VDQ==", + "requires": { + "@types/d3-drag": "^3.0.7", + "@types/d3-selection": "^3.0.10", + "@types/d3-transition": "^3.0.8", + "@types/d3-zoom": "^3.0.8", + "d3-drag": "^3.0.0", + "d3-selection": "^3.0.0", + "d3-zoom": "^3.0.0" + } + } + } + }, "@mongodb-js/dl-center": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/@mongodb-js/dl-center/-/dl-center-1.3.0.tgz", @@ -67059,32 +67029,6 @@ "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==" }, - "@xyflow/react": { - "version": "12.8.1", - "resolved": "https://registry.npmjs.org/@xyflow/react/-/react-12.8.1.tgz", - "integrity": "sha512-t5Rame4Gc/540VcOZd28yFe9Xd8lyjKUX+VTiyb1x4ykNXZH5zyDmsu+lj9je2O/jGBVb0pj1Vjcxrxyn+Xk2g==", - "requires": { - "@xyflow/system": "0.0.65", - "classcat": "^5.0.3", - "zustand": "^4.4.0" - } - }, - "@xyflow/system": { - "version": "0.0.65", - "resolved": "https://registry.npmjs.org/@xyflow/system/-/system-0.0.65.tgz", - "integrity": "sha512-AliQPQeurQMoNlOdySnRoDQl9yDSA/1Lqi47Eo0m98lHcfrTdD9jK75H0tiGj+0qRC10SKNUXyMkT0KL0opg4g==", - "requires": { - "@types/d3-drag": "^3.0.7", - "@types/d3-interpolate": "^3.0.4", - "@types/d3-selection": "^3.0.10", - "@types/d3-transition": "^3.0.8", - "@types/d3-zoom": "^3.0.8", - "d3-drag": "^3.0.0", - "d3-interpolate": "^3.0.1", - "d3-selection": "^3.0.0", - "d3-zoom": "^3.0.0" - } - }, "@yarnpkg/lockfile": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@yarnpkg/lockfile/-/lockfile-1.1.0.tgz", @@ -69310,19 +69254,11 @@ } }, "cli-progress": { - "version": "3.9.1", - "resolved": "https://registry.npmjs.org/cli-progress/-/cli-progress-3.9.1.tgz", - "integrity": "sha512-AXxiCe2a0Lm0VN+9L0jzmfQSkcZm5EYspfqXKaSIQKqIk+0hnkZ3/v1E9B39mkD6vYhKih3c/RPsJBSwq9O99Q==", + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/cli-progress/-/cli-progress-3.12.0.tgz", + "integrity": "sha512-tRkV3HJ1ASwm19THiiLIXLO7Im7wlTuKnvkYaTkyoAPefqjNg7W7DHKUlGRxy9vxDvbyCYQkQozvptuMkGCg8A==", "requires": { - "colors": "^1.1.2", - "string-width": "^4.2.0" - }, - "dependencies": { - "colors": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", - "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==" - } + "string-width": "^4.2.3" } }, "cli-spinners": {