diff --git a/package-lock.json b/package-lock.json index ac6107d4a14..61fa6d16259 100644 --- a/package-lock.json +++ b/package-lock.json @@ -46620,6 +46620,7 @@ "@mongodb-js/compass-field-store": "^9.25.2", "@mongodb-js/compass-logging": "^1.6.2", "@mongodb-js/compass-telemetry": "^1.4.2", + "@mongodb-js/compass-workspaces": "^0.31.2", "bson": "^6.10.1", "compass-preferences-model": "^2.33.2", "hadron-app-registry": "^9.4.2", @@ -58506,6 +58507,7 @@ "@mongodb-js/compass-field-store": "^9.25.2", "@mongodb-js/compass-logging": "^1.6.2", "@mongodb-js/compass-telemetry": "^1.4.2", + "@mongodb-js/compass-workspaces": "^0.31.2", "@mongodb-js/eslint-config-compass": "^1.3.2", "@mongodb-js/mocha-config-compass": "^1.6.2", "@mongodb-js/prettier-config-compass": "^1.2.2", diff --git a/packages/compass-schema-validation/package.json b/packages/compass-schema-validation/package.json index 47ffa39b86e..c6f41463c01 100644 --- a/packages/compass-schema-validation/package.json +++ b/packages/compass-schema-validation/package.json @@ -78,6 +78,7 @@ "@mongodb-js/compass-field-store": "^9.25.2", "@mongodb-js/compass-logging": "^1.6.2", "@mongodb-js/compass-telemetry": "^1.4.2", + "@mongodb-js/compass-workspaces": "^0.31.2", "bson": "^6.10.1", "compass-preferences-model": "^2.33.2", "hadron-app-registry": "^9.4.2", diff --git a/packages/compass-schema-validation/src/index.ts b/packages/compass-schema-validation/src/index.ts index 71af180d1c7..9e4d39e4ee9 100644 --- a/packages/compass-schema-validation/src/index.ts +++ b/packages/compass-schema-validation/src/index.ts @@ -12,6 +12,7 @@ import { preferencesLocator } from 'compass-preferences-model/provider'; import { createLoggerLocator } from '@mongodb-js/compass-logging/provider'; import { telemetryLocator } from '@mongodb-js/compass-telemetry/provider'; import { SchemaValidationTabTitle } from './plugin-title'; +import { workspacesServiceLocator } from '@mongodb-js/compass-workspaces/provider'; const CompassSchemaValidationHadronPlugin = registerHadronPlugin( { @@ -30,6 +31,7 @@ const CompassSchemaValidationHadronPlugin = registerHadronPlugin( preferences: preferencesLocator, logger: createLoggerLocator('COMPASS-SCHEMA-VALIDATION-UI'), track: telemetryLocator, + workspaces: workspacesServiceLocator, } ); export const CompassSchemaValidationPlugin = { diff --git a/packages/compass-schema-validation/src/modules/index.ts b/packages/compass-schema-validation/src/modules/index.ts index 43ce831ae1c..dcbf69bd2f1 100644 --- a/packages/compass-schema-validation/src/modules/index.ts +++ b/packages/compass-schema-validation/src/modules/index.ts @@ -30,6 +30,7 @@ import type { import type AppRegistry from 'hadron-app-registry'; import type { Logger } from '@mongodb-js/compass-logging/provider'; import type { TrackFunction } from '@mongodb-js/compass-telemetry'; +import { type WorkspacesService } from '@mongodb-js/compass-workspaces/provider'; /** * Reset action constant. @@ -67,6 +68,7 @@ export type SchemaValidationExtraArgs = { connectionInfoRef: ConnectionInfoRef; preferences: PreferencesAccess; globalAppRegistry: AppRegistry; + workspaces: WorkspacesService; logger: Logger; track: TrackFunction; }; diff --git a/packages/compass-schema-validation/src/stores/store.spec.ts b/packages/compass-schema-validation/src/stores/store.spec.ts index 90be6a3c07d..598b1f1ba48 100644 --- a/packages/compass-schema-validation/src/stores/store.spec.ts +++ b/packages/compass-schema-validation/src/stores/store.spec.ts @@ -21,6 +21,8 @@ import { createSandboxFromDefaultPreferences } from 'compass-preferences-model'; import { createNoopLogger } from '@mongodb-js/compass-logging/provider'; import { createNoopTrack } from '@mongodb-js/compass-telemetry/provider'; import type { ConnectionInfoRef } from '@mongodb-js/compass-connections/provider'; +import { type WorkspacesService } from '@mongodb-js/compass-workspaces/provider'; +import Sinon from 'sinon'; const topologyDescription = { type: 'Unknown', @@ -42,34 +44,49 @@ const fakeDataService = { }), } as any; -describe('Schema Validation Store', function () { - let store: Store; - let deactivate: null | (() => void) = null; +const fakeWorkspaces = { + onTabReplace: () => {}, + onTabClose: () => {}, +} as unknown as WorkspacesService; + +const getMockedStore = async () => { const globalAppRegistry = new AppRegistry(); const connectionInfoRef = { current: {}, } as ConnectionInfoRef; + const activateResult = onActivated( + { namespace: 'test.test' } as any, + { + globalAppRegistry: globalAppRegistry, + dataService: fakeDataService, + instance: fakeInstance, + workspaces: fakeWorkspaces, + preferences: await createSandboxFromDefaultPreferences(), + logger: createNoopLogger(), + track: createNoopTrack(), + connectionInfoRef, + }, + createActivateHelpers() + ); + return activateResult; +}; + +describe('Schema Validation Store', function () { + let store: Store; + let deactivate: null | (() => void) = null; + let sandbox: Sinon.SinonSandbox; beforeEach(async function () { - const activateResult = onActivated( - { namespace: 'test.test' } as any, - { - globalAppRegistry: globalAppRegistry, - dataService: fakeDataService, - instance: fakeInstance, - preferences: await createSandboxFromDefaultPreferences(), - logger: createNoopLogger(), - track: createNoopTrack(), - connectionInfoRef, - }, - createActivateHelpers() - ); + sandbox = Sinon.createSandbox(); + fakeWorkspaces.onTabClose = sandbox.stub(); + fakeWorkspaces.onTabReplace = sandbox.stub(); + const activateResult = await getMockedStore(); store = activateResult.store; - // eslint-disable-next-line @typescript-eslint/unbound-method deactivate = activateResult.deactivate; }); afterEach(function () { + sandbox.reset(); deactivate?.(); deactivate = null; }); @@ -128,6 +145,16 @@ describe('Schema Validation Store', function () { }); store.dispatch(validatorChanged(validator)); }); + + it('prevents closing the tab', function () { + store.dispatch(validatorChanged(validator)); + expect(store.getState().validation.isChanged).to.be.true; + deactivate?.(); + const fnProvidedToOnTabClose = ( + fakeWorkspaces.onTabClose as Sinon.SinonStub + ).args[0][0]; + expect(fnProvidedToOnTabClose()).to.be.false; + }); }); context('when the action is fetch valid sample documents', function () { diff --git a/packages/compass-schema-validation/src/stores/store.ts b/packages/compass-schema-validation/src/stores/store.ts index 41a0f2364d6..e7e0be3f79d 100644 --- a/packages/compass-schema-validation/src/stores/store.ts +++ b/packages/compass-schema-validation/src/stores/store.ts @@ -16,13 +16,14 @@ import type { MongoDBInstance } from '@mongodb-js/compass-app-stores/provider'; import type { PreferencesAccess } from 'compass-preferences-model'; import type { Logger } from '@mongodb-js/compass-logging/provider'; import type { TrackFunction } from '@mongodb-js/compass-telemetry'; +import { type WorkspacesService } from '@mongodb-js/compass-workspaces/provider'; /** * The lowest supported version. */ const MIN_VERSION = '3.2.0'; -type SchemaValidationServices = { +export type SchemaValidationServices = { globalAppRegistry: AppRegistry; dataService: Pick< DataService, @@ -32,6 +33,7 @@ type SchemaValidationServices = { preferences: PreferencesAccess; instance: MongoDBInstance; logger: Logger; + workspaces: WorkspacesService; track: TrackFunction; }; @@ -41,6 +43,7 @@ export function configureStore( services: Pick< SchemaValidationServices, | 'globalAppRegistry' + | 'workspaces' | 'dataService' | 'preferences' | 'logger' @@ -70,9 +73,10 @@ export function onActivated( preferences, instance, logger, + workspaces, track, }: SchemaValidationServices, - { on, cleanup }: ActivateHelpers + { on, cleanup, addCleanup }: ActivateHelpers ) { const store = configureStore( { @@ -90,6 +94,7 @@ export function onActivated( connectionInfoRef, preferences, globalAppRegistry, + workspaces, logger, track, } @@ -107,6 +112,14 @@ export function onActivated( // Activate validation when this plugin is first rendered store.dispatch(activateValidation()); + const onCloseOrReplace = () => { + return !store.getState().validation.isChanged; + }; + + addCleanup(workspaces.onTabReplace?.(onCloseOrReplace)); + + addCleanup(workspaces.onTabClose?.(onCloseOrReplace)); + return { store, deactivate: cleanup,