diff --git a/package-lock.json b/package-lock.json index 4952ea15b13..8f51518f9fc 100644 --- a/package-lock.json +++ b/package-lock.json @@ -45142,7 +45142,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", @@ -45186,12 +45186,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": { @@ -45607,7 +45610,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", "bson": "^6.10.1", "compass-preferences-model": "^2.50.0", "hadron-document": "^8.9.5", @@ -45644,12 +45647,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": { @@ -47139,7 +47145,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", @@ -47164,12 +47170,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": { @@ -47949,7 +47958,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", "@mongodb-js/shell-bson-parser": "^1.2.0", "bson": "^6.10.4", "compass-preferences-model": "^2.50.0", @@ -47987,12 +47996,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": { @@ -48404,7 +48416,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", @@ -48439,12 +48451,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": { @@ -48663,7 +48678,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", @@ -48697,12 +48712,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": { @@ -48942,7 +48960,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", @@ -48978,12 +48996,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": { @@ -58147,7 +58168,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", @@ -58187,9 +58208,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" } @@ -58516,7 +58537,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", @@ -58549,9 +58570,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" } @@ -59519,7 +59540,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", @@ -59540,9 +59561,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" } @@ -60155,7 +60176,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", @@ -60189,9 +60210,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" } @@ -60460,7 +60481,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", @@ -60491,9 +60512,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" } @@ -60705,7 +60726,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", @@ -60735,9 +60756,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" } @@ -61082,7 +61103,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", @@ -61114,9 +61135,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 c29a03c3fde..3347ce41593 100644 --- a/packages/compass-aggregations/src/modules/search-indexes.ts +++ b/packages/compass-aggregations/src/modules/search-indexes.ts @@ -123,4 +123,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 { + return false; + } +}; + 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 4e0c6603d4f..e033d4b2a9e 100644 --- a/packages/compass-aggregations/src/modules/update-view.spec.ts +++ b/packages/compass-aggregations/src/modules/update-view.spec.ts @@ -10,6 +10,10 @@ 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'; +import * as searchIndexesSlice from './search-indexes'; + const TEST_CONNECTION_INFO = { ...createDefaultConnectionInfo(), title: '' }; describe('update-view module', function () { @@ -48,10 +52,20 @@ describe('update-view module', function () { let stateMock: any; let getStateMock: () => any; let updateCollectionFake = sinon.fake(); + let showConfirmationStub: sinon.SinonStub; + let namespaceHasSearchIndexesStub: sinon.SinonStub; - beforeEach(async function () { + beforeEach(function () { dispatchFake = sinon.fake(); updateCollectionFake = sinon.fake.resolves(undefined); + showConfirmationStub = sinon + .stub(updateViewSlice, 'showConfirmation') + .resolves(true); + + namespaceHasSearchIndexesStub = sinon + .stub(searchIndexesSlice, 'namespaceHasSearchIndexes') + .resolves(true); + stateMock = { pipelineBuilder: { pipelineMode: 'builder-ui' }, focusMode: { isEnabled: false }, @@ -62,20 +76,57 @@ describe('update-view module', function () { updateCollection: updateCollectionFake, }, }, + serverVersion: '8.1.0', }; getStateMock = () => stateMock; + }); + afterEach(function () { + showConfirmationStub.restore(); + namespaceHasSearchIndexesStub.restore(); + }); + + it('first it calls to dismiss any existing error', async function () { const runUpdateView = updateView(); await runUpdateView(dispatchFake, getStateMock, thunkArg as any); - }); - 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('calls the data service to update the view for the provided ns', function () { + it('does not shows confirmation banner if search indexes are not present', async function () { + namespaceHasSearchIndexesStub.resolves(false); + 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); + + 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 () { + 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', 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', diff --git a/packages/compass-aggregations/src/modules/update-view.ts b/packages/compass-aggregations/src/modules/update-view.ts index 87ce2838964..d7b60d50c33 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 as showConfirmationModal } from '@mongodb-js/compass-components'; +import { namespaceHasSearchIndexes } from './search-indexes'; +import { VIEW_PIPELINE_UTILS } from '@mongodb-js/mongodb-constants'; export type UpdateViewState = null | string; @@ -73,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. * @@ -96,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; @@ -107,6 +113,30 @@ export const updateView = (): PipelineBuilderThunkAction> => { getState(), pipelineBuilder ); + + if ( + VIEW_PIPELINE_UTILS.isVersionSearchCompatibleForViewsDataExplorer( + serverVersion + ) && + ds && + (await namespaceHasSearchIndexes(viewNamespace, ds)) + ) { + const pipelineIsSearchQueryable = + VIEW_PIPELINE_UTILS.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-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 () { diff --git a/packages/compass-collection/package.json b/packages/compass-collection/package.json index b520c0c15e1..7300c904a77 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 ed0a5cfb671..b82fdea6334 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", "bson": "^6.10.4", 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..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 @@ -13,6 +13,7 @@ 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'; describe('IndexesToolbar Component', function () { before(cleanup); @@ -39,6 +40,7 @@ describe('IndexesToolbar Component', function () { onRefreshIndexes={() => {}} isSearchIndexesSupported={false} isRefreshing={false} + collectionStats={{ index_count: 0, index_size: 0, pipeline: [] }} onIndexViewChanged={() => {}} onCreateRegularIndexClick={() => {}} onCreateSearchIndexClick={() => {}} @@ -153,10 +155,38 @@ 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 = { + index_count: 0, + index_size: 0, + 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 973dc517641..cb522741e3e 100644 --- a/packages/compass-indexes/src/components/indexes-toolbar/indexes-toolbar.tsx +++ b/packages/compass-indexes/src/components/indexes-toolbar/indexes-toolbar.tsx @@ -23,14 +23,14 @@ 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'; import { indexViewChanged } from '../../modules/index-view'; +import type { CollectionStats } from '../../modules/collection-stats'; +import type { Document } from 'mongodb'; +import { VIEW_PIPELINE_UTILS } from '@mongodb-js/mongodb-constants'; const toolbarButtonsContainer = css({ display: 'flex', @@ -88,6 +88,7 @@ type IndexesToolbarProps = { isSearchIndexesSupported: boolean; // via withPreferences: readOnly?: boolean; + collectionStats: CollectionStats; }; export const IndexesToolbar: React.FunctionComponent = ({ @@ -107,12 +108,16 @@ export const IndexesToolbar: React.FunctionComponent = ({ onIndexViewChanged, serverVersion, readOnly, // preferences readOnly. + collectionStats, }) => { const isSearchManagementActive = usePreference('enableAtlasSearchIndexes'); const { atlasMetadata } = useConnectionInfo(); const showInsights = usePreference('showInsights') && !errorMessage; const showCreateIndexButton = - (!isReadonlyView || isVersionSearchCompatibleForViews(serverVersion)) && + (!isReadonlyView || + VIEW_PIPELINE_UTILS.isVersionSearchCompatibleForViewsCompass( + serverVersion + )) && !readOnly && !errorMessage; const refreshButtonIcon = isRefreshing ? ( @@ -122,20 +127,29 @@ export const IndexesToolbar: React.FunctionComponent = ({ ) : ( ); - + const isViewPipelineSearchQueryable = + isReadonlyView && collectionStats?.pipeline + ? 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.'; return (
{(!isReadonlyView || - (isVersionSearchCompatibleForViews(serverVersion) && + (VIEW_PIPELINE_UTILS.isVersionSearchCompatibleForViewsCompass( + serverVersion + ) && isSearchManagementActive)) && (
{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, @@ -290,6 +308,7 @@ export const SearchIndexesTable: React.FunctionComponent< onDropIndexClick, onSearchIndexesOpened, onSearchIndexesClosed, + isReadonlyView, }) => { const { openCollectionWorkspace } = useOpenWorkspace(); const { id: connectionId } = useConnectionInfo(); @@ -302,6 +321,12 @@ export const SearchIndexesTable: React.FunctionComponent< onSearchIndexesClosed(tabId); }; }, [tabId, onSearchIndexesOpened, onSearchIndexesClosed]); + const isViewPipelineSearchQueryable = + isReadonlyView && collectionStats?.pipeline + ? VIEW_PIPELINE_UTILS.isPipelineSearchQueryable( + collectionStats.pipeline as Document[] + ) + : true; const data = useMemo[]>( () => @@ -384,7 +409,12 @@ export const SearchIndexesTable: React.FunctionComponent< } if (indexes.length === 0) { - return ; + return ( + + ); } const canModifyIndex = isWritable && !readOnly; @@ -399,9 +429,17 @@ export const SearchIndexesTable: React.FunctionComponent< ); }; -const mapState = ({ searchIndexes, isWritable, namespace }: RootState) => ({ +const mapState = ({ + searchIndexes, + isWritable, + namespace, + collectionStats, + isReadonlyView, +}: RootState) => ({ namespace, isWritable, + collectionStats, + isReadonlyView, indexes: searchIndexes.indexes, status: searchIndexes.status, }); 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..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,11 +42,16 @@ 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 ( - + Looking for search indexes?
diff --git a/packages/compass-indexes/src/modules/collection-stats.ts b/packages/compass-indexes/src/modules/collection-stats.ts index e867e452b4e..dd2d8593b29 100644 --- a/packages/compass-indexes/src/modules/collection-stats.ts +++ b/packages/compass-indexes/src/modules/collection-stats.ts @@ -11,16 +11,17 @@ function isAction( export function extractCollectionStats( collection: Collection ): CollectionStats { - const { index_count, index_size } = collection.toJSON(); + const { index_count, index_size, pipeline } = collection.toJSON(); return { index_count, index_size, + pipeline, }; } export type CollectionStats = Pick< Collection, - 'index_count' | 'index_size' + 'index_count' | 'index_size' | 'pipeline' > | null; enum StatsActions { 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",