({
+ id: 'TEST',
+ }),
+ };
+
describe('with a successful server response', function () {
it('should succeed', async function () {
const mockAtlasAiService = {
@@ -54,6 +60,7 @@ describe('aiQueryReducer', function () {
},
{
dataService: mockDataService,
+ connectionInfoAccess,
atlasAuthService: { on: sandbox.stub() },
atlasAiService: mockAtlasAiService,
preferences,
@@ -99,6 +106,7 @@ describe('aiQueryReducer', function () {
const store = createStore({}, {
atlasAuthService: { on: sandbox.stub() },
atlasAiService: mockAtlasAiService,
+ connectionInfoAccess,
dataService: {
sample() {
return Promise.resolve([]);
@@ -131,6 +139,7 @@ describe('aiQueryReducer', function () {
return Promise.resolve([]);
},
},
+ connectionInfoAccess,
preferences,
logger: createNoopLogger(),
track: createNoopTrack(),
@@ -172,6 +181,7 @@ describe('aiQueryReducer', function () {
},
{
dataService: mockDataService,
+ connectionInfoAccess,
atlasAuthService: { on: sandbox.stub() },
atlasAiService: mockAtlasAiService,
preferences,
@@ -212,6 +222,7 @@ describe('aiQueryReducer', function () {
},
{
dataService: mockDataService,
+ connectionInfoAccess,
atlasAuthService: { on: sandbox.stub() },
atlasAiService: mockAtlasAiService,
preferences,
diff --git a/packages/compass-query-bar/src/stores/ai-query-reducer.ts b/packages/compass-query-bar/src/stores/ai-query-reducer.ts
index f7530728493..0c6c7c43ee3 100644
--- a/packages/compass-query-bar/src/stores/ai-query-reducer.ts
+++ b/packages/compass-query-bar/src/stores/ai-query-reducer.ts
@@ -16,6 +16,7 @@ import type { AtlasServiceError } from '@mongodb-js/atlas-service/renderer';
import type { Logger } from '@mongodb-js/compass-logging/provider';
import { mongoLogId } from '@mongodb-js/compass-logging/provider';
import type { TrackFunction } from '@mongodb-js/compass-telemetry';
+import type { ConnectionInfo } from '@mongodb-js/compass-connections/provider';
type AIQueryStatus = 'ready' | 'fetching' | 'success';
@@ -115,6 +116,7 @@ type FailedResponseTrackMessage = {
log: Logger['log'];
track: TrackFunction;
requestId: string;
+ connectionInfo: ConnectionInfo;
};
function trackAndLogFailed({
@@ -125,6 +127,7 @@ function trackAndLogFailed({
log,
track,
requestId,
+ connectionInfo,
}: FailedResponseTrackMessage) {
log.warn(mongoLogId(1_001_000_198), 'AIQuery', 'AI query request failed', {
statusCode,
@@ -133,13 +136,17 @@ function trackAndLogFailed({
errorCode,
requestId,
});
- track('AI Response Failed', () => ({
- editor_view_type: 'find',
- error_name: errorName,
- status_code: statusCode,
- error_code: errorCode ?? '',
- request_id: requestId,
- }));
+ track(
+ 'AI Response Failed',
+ () => ({
+ editor_view_type: 'find',
+ error_name: errorName,
+ status_code: statusCode,
+ error_code: errorCode ?? '',
+ request_id: requestId,
+ }),
+ connectionInfo
+ );
}
export const runAIQuery = (
@@ -157,6 +164,7 @@ export const runAIQuery = (
preferences,
atlasAiService,
logger: { log },
+ connectionInfoAccess,
track,
}
) => {
@@ -165,12 +173,18 @@ export const runAIQuery = (
const abortController = new AbortController();
const { id: requestId, signal } = getAbortSignal();
- track('AI Prompt Submitted', () => ({
- editor_view_type: 'find',
- user_input_length: userInput.length,
- has_sample_documents: provideSampleDocuments,
- request_id: requestId,
- }));
+ const connectionInfo = connectionInfoAccess.getCurrentConnectionInfo();
+
+ track(
+ 'AI Prompt Submitted',
+ () => ({
+ editor_view_type: 'find',
+ user_input_length: userInput.length,
+ has_sample_documents: provideSampleDocuments,
+ request_id: requestId,
+ }),
+ connectionInfo
+ );
const {
aiQuery: { aiQueryRequestId: existingRequestId },
@@ -234,6 +248,7 @@ export const runAIQuery = (
log,
track,
requestId,
+ connectionInfo,
});
// We're going to reset input state with this error, show the error in the
// toast instead
@@ -286,6 +301,7 @@ export const runAIQuery = (
log,
track,
requestId,
+ connectionInfo,
});
dispatch({
type: AIQueryActionTypes.AIQueryFailed,
@@ -314,6 +330,7 @@ export const runAIQuery = (
log,
track,
requestId,
+ connectionInfo,
});
return;
}
@@ -326,6 +343,7 @@ export const runAIQuery = (
log,
track,
requestId,
+ connectionInfo,
});
dispatch({
type: AIQueryActionTypes.AIQueryFailed,
@@ -351,11 +369,15 @@ export const runAIQuery = (
shape: Object.keys(generatedFields),
}
);
- track('AI Response Generated', () => ({
- editor_view_type: 'find',
- query_shape: Object.keys(generatedFields),
- request_id: requestId,
- }));
+ track(
+ 'AI Response Generated',
+ () => ({
+ editor_view_type: 'find',
+ query_shape: Object.keys(generatedFields),
+ request_id: requestId,
+ }),
+ connectionInfo
+ );
dispatch({
type: AIQueryActionTypes.AIQuerySucceeded,
diff --git a/packages/compass-query-bar/src/stores/query-bar-reducer.ts b/packages/compass-query-bar/src/stores/query-bar-reducer.ts
index 71da0837305..0996a5c9036 100644
--- a/packages/compass-query-bar/src/stores/query-bar-reducer.ts
+++ b/packages/compass-query-bar/src/stores/query-bar-reducer.ts
@@ -394,7 +394,7 @@ const saveRecentQuery = (
query: Omit
): QueryBarThunkAction> => {
return async (
- _dispatch,
+ dispatch,
getState,
{ recentQueryStorage, logger: { debug } }
) => {
@@ -424,6 +424,7 @@ const saveRecentQuery = (
existingQuery._id,
updateAttributes
);
+ dispatch(fetchSavedQueries());
return;
}
@@ -432,6 +433,7 @@ const saveRecentQuery = (
_ns: namespace,
_host: host ?? '',
});
+ dispatch(fetchSavedQueries());
} catch (e) {
debug('Failed to save recent query', e);
}
diff --git a/packages/compass-query-bar/src/stores/query-bar-store.spec.ts b/packages/compass-query-bar/src/stores/query-bar-store.spec.ts
new file mode 100644
index 00000000000..370507d03ec
--- /dev/null
+++ b/packages/compass-query-bar/src/stores/query-bar-store.spec.ts
@@ -0,0 +1,74 @@
+import sinon from 'sinon';
+import { activatePlugin } from './query-bar-store';
+import { createNoopLogger } from '@mongodb-js/compass-logging/provider';
+import { createNoopTrack } from '@mongodb-js/compass-telemetry/provider';
+import { AppRegistry } from 'hadron-app-registry';
+import type { PreferencesAccess } from 'compass-preferences-model';
+import { createSandboxFromDefaultPreferences } from 'compass-preferences-model';
+import { expect } from 'chai';
+import { waitFor } from '@testing-library/react';
+describe('createQueryWithHistoryAutocompleter', function () {
+ let preferences: PreferencesAccess;
+ let loadAllStub: sinon.SinonStub;
+ beforeEach(async function () {
+ loadAllStub = sinon.stub();
+ preferences = await createSandboxFromDefaultPreferences();
+ });
+ afterEach(function () {
+ sinon.restore();
+ });
+ it('calls fetchSavedQueries when activatePlugin is called', async function () {
+ const mockService = {
+ getQueryFromUserInput: sinon
+ .stub()
+ .resolves({ content: { query: { filter: '{_id: 1}' } } }),
+ };
+ const mockDataService = {
+ sample: sinon.stub().resolves([{ _id: 42 }]),
+ getConnectionString: sinon.stub().returns({
+ hosts: ['localhost:27017'],
+ }),
+ };
+ activatePlugin(
+ {
+ namespace: 'test.coll',
+ isReadonly: true,
+ serverVersion: '6.0.0',
+ isSearchIndexesSupported: true,
+ isTimeSeries: false,
+ isClustered: false,
+ isFLE: false,
+ isDataLake: false,
+ isAtlas: false,
+ },
+ {
+ localAppRegistry: new AppRegistry(),
+ globalAppRegistry: new AppRegistry(),
+ dataService: mockDataService,
+ recentQueryStorageAccess: {
+ getStorage: () => ({
+ loadAll: loadAllStub,
+ }),
+ },
+ favoriteQueryStorageAccess: {
+ getStorage: () => ({
+ loadAll: loadAllStub,
+ }),
+ },
+ atlasAuthService: { on: sinon.stub() },
+ atlasAiService: mockService,
+ preferences,
+ logger: createNoopLogger(),
+ track: createNoopTrack(),
+ instance: { isWritable: true, on: sinon.stub() },
+ } as any,
+ {
+ on: () => {},
+ cleanup: () => {},
+ } as any
+ );
+ await waitFor(() => {
+ expect(loadAllStub).to.have.been.calledTwice;
+ });
+ });
+});
diff --git a/packages/compass-query-bar/src/stores/query-bar-store.ts b/packages/compass-query-bar/src/stores/query-bar-store.ts
index a3fd82c2f96..70a1dbcf532 100644
--- a/packages/compass-query-bar/src/stores/query-bar-store.ts
+++ b/packages/compass-query-bar/src/stores/query-bar-store.ts
@@ -7,13 +7,17 @@ import {
import thunk from 'redux-thunk';
import type { AnyAction } from 'redux';
import type { ThunkAction, ThunkDispatch } from 'redux-thunk';
-import type { DataService } from '@mongodb-js/compass-connections/provider';
+import type {
+ ConnectionInfoAccess,
+ DataService,
+} from '@mongodb-js/compass-connections/provider';
import { DEFAULT_FIELD_VALUES } from '../constants/query-bar-store';
import { mapQueryToFormFields } from '../utils/query';
import {
queryBarReducer,
INITIAL_STATE as INITIAL_QUERY_BAR_STATE,
QueryBarActions,
+ fetchSavedQueries,
} from './query-bar-reducer';
import { aiQueryReducer } from './ai-query-reducer';
import { getQueryAttributes } from '../utils';
@@ -44,6 +48,7 @@ type QueryBarServices = {
preferences: PreferencesAccess;
logger: Logger;
track: TrackFunction;
+ connectionInfoAccess: ConnectionInfoAccess;
atlasAuthService: AtlasAuthService;
atlasAiService: AtlasAiService;
favoriteQueryStorageAccess?: FavoriteQueryStorageAccess;
@@ -77,6 +82,7 @@ export type QueryBarExtraArgs = {
recentQueryStorage?: RecentQueryStorage;
logger: Logger;
track: TrackFunction;
+ connectionInfoAccess: ConnectionInfoAccess;
atlasAiService: AtlasAiService;
};
@@ -119,6 +125,7 @@ export function activatePlugin(
preferences,
logger,
track,
+ connectionInfoAccess,
atlasAuthService,
atlasAiService,
favoriteQueryStorageAccess,
@@ -153,6 +160,7 @@ export function activatePlugin(
preferences,
logger,
track,
+ connectionInfoAccess,
atlasAiService,
}
);
@@ -164,5 +172,7 @@ export function activatePlugin(
});
});
+ store.dispatch(fetchSavedQueries());
+
return { store, deactivate: cleanup, context: QueryBarStoreContext };
}
diff --git a/packages/compass-saved-aggregations-queries/package.json b/packages/compass-saved-aggregations-queries/package.json
index 5f114ef1e2a..728e1820944 100644
--- a/packages/compass-saved-aggregations-queries/package.json
+++ b/packages/compass-saved-aggregations-queries/package.json
@@ -11,7 +11,7 @@
"email": "compass@mongodb.com"
},
"homepage": "https://github.com/mongodb-js/compass",
- "version": "1.33.0",
+ "version": "1.36.0",
"repository": {
"type": "git",
"url": "https://github.com/mongodb-js/compass.git"
@@ -48,19 +48,19 @@
"reformat": "npm run eslint . -- --fix && npm run prettier -- --write ."
},
"dependencies": {
- "@mongodb-js/compass-app-stores": "^7.19.0",
- "@mongodb-js/compass-components": "^1.26.0",
- "@mongodb-js/compass-connections": "^1.33.0",
- "@mongodb-js/compass-logging": "^1.3.1",
- "@mongodb-js/compass-telemetry": "^1.0.1",
- "@mongodb-js/compass-workspaces": "^0.14.0",
- "@mongodb-js/connection-form": "^1.31.0",
- "@mongodb-js/connection-info": "^0.4.1",
- "@mongodb-js/my-queries-storage": "^0.10.0",
+ "@mongodb-js/compass-app-stores": "^7.22.0",
+ "@mongodb-js/compass-components": "^1.28.0",
+ "@mongodb-js/compass-connections": "^1.36.0",
+ "@mongodb-js/compass-logging": "^1.4.1",
+ "@mongodb-js/compass-telemetry": "^1.1.1",
+ "@mongodb-js/compass-workspaces": "^0.17.0",
+ "@mongodb-js/connection-form": "^1.34.0",
+ "@mongodb-js/connection-info": "^0.5.1",
+ "@mongodb-js/my-queries-storage": "^0.13.0",
"bson": "^6.7.0",
- "compass-preferences-model": "^2.23.1",
+ "compass-preferences-model": "^2.25.0",
"fuse.js": "^6.5.3",
- "hadron-app-registry": "^9.1.12",
+ "hadron-app-registry": "^9.2.1",
"mongodb-ns": "^2.4.2",
"react": "^17.0.2",
"react-redux": "^8.1.3",
@@ -68,8 +68,8 @@
"redux-thunk": "^2.4.2"
},
"devDependencies": {
- "@mongodb-js/connection-storage": "^0.14.1",
- "@mongodb-js/eslint-config-compass": "^1.1.2",
+ "@mongodb-js/connection-storage": "^0.16.0",
+ "@mongodb-js/eslint-config-compass": "^1.1.3",
"@mongodb-js/mocha-config-compass": "^1.3.9",
"@mongodb-js/prettier-config-compass": "^1.0.2",
"@mongodb-js/tsconfig-compass": "^1.0.4",
diff --git a/packages/compass-saved-aggregations-queries/src/index.ts b/packages/compass-saved-aggregations-queries/src/index.ts
index bdcf6573577..c977c816dbd 100644
--- a/packages/compass-saved-aggregations-queries/src/index.ts
+++ b/packages/compass-saved-aggregations-queries/src/index.ts
@@ -2,7 +2,7 @@ import { registerHadronPlugin } from 'hadron-app-registry';
import { connectionsManagerLocator } from '@mongodb-js/compass-connections/provider';
import { mongoDBInstancesManagerLocator } from '@mongodb-js/compass-app-stores/provider';
import { createLoggerLocator } from '@mongodb-js/compass-logging/provider';
-import { createTelemetryLocator } from '@mongodb-js/compass-telemetry/provider';
+import { telemetryLocator } from '@mongodb-js/compass-telemetry/provider';
import { activatePlugin } from './stores';
import AggregationsQueriesList from './components/aggregations-queries-list';
import type { WorkspaceComponent } from '@mongodb-js/compass-workspaces';
@@ -18,7 +18,7 @@ const serviceLocators = {
instancesManager: mongoDBInstancesManagerLocator,
preferencesAccess: preferencesLocator,
logger: createLoggerLocator('COMPASS-MY-QUERIES-UI'),
- track: createTelemetryLocator(),
+ track: telemetryLocator,
workspaces: workspacesServiceLocator,
pipelineStorage: pipelineStorageLocator,
favoriteQueryStorageAccess: favoriteQueryStorageAccessLocator,
diff --git a/packages/compass-schema-validation/package.json b/packages/compass-schema-validation/package.json
index 397f0b369f1..2d55fa0eda0 100644
--- a/packages/compass-schema-validation/package.json
+++ b/packages/compass-schema-validation/package.json
@@ -6,7 +6,7 @@
"email": "compass@mongodb.com"
},
"private": true,
- "version": "6.33.0",
+ "version": "6.36.0",
"repository": {
"type": "git",
"url": "https://github.com/mongodb-js/compass.git"
@@ -48,41 +48,41 @@
"reformat": "npm run eslint . -- --fix && npm run prettier -- --write ."
},
"devDependencies": {
- "@mongodb-js/eslint-config-compass": "^1.1.2",
+ "@mongodb-js/eslint-config-compass": "^1.1.3",
"@mongodb-js/mocha-config-compass": "^1.3.9",
"@mongodb-js/prettier-config-compass": "^1.0.2",
"@mongodb-js/tsconfig-compass": "^1.0.4",
"chai": "^4.2.0",
"depcheck": "^1.4.1",
- "electron": "^29.4.3",
+ "electron": "^29.4.5",
"electron-mocha": "^12.2.0",
"enzyme": "^3.11.0",
"eslint": "^7.25.0",
- "hadron-ipc": "^3.2.16",
+ "hadron-ipc": "^3.2.18",
"mocha": "^10.2.0",
- "mongodb-instance-model": "^12.22.1",
+ "mongodb-instance-model": "^12.23.1",
"nyc": "^15.1.0",
"react-dom": "^17.0.2",
"sinon": "^8.1.1",
"typescript": "^5.0.4"
},
"dependencies": {
- "@mongodb-js/compass-app-stores": "^7.19.0",
- "@mongodb-js/compass-collection": "^4.32.0",
- "@mongodb-js/compass-components": "^1.26.0",
- "@mongodb-js/compass-connections": "^1.33.0",
- "@mongodb-js/compass-crud": "^13.33.0",
- "@mongodb-js/compass-editor": "^0.25.0",
- "@mongodb-js/compass-field-store": "^9.8.0",
- "@mongodb-js/compass-logging": "^1.3.1",
- "@mongodb-js/compass-telemetry": "^1.0.1",
+ "@mongodb-js/compass-app-stores": "^7.22.0",
+ "@mongodb-js/compass-collection": "^4.35.0",
+ "@mongodb-js/compass-components": "^1.28.0",
+ "@mongodb-js/compass-connections": "^1.36.0",
+ "@mongodb-js/compass-crud": "^13.36.0",
+ "@mongodb-js/compass-editor": "^0.27.0",
+ "@mongodb-js/compass-field-store": "^9.11.0",
+ "@mongodb-js/compass-logging": "^1.4.1",
+ "@mongodb-js/compass-telemetry": "^1.1.1",
"bson": "^6.7.0",
- "compass-preferences-model": "^2.23.1",
- "hadron-app-registry": "^9.1.12",
+ "compass-preferences-model": "^2.25.0",
+ "hadron-app-registry": "^9.2.1",
"javascript-stringify": "^2.0.1",
"lodash": "^4.17.21",
"mongodb-ns": "^2.4.2",
- "mongodb-query-parser": "^4.1.2",
+ "mongodb-query-parser": "^4.2.0",
"prop-types": "^15.7.2",
"react": "^17.0.2",
"react-redux": "^8.1.3",
diff --git a/packages/compass-schema-validation/src/components/validation-editor/validation-editor.tsx b/packages/compass-schema-validation/src/components/validation-editor/validation-editor.tsx
index 56f77310703..016e91481ed 100644
--- a/packages/compass-schema-validation/src/components/validation-editor/validation-editor.tsx
+++ b/packages/compass-schema-validation/src/components/validation-editor/validation-editor.tsx
@@ -28,6 +28,10 @@ import type {
} from '../../modules/validation';
import { checkValidator } from '../../modules/validation';
import { ActionSelector, LevelSelector } from '../validation-selectors';
+import {
+ type ConnectionInfoAccess,
+ withConnectionInfoAccess,
+} from '@mongodb-js/compass-connections/provider';
const validationEditorStyles = css({
padding: spacing[3],
@@ -117,6 +121,7 @@ export type ValidationEditorProps = {
isEditable: boolean;
darkMode?: boolean;
track: TrackFunction;
+ connectionInfoAccess: ConnectionInfoAccess;
};
/**
@@ -178,7 +183,11 @@ class ValidationEditor extends Component {
typeof checkedValidator.validator === 'object' &&
!!checkedValidator.validator?.$jsonSchema,
};
- this.props.track('Schema Validation Edited', trackEvent);
+ this.props.track(
+ 'Schema Validation Edited',
+ trackEvent,
+ this.props.connectionInfoAccess.getCurrentConnectionInfo()
+ );
}
/**
@@ -313,5 +322,7 @@ class ValidationEditor extends Component {
}
export default withTelemetry(
- withDarkMode(ValidationEditor)
+ withConnectionInfoAccess(
+ withDarkMode(ValidationEditor)
+ )
);
diff --git a/packages/compass-schema-validation/src/index.ts b/packages/compass-schema-validation/src/index.ts
index 3cd3f8f8c3b..ec4da917a16 100644
--- a/packages/compass-schema-validation/src/index.ts
+++ b/packages/compass-schema-validation/src/index.ts
@@ -2,13 +2,14 @@ import { onActivated } from './stores';
import CompassSchemaValidation from './components/compass-schema-validation';
import { registerHadronPlugin } from 'hadron-app-registry';
import {
+ connectionInfoAccessLocator,
dataServiceLocator,
type DataServiceLocator,
} from '@mongodb-js/compass-connections/provider';
import { mongoDBInstanceLocator } from '@mongodb-js/compass-app-stores/provider';
import { preferencesLocator } from 'compass-preferences-model/provider';
import { createLoggerLocator } from '@mongodb-js/compass-logging/provider';
-import { createTelemetryLocator } from '@mongodb-js/compass-telemetry/provider';
+import { telemetryLocator } from '@mongodb-js/compass-telemetry/provider';
export const CompassSchemaValidationHadronPlugin = registerHadronPlugin(
{
@@ -20,10 +21,11 @@ export const CompassSchemaValidationHadronPlugin = registerHadronPlugin(
dataService: dataServiceLocator as DataServiceLocator<
'aggregate' | 'collectionInfo' | 'updateCollection'
>,
+ connectionInfoAccess: connectionInfoAccessLocator,
instance: mongoDBInstanceLocator,
preferences: preferencesLocator,
logger: createLoggerLocator('COMPASS-SCHEMA-VALIDATION-UI'),
- track: createTelemetryLocator(),
+ track: telemetryLocator,
}
);
export const CompassSchemaValidationPlugin = {
diff --git a/packages/compass-schema-validation/src/modules/index.ts b/packages/compass-schema-validation/src/modules/index.ts
index 8c3376bb51a..f0592fd6cbd 100644
--- a/packages/compass-schema-validation/src/modules/index.ts
+++ b/packages/compass-schema-validation/src/modules/index.ts
@@ -23,7 +23,10 @@ import type { EditModeAction, EditModeState } from './edit-mode';
import editMode, { INITIAL_STATE as EDIT_MODE_STATE } from './edit-mode';
import type { ThunkAction } from 'redux-thunk';
import type { PreferencesAccess } from 'compass-preferences-model';
-import type { DataService } from '@mongodb-js/compass-connections/provider';
+import type {
+ ConnectionInfoAccess,
+ DataService,
+} from '@mongodb-js/compass-connections/provider';
import type AppRegistry from 'hadron-app-registry';
import type { Logger } from '@mongodb-js/compass-logging/provider';
import type { TrackFunction } from '@mongodb-js/compass-telemetry';
@@ -61,6 +64,7 @@ export type SchemaValidationExtraArgs = {
DataService,
'aggregate' | 'collectionInfo' | 'updateCollection'
>;
+ connectionInfoAccess: ConnectionInfoAccess;
preferences: PreferencesAccess;
globalAppRegistry: AppRegistry;
logger: Logger;
diff --git a/packages/compass-schema-validation/src/modules/validation.ts b/packages/compass-schema-validation/src/modules/validation.ts
index 0cdb01d56dd..a98c34f5541 100644
--- a/packages/compass-schema-validation/src/modules/validation.ts
+++ b/packages/compass-schema-validation/src/modules/validation.ts
@@ -456,7 +456,11 @@ export function validationFromCollection(
export const saveValidation = (
validation: Validation
): SchemaValidationThunkAction> => {
- return async (dispatch, getState, { dataService, track }) => {
+ return async (
+ dispatch,
+ getState,
+ { dataService, track, connectionInfoAccess }
+ ) => {
const state = getState();
const namespace = state.namespace;
const checkedValidator = checkValidator(validation.validator);
@@ -471,7 +475,11 @@ export const saveValidation = (
validation_action: validation.validationAction,
validation_level: validation.validationLevel,
};
- track('Schema Validation Updated', trackEvent);
+ track(
+ 'Schema Validation Updated',
+ trackEvent,
+ connectionInfoAccess.getCurrentConnectionInfo()
+ );
try {
await dataService.updateCollection(
`${namespace.database}.${namespace.collection}`,
diff --git a/packages/compass-schema-validation/src/modules/zero-state.ts b/packages/compass-schema-validation/src/modules/zero-state.ts
index 22d2b70b09d..fcb98f5f5b1 100644
--- a/packages/compass-schema-validation/src/modules/zero-state.ts
+++ b/packages/compass-schema-validation/src/modules/zero-state.ts
@@ -48,9 +48,13 @@ export const zeroStateChanged = (
export const changeZeroState = (
isZeroState: boolean
): SchemaValidationThunkAction => {
- return (dispatch, _getState, { track }) => {
+ return (dispatch, _getState, { track, connectionInfoAccess }) => {
if (isZeroState === false) {
- track('Schema Validation Added');
+ track(
+ 'Schema Validation Added',
+ {},
+ connectionInfoAccess.getCurrentConnectionInfo()
+ );
}
return dispatch(zeroStateChanged(isZeroState));
};
diff --git a/packages/compass-schema-validation/src/stores/store.spec.ts b/packages/compass-schema-validation/src/stores/store.spec.ts
index 116f12ba577..bdc8f0f9b70 100644
--- a/packages/compass-schema-validation/src/stores/store.spec.ts
+++ b/packages/compass-schema-validation/src/stores/store.spec.ts
@@ -20,6 +20,7 @@ import { onActivated } from './store';
import { createSandboxFromDefaultPreferences } from 'compass-preferences-model';
import { createNoopLogger } from '@mongodb-js/compass-logging/provider';
import { createNoopTrack } from '@mongodb-js/compass-telemetry/provider';
+import type { ConnectionInfoAccess } from '@mongodb-js/compass-connections/provider';
const topologyDescription = {
type: 'Unknown',
@@ -45,6 +46,9 @@ describe('Schema Validation Store', function () {
let store: Store;
let deactivate: null | (() => void) = null;
const globalAppRegistry = new AppRegistry();
+ const connectionInfoAccess = {
+ getCurrentConnectionInfo: () => {},
+ } as ConnectionInfoAccess;
beforeEach(async function () {
const activateResult = onActivated(
@@ -56,6 +60,7 @@ describe('Schema Validation Store', function () {
preferences: await createSandboxFromDefaultPreferences(),
logger: createNoopLogger(),
track: createNoopTrack(),
+ connectionInfoAccess,
},
createActivateHelpers()
);
diff --git a/packages/compass-schema-validation/src/stores/store.ts b/packages/compass-schema-validation/src/stores/store.ts
index bb30e1bfea3..38510cf10cf 100644
--- a/packages/compass-schema-validation/src/stores/store.ts
+++ b/packages/compass-schema-validation/src/stores/store.ts
@@ -8,7 +8,10 @@ import { editModeChanged } from '../modules/edit-mode';
import semver from 'semver';
import type { CollectionTabPluginMetadata } from '@mongodb-js/compass-collection';
import type { ActivateHelpers, AppRegistry } from 'hadron-app-registry';
-import type { DataService } from '@mongodb-js/compass-connections/provider';
+import type {
+ ConnectionInfoAccess,
+ DataService,
+} from '@mongodb-js/compass-connections/provider';
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';
@@ -25,6 +28,7 @@ type SchemaValidationServices = {
DataService,
'aggregate' | 'collectionInfo' | 'updateCollection'
>;
+ connectionInfoAccess: ConnectionInfoAccess;
preferences: PreferencesAccess;
instance: MongoDBInstance;
logger: Logger;
@@ -36,7 +40,12 @@ export function configureStore(
state: Partial,
services: Pick<
SchemaValidationServices,
- 'globalAppRegistry' | 'dataService' | 'preferences' | 'logger' | 'track'
+ | 'globalAppRegistry'
+ | 'dataService'
+ | 'preferences'
+ | 'logger'
+ | 'track'
+ | 'connectionInfoAccess'
>
) {
return createStore(
@@ -57,6 +66,7 @@ export function onActivated(
{
globalAppRegistry,
dataService,
+ connectionInfoAccess,
preferences,
instance,
logger,
@@ -77,6 +87,7 @@ export function onActivated(
},
{
dataService,
+ connectionInfoAccess,
preferences,
globalAppRegistry,
logger,
diff --git a/packages/compass-schema/package.json b/packages/compass-schema/package.json
index 83bfdcb2fc4..19df073b66e 100644
--- a/packages/compass-schema/package.json
+++ b/packages/compass-schema/package.json
@@ -6,7 +6,7 @@
"email": "compass@mongodb.com"
},
"private": true,
- "version": "6.34.0",
+ "version": "6.37.0",
"repository": {
"type": "git",
"url": "https://github.com/mongodb-js/compass.git"
@@ -48,9 +48,9 @@
"reformat": "npm run eslint . -- --fix && npm run prettier -- --write ."
},
"devDependencies": {
- "@mongodb-js/eslint-config-compass": "^1.1.2",
+ "@mongodb-js/eslint-config-compass": "^1.1.3",
"@mongodb-js/mocha-config-compass": "^1.3.9",
- "@mongodb-js/my-queries-storage": "^0.10.0",
+ "@mongodb-js/my-queries-storage": "^0.13.0",
"@mongodb-js/prettier-config-compass": "^1.0.2",
"@mongodb-js/tsconfig-compass": "^1.0.4",
"@testing-library/react": "^12.1.5",
@@ -73,26 +73,26 @@
"xvfb-maybe": "^0.2.1"
},
"dependencies": {
- "@mongodb-js/compass-collection": "^4.32.0",
- "@mongodb-js/compass-components": "^1.26.0",
- "@mongodb-js/compass-connections": "^1.33.0",
- "@mongodb-js/compass-field-store": "^9.8.0",
- "@mongodb-js/compass-logging": "^1.3.1",
- "@mongodb-js/compass-telemetry": "^1.0.1",
- "@mongodb-js/compass-query-bar": "^8.34.0",
- "@mongodb-js/connection-storage": "^0.14.1",
+ "@mongodb-js/compass-collection": "^4.35.0",
+ "@mongodb-js/compass-components": "^1.28.0",
+ "@mongodb-js/compass-connections": "^1.36.0",
+ "@mongodb-js/compass-field-store": "^9.11.0",
+ "@mongodb-js/compass-logging": "^1.4.1",
+ "@mongodb-js/compass-telemetry": "^1.1.1",
+ "@mongodb-js/compass-query-bar": "^8.37.0",
+ "@mongodb-js/connection-storage": "^0.16.0",
"bson": "^6.7.0",
- "compass-preferences-model": "^2.23.1",
+ "compass-preferences-model": "^2.25.0",
"d3": "^3.5.17",
- "hadron-app-registry": "^9.1.12",
- "hadron-document": "^8.5.4",
+ "hadron-app-registry": "^9.2.1",
+ "hadron-document": "^8.5.5",
"leaflet": "^1.5.1",
"leaflet-defaulticon-compatibility": "^0.1.1",
"leaflet-draw": "^1.0.4",
"lodash": "^4.17.21",
"moment": "^2.29.4",
"mongodb": "^6.7.0",
- "mongodb-query-util": "^2.2.3",
+ "mongodb-query-util": "^2.2.4",
"mongodb-schema": "^12.2.0",
"numeral": "^1.5.6",
"prop-types": "^15.7.2",
@@ -100,7 +100,7 @@
"react-leaflet": "^2.4.0",
"react-leaflet-draw": "^0.19.0",
"reflux": "^0.4.1",
- "@mongodb-js/reflux-state-mixin": "^1.0.2"
+ "@mongodb-js/reflux-state-mixin": "^1.0.3"
},
"is_compass_plugin": true
}
diff --git a/packages/compass-schema/src/components/compass-schema.tsx b/packages/compass-schema/src/components/compass-schema.tsx
index 231c85f8b07..6b4d47ff6b1 100644
--- a/packages/compass-schema/src/components/compass-schema.tsx
+++ b/packages/compass-schema/src/components/compass-schema.tsx
@@ -337,7 +337,7 @@ const FieldList: React.FunctionComponent<{
const nbsp = '\u00a0';
const title = 'Atlas’ Performance Advisor.';
const PerformanceAdvisorBanner = () => {
- const { atlasMetadata } = useConnectionInfo();
+ const connectionInfo = useConnectionInfo();
const track = useTelemetry();
return (
@@ -348,10 +348,12 @@ const PerformanceAdvisorBanner = () => {
Insight
{nbsp}or{nbsp}
- {atlasMetadata ? (
+ {connectionInfo.atlasMetadata ? (
track('Performance Advisor Clicked')}
+ href={getAtlasPerformanceAdvisorLink(connectionInfo.atlasMetadata)}
+ onClick={() =>
+ track('Performance Advisor Clicked', {}, connectionInfo)
+ }
hideExternalIcon
>
{title}
diff --git a/packages/compass-schema/src/index.ts b/packages/compass-schema/src/index.ts
index 0701e840424..201098d8abd 100644
--- a/packages/compass-schema/src/index.ts
+++ b/packages/compass-schema/src/index.ts
@@ -1,4 +1,5 @@
import {
+ connectionInfoAccessLocator,
dataServiceLocator,
type DataServiceLocator,
} from '@mongodb-js/compass-connections/provider';
@@ -7,7 +8,7 @@ import CompassSchema from './components/compass-schema';
import { registerHadronPlugin } from 'hadron-app-registry';
import { activateSchemaPlugin } from './stores/store';
import { createLoggerLocator } from '@mongodb-js/compass-logging/provider';
-import { createTelemetryLocator } from '@mongodb-js/compass-telemetry/provider';
+import { telemetryLocator } from '@mongodb-js/compass-telemetry/provider';
import { preferencesLocator } from 'compass-preferences-model/provider';
import { fieldStoreServiceLocator } from '@mongodb-js/compass-field-store';
import { queryBarServiceLocator } from '@mongodb-js/compass-query-bar';
@@ -23,10 +24,11 @@ export const CompassSchemaHadronPlugin = registerHadronPlugin(
'sample' | 'isCancelError'
>,
logger: createLoggerLocator('COMPASS-SCHEMA-UI'),
- track: createTelemetryLocator(),
+ track: telemetryLocator,
preferences: preferencesLocator,
fieldStoreService: fieldStoreServiceLocator,
queryBar: queryBarServiceLocator,
+ connectionInfoAccess: connectionInfoAccessLocator,
}
);
export const CompassSchemaPlugin = {
diff --git a/packages/compass-schema/src/stores/store.spec.ts b/packages/compass-schema/src/stores/store.spec.ts
index 096ed700631..f08d4617d25 100644
--- a/packages/compass-schema/src/stores/store.spec.ts
+++ b/packages/compass-schema/src/stores/store.spec.ts
@@ -8,6 +8,7 @@ import { createSandboxFromDefaultPreferences } from 'compass-preferences-model';
import { createNoopLogger } from '@mongodb-js/compass-logging/provider';
import type { FieldStoreService } from '@mongodb-js/compass-field-store';
import { createNoopTrack } from '@mongodb-js/compass-telemetry/provider';
+import type { ConnectionInfoAccess } from '@mongodb-js/compass-connections/provider';
const dummyLogger = createNoopLogger('TEST');
const dummyTrack = createNoopTrack();
@@ -31,6 +32,9 @@ describe('Schema Store', function () {
const globalAppRegistry = new AppRegistry();
const dataService = 'test';
const namespace = 'db.coll';
+ const connectionInfoAccess = {
+ getCurrentConnectionInfo: () => {},
+ } as ConnectionInfoAccess;
beforeEach(async function () {
const plugin = activateSchemaPlugin(
@@ -46,6 +50,7 @@ describe('Schema Store', function () {
preferences: await createSandboxFromDefaultPreferences(),
fieldStoreService: mockFieldStoreService,
queryBar: mockQueryBar as any,
+ connectionInfoAccess,
},
createActivateHelpers()
);
diff --git a/packages/compass-schema/src/stores/store.ts b/packages/compass-schema/src/stores/store.ts
index 1debaaf7b54..9485a1250e9 100644
--- a/packages/compass-schema/src/stores/store.ts
+++ b/packages/compass-schema/src/stores/store.ts
@@ -20,7 +20,10 @@ import {
import { capMaxTimeMSAtPreferenceLimit } from 'compass-preferences-model/provider';
import { openToast } from '@mongodb-js/compass-components';
import type { CollectionTabPluginMetadata } from '@mongodb-js/compass-collection';
-import type { DataService as OriginalDataService } from '@mongodb-js/compass-connections/provider';
+import type {
+ ConnectionInfoAccess,
+ DataService as OriginalDataService,
+} from '@mongodb-js/compass-connections/provider';
import type { ActivateHelpers } from 'hadron-app-registry';
import type AppRegistry from 'hadron-app-registry';
import { configureActions } from '../actions';
@@ -57,6 +60,7 @@ function resultId(): number {
export type DataService = Pick;
export type SchemaPluginServices = {
dataService: DataService;
+ connectionInfoAccess: ConnectionInfoAccess;
localAppRegistry: Pick;
globalAppRegistry: Pick;
logger: Logger;
@@ -127,6 +131,7 @@ export function activateSchemaPlugin(
preferences,
fieldStoreService,
queryBar,
+ connectionInfoAccess,
}: SchemaPluginServices,
{ on, cleanup }: ActivateHelpers
) {
@@ -261,7 +266,11 @@ export function activateSchemaPlugin(
geo_data: schema ? schemaContainsGeoData(schema) : false,
analysis_time_ms: analysisTimeMS,
});
- track('Schema Analyzed', trackEvent);
+ track(
+ 'Schema Analyzed',
+ trackEvent,
+ connectionInfoAccess.getCurrentConnectionInfo()
+ );
},
startAnalysis: async function (this: SchemaStore) {
diff --git a/packages/compass-serverstats/package.json b/packages/compass-serverstats/package.json
index 30f834356f3..9ec09b697e4 100644
--- a/packages/compass-serverstats/package.json
+++ b/packages/compass-serverstats/package.json
@@ -2,7 +2,7 @@
"name": "@mongodb-js/compass-serverstats",
"description": "Compass Real Time",
"private": true,
- "version": "16.32.0",
+ "version": "16.35.0",
"main": "dist/index.js",
"compass:main": "src/index.ts",
"exports": {
@@ -30,15 +30,15 @@
},
"license": "SSPL",
"dependencies": {
- "@mongodb-js/compass-app-stores": "^7.19.0",
- "@mongodb-js/compass-components": "^1.26.0",
- "@mongodb-js/compass-connections": "^1.33.0",
- "@mongodb-js/compass-telemetry": "^1.0.1",
- "@mongodb-js/compass-workspaces": "^0.14.0",
+ "@mongodb-js/compass-app-stores": "^7.22.0",
+ "@mongodb-js/compass-components": "^1.28.0",
+ "@mongodb-js/compass-connections": "^1.36.0",
+ "@mongodb-js/compass-telemetry": "^1.1.1",
+ "@mongodb-js/compass-workspaces": "^0.17.0",
"d3": "^3.5.17",
"d3-timer": "^1.0.3",
"debug": "^4.3.4",
- "hadron-app-registry": "^9.1.12",
+ "hadron-app-registry": "^9.2.1",
"lodash": "^4.17.21",
"mongodb-ns": "^2.4.2",
"prop-types": "^15.7.2",
@@ -46,7 +46,7 @@
"reflux": "^0.4.1"
},
"devDependencies": {
- "@mongodb-js/eslint-config-compass": "^1.1.2",
+ "@mongodb-js/eslint-config-compass": "^1.1.3",
"@mongodb-js/mocha-config-compass": "^1.3.9",
"@mongodb-js/prettier-config-compass": "^1.0.2",
"@mongodb-js/tsconfig-compass": "^1.0.4",
diff --git a/packages/compass-serverstats/src/components/current-op-component.jsx b/packages/compass-serverstats/src/components/current-op-component.jsx
index 5d0fd30e278..a17af94ee28 100644
--- a/packages/compass-serverstats/src/components/current-op-component.jsx
+++ b/packages/compass-serverstats/src/components/current-op-component.jsx
@@ -4,6 +4,9 @@ const PropTypes = require('prop-types');
const Actions = require('../actions');
const DBErrorStore = require('../stores/dberror-store');
const { withTelemetry } = require('@mongodb-js/compass-telemetry/provider');
+const {
+ withConnectionInfoAccess,
+} = require('@mongodb-js/compass-connections/provider');
// const debug = require('debug')('mongodb-compass:server-stats:current-op-component');
@@ -97,7 +100,11 @@ class CurrentOpComponent extends React.Component {
* @param {Object} data - The row data.
*/
showOperationDetails(data) {
- this.props.track('CurrentOp showOperationDetails');
+ this.props.track(
+ 'CurrentOp showOperationDetails',
+ {},
+ this.props.connectionInfoAccess.getCurrentConnectionInfo()
+ );
Actions.showOperationDetails(data);
}
@@ -186,9 +193,10 @@ class CurrentOpComponent extends React.Component {
CurrentOpComponent.propTypes = {
store: PropTypes.any.isRequired,
interval: PropTypes.number.isRequired,
- track: PropTypes.any,
+ track: PropTypes.any.isRequired,
+ connectionInfoAccess: PropTypes.any.isRequired,
};
CurrentOpComponent.displayName = 'CurrentOpComponent';
-module.exports = withTelemetry(CurrentOpComponent);
+module.exports = withTelemetry(withConnectionInfoAccess(CurrentOpComponent));
diff --git a/packages/compass-serverstats/src/components/detailview-component.jsx b/packages/compass-serverstats/src/components/detailview-component.jsx
deleted file mode 100644
index 8b2a5b1f891..00000000000
--- a/packages/compass-serverstats/src/components/detailview-component.jsx
+++ /dev/null
@@ -1,165 +0,0 @@
-const React = require('react');
-const Actions = require('../actions');
-const { Button, Icon } = require('@mongodb-js/compass-components');
-const PropTypes = require('prop-types');
-const { withTelemetry } = require('@mongodb-js/compass-telemetry/provider');
-
-class DetailViewComponent extends React.Component {
- constructor(props) {
- super(props);
- this.state = { error: null, data: {}, display: 'none' };
- }
-
- componentDidMount() {
- this.unsubscribeShowOperationDetails = Actions.showOperationDetails.listen(
- this.show.bind(this)
- );
- this.unsubscribeHideOperationDetails = Actions.hideOperationDetails.listen(
- this.hide.bind(this)
- );
- }
-
- componentWillUnmount() {
- this.unsubscribeShowOperationDetails();
- this.unsubscribeHideOperationDetails();
- }
-
- /**
- * Set the component to visible.
- *
- * @param {Object} data - The operation data.
- */
- show(data) {
- this.setState({ data: data, display: 'block' });
- }
-
- /**
- * Set the component to hidden.
- */
- hide() {
- this.setState({ data: {}, display: 'none' });
- }
-
- killOp() {
- this.props.logger.track('DetailView killOp');
- Actions.killOp(this.state.data.opid);
- this.hideOperationDetails();
- }
-
- /**
- * Fire the show operation detail action with the row data.
- */
- hideOperationDetails() {
- this.props.logger.track('DetailView hideOperationDetails');
- Actions.hideOperationDetails();
- }
-
- removeMs(key, value) {
- if (key === 'ms_running') {
- return undefined;
- }
- return value;
- }
-
- renderError() {
- return (
-
- this.state.error.message
-
- );
- }
-
- renderZero() {
- return ;
- }
-
- renderGraph() {
- return (
-
-
-
-
-
{this.state.data.op}
-
- {this.state.data.ns}
-
-
- {this.state.data.ms_running + ' ms'}
-
-
-
- -
-
opid
-
- {this.state.data.opid}
-
-
- -
-
client s
-
- {this.state.data.client}
-
-
- -
-
active
-
- {this.state.data.active}
-
-
- -
-
wait lock
-
- {this.state.data.waitingForLock}
-
-
- -
-
-
-
-
-
-
- {JSON.stringify(this.state.data, this.removeMs, 4)}
-
-
-
- );
- }
-
- render() {
- if (this.state.error) {
- return this.renderError();
- }
- if (this.state.data.length === 0) {
- return this.renderZero();
- }
- return this.renderGraph();
- }
-
- static propTypes = {
- logger: PropTypes.any.isRequired,
- };
-}
-
-DetailViewComponent.displayName = 'DetailViewComponent';
-
-module.exports = withTelemetry(DetailViewComponent);
diff --git a/packages/compass-serverstats/src/components/detailview-component.tsx b/packages/compass-serverstats/src/components/detailview-component.tsx
new file mode 100644
index 00000000000..87a4b2e3f3e
--- /dev/null
+++ b/packages/compass-serverstats/src/components/detailview-component.tsx
@@ -0,0 +1,131 @@
+import React, { useCallback, useEffect, useState } from 'react';
+import { Button, Icon } from '@mongodb-js/compass-components';
+import { useTelemetry } from '@mongodb-js/compass-telemetry/provider';
+
+import Actions from '../actions';
+import { useConnectionInfoAccess } from '@mongodb-js/compass-connections/provider';
+
+function removeMS(key: string, value: any) {
+ if (key === 'ms_running') {
+ return undefined;
+ }
+ return value;
+}
+
+type CurrentOpData = {
+ op: string;
+ ns: string;
+ ms_running: number;
+ opid: number;
+ client: string;
+ active: boolean;
+ waitingForLock: boolean;
+};
+
+export function DetailViewComponent() {
+ const [data, setData] = useState(null);
+
+ const track = useTelemetry();
+ const connectionInfoAccess = useConnectionInfoAccess();
+
+ useEffect(() => {
+ const unsubscribeShowOperationDetails = Actions.showOperationDetails.listen(
+ (newDataToShow: CurrentOpData) => {
+ setData(newDataToShow);
+ }
+ );
+ const unsubscribeHideOperationDetails = Actions.hideOperationDetails.listen(
+ () => {
+ setData(null);
+ }
+ );
+
+ return () => {
+ unsubscribeShowOperationDetails();
+ unsubscribeHideOperationDetails();
+ };
+ }, []);
+
+ const hideOperationDetails = useCallback(() => {
+ track(
+ 'DetailView hideOperationDetails',
+ {},
+ connectionInfoAccess.getCurrentConnectionInfo()
+ );
+ Actions.hideOperationDetails();
+ }, [track, connectionInfoAccess]);
+
+ const onKillOp = useCallback(() => {
+ track(
+ 'DetailView killOp',
+ {},
+ connectionInfoAccess.getCurrentConnectionInfo()
+ );
+ if (data?.opid !== undefined) Actions.killOp(data.opid);
+ hideOperationDetails();
+ }, [data, track, hideOperationDetails, connectionInfoAccess]);
+
+ if (!data) {
+ return null;
+ }
+
+ return (
+
+
+
+
+
{data.op}
+
{data.ns}
+
{`${data.ms_running} ms`}
+
+
+
+ {JSON.stringify(data, removeMS, 4)}
+
+
+
+ );
+}
diff --git a/packages/compass-serverstats/src/components/index.tsx b/packages/compass-serverstats/src/components/index.tsx
index 87f9e5e4679..a6757433c2c 100644
--- a/packages/compass-serverstats/src/components/index.tsx
+++ b/packages/compass-serverstats/src/components/index.tsx
@@ -25,6 +25,7 @@ import {
useTrackOnChange,
type TrackFunction,
} from '@mongodb-js/compass-telemetry/provider';
+import { useConnectionInfoAccess } from '@mongodb-js/compass-connections/provider';
const REFRESH_STATS_INTERVAL_MS = 1000;
@@ -118,10 +119,18 @@ function PerformancePanelMsgs() {
*/
function PerformanceComponent() {
const eventDispatcher = useRef(realTimeDispatcher());
-
- useTrackOnChange((track: TrackFunction) => {
- track('Screen', { name: 'performance' });
- }, []);
+ const connectionInfoAccess = useConnectionInfoAccess();
+
+ useTrackOnChange(
+ (track: TrackFunction) => {
+ track(
+ 'Screen',
+ { name: 'performance' },
+ connectionInfoAccess.getCurrentConnectionInfo()
+ );
+ },
+ [connectionInfoAccess]
+ );
useEffect(() => {
return () => {
diff --git a/packages/compass-serverstats/src/components/server-stats-lists-component.jsx b/packages/compass-serverstats/src/components/server-stats-lists-component.jsx
index efdc59a8904..e688f217ddf 100644
--- a/packages/compass-serverstats/src/components/server-stats-lists-component.jsx
+++ b/packages/compass-serverstats/src/components/server-stats-lists-component.jsx
@@ -1,6 +1,6 @@
const React = require('react');
const PropTypes = require('prop-types');
-const DetailViewComponent = require('./detailview-component');
+const { DetailViewComponent } = require('./detailview-component');
const CurrentOpComponent = require('./current-op-component');
const TopComponent = require('./top-component');
const CurrentOpStore = require('../stores/current-op-store');
diff --git a/packages/compass-serverstats/src/components/server-stats-toolbar.tsx b/packages/compass-serverstats/src/components/server-stats-toolbar.tsx
index 24dd265e705..8ea26d269fa 100644
--- a/packages/compass-serverstats/src/components/server-stats-toolbar.tsx
+++ b/packages/compass-serverstats/src/components/server-stats-toolbar.tsx
@@ -13,6 +13,7 @@ import { useTelemetry } from '@mongodb-js/compass-telemetry/provider';
import Actions from '../actions';
import ServerStatsStore from '../stores/server-stats-graphs-store';
+import { useConnectionInfoAccess } from '@mongodb-js/compass-connections/provider';
const serverStatsToolbarStyles = css({
display: 'flex',
@@ -57,6 +58,7 @@ type ServerStatsToolbarProps = {
function ServerStatsToolbar({ eventDispatcher }: ServerStatsToolbarProps) {
const track = useTelemetry();
+ const connectionInfoAccess = useConnectionInfoAccess();
const darkMode = useDarkMode();
const [time, setTime] = useState('00:00:00');
@@ -71,14 +73,15 @@ function ServerStatsToolbar({ eventDispatcher }: ServerStatsToolbarProps) {
}, [eventDispatcher]);
const onPlayPauseClicked = useCallback(() => {
+ const connectionInfo = connectionInfoAccess.getCurrentConnectionInfo();
if (isPaused) {
- track('Performance Resumed');
+ track('Performance Resumed', {}, connectionInfo);
} else {
- track('Performance Paused');
+ track('Performance Paused', {}, connectionInfo);
}
setPaused(!isPaused);
Actions.pause();
- }, [isPaused, track]);
+ }, [isPaused, track, connectionInfoAccess]);
return (
undefined}
runtime={fakeRuntime}
- emitShellPluginOpened={emitShellOpenedSpy}
enableShell
/>
);
@@ -49,23 +47,19 @@ describe('CompassShell', function () {
getComputedStyle(shellDomNode).getPropertyValue('display');
expect(shellDisplayStyle).to.equal('none');
});
-
- context('when is it expanded', function () {
- it('calls the function prop emitShellPluginOpened', function () {
- expect(emitShellOpenedSpy.calledOnce).to.equal(false);
-
- wrapper.setState({ height: 300 });
- wrapper.update();
-
- expect(emitShellOpenedSpy.calledOnce).to.equal(true);
- });
- });
});
context('when rendered expanded', function () {
context('when runtime property is not present', function () {
it('does not render a shell if runtime is null', function () {
- const wrapper = mount(
);
+ const wrapper = mount(
+
undefined}
+ runtime={null}
+ enableShell
+ />
+ );
try {
wrapper.setState({ height: 300 });
wrapper.update();
@@ -82,8 +76,9 @@ describe('CompassShell', function () {
beforeEach(function () {
wrapper = mount(
undefined}
runtime={fakeRuntime}
- emitShellPluginOpened={() => {}}
enableShell
/>
);
@@ -128,8 +123,9 @@ describe('CompassShell', function () {
it('renders the inital output', function () {
const wrapper = mount(
undefined}
runtime={fakeRuntime}
- emitShellPluginOpened={() => {}}
shellOutput={[
{
type: 'output',
@@ -159,7 +155,12 @@ describe('CompassShell', function () {
context('when historyStorage is not present', function () {
it('passes an empty history to the Shell', function () {
const wrapper = shallow(
-
+ undefined}
+ runtime={fakeRuntime}
+ enableShell
+ />
);
expect(wrapper.find(Shell).prop('initialHistory')).to.deep.equal([]);
@@ -174,8 +175,9 @@ describe('CompassShell', function () {
beforeEach(function () {
wrapper = mount(
undefined}
runtime={fakeRuntime}
- emitShellPluginOpened={() => {}}
enableShell
/>
);
@@ -221,22 +223,14 @@ describe('CompassShell', function () {
});
context('when historyStorage is present', function () {
- let fakeStorage;
-
- beforeEach(function () {
- fakeStorage = {
- load: sinon.spy(() => Promise.resolve([])),
- save: sinon.spy(() => Promise.resolve()),
- };
- });
+ const history = ['line1'];
it('passes the loaded history as initialHistory to Shell', async function () {
- fakeStorage.load = sinon.spy(() => Promise.resolve(['line1']));
-
const wrapper = shallow(
undefined}
enableShell
/>
);
@@ -251,10 +245,13 @@ describe('CompassShell', function () {
});
it('saves the history when history changes', async function () {
+ const changeSpy = sinon.spy();
+
const wrapper = shallow(
);
@@ -264,7 +261,7 @@ describe('CompassShell', function () {
const onHistoryChanged = wrapper.find(Shell).prop('onHistoryChanged');
onHistoryChanged(['line1']);
- expect(fakeStorage.save.calledWith(['line1'])).to.equal(true);
+ expect(changeSpy).to.have.been.calledOnceWith(['line1']);
wrapper.unmount();
});
@@ -291,22 +288,20 @@ describe('CompassShell', function () {
});
context('resize actions', function () {
- let onOpenShellSpy;
let wrapper;
beforeEach(function () {
- onOpenShellSpy = sinon.spy();
wrapper = mount(
undefined}
runtime={fakeRuntime}
- emitShellPluginOpened={onOpenShellSpy}
enableShell
/>
);
});
afterEach(function () {
wrapper.unmount();
- onOpenShellSpy = null;
wrapper = null;
});
@@ -379,10 +374,6 @@ describe('CompassShell', function () {
expect(shellDisplayStyle).to.equal('none');
});
- it('does not calls the function prop emitShellPluginOpened', function () {
- expect(onOpenShellSpy.called).to.equal(false);
- });
-
context('when it hits the resize threshold', function () {
beforeEach(function () {
wrapper.setState({ height: 151 });
@@ -395,10 +386,6 @@ describe('CompassShell', function () {
).to.equal(151);
expect(wrapper.state('height')).to.equal(151);
});
-
- it('calls the function prop emitShellPluginOpened', function () {
- expect(onOpenShellSpy.calledOnce).to.equal(true);
- });
});
});
});
diff --git a/packages/compass-shell/src/components/compass-shell/compass-shell.tsx b/packages/compass-shell/src/components/compass-shell/compass-shell.tsx
index 5037f9bfa5d..faac5612b9e 100644
--- a/packages/compass-shell/src/components/compass-shell/compass-shell.tsx
+++ b/packages/compass-shell/src/components/compass-shell/compass-shell.tsx
@@ -1,13 +1,7 @@
import React, { Component, Fragment } from 'react';
-import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { withPreferences } from 'compass-preferences-model/provider';
-import type { Shell as ShellType } from '@mongosh/browser-repl';
-
-// The browser-repl package.json defines exports['.'].require but not .module, hence require() instead of import
-const { Shell } =
- // eslint-disable-next-line @typescript-eslint/no-var-requires, @typescript-eslint/consistent-type-imports
- require('@mongosh/browser-repl') as typeof import('@mongosh/browser-repl');
+import { Shell } from '@mongosh/browser-repl';
import {
ResizeHandle,
ResizeDirection,
@@ -16,12 +10,11 @@ import {
getScrollbarStyles,
palette,
} from '@mongodb-js/compass-components';
-
import ShellInfoModal from '../shell-info-modal';
import ShellHeader from '../shell-header';
import type { WorkerRuntime } from '@mongosh/node-runtime-worker-thread';
-import type { HistoryStorage } from '../../modules/history-storage';
-import type { RootState } from '../../modules';
+import type { RootState } from '../../stores/store';
+import { saveHistory, selectRuntimeById } from '../../stores/store';
const compassShellStyles = css(
{
@@ -63,42 +56,34 @@ function boundShellHeight(attemptedHeight: number): number {
}
export interface CompassShellProps {
- emitShellPluginOpened?: () => void;
runtime: WorkerRuntime | null;
shellOutput?: ShellOutputEntry[];
- historyStorage?: HistoryStorage;
enableShell: boolean;
+ initialHistory: string[] | null;
+ onHistoryChange: (history: string[]) => void;
}
interface CompassShellState {
height: number;
prevHeight: number;
- initialHistory: string[] | null;
isOperationInProgress: boolean;
showInfoModal: boolean;
}
-type ShellOutputEntry = ShellType['state']['output'][number];
+type ShellProps = React.ComponentProps;
+
+type ShellRef = Extract['ref'], { current: any }>;
+
+type ShellOutputEntry = Required['initialOutput'][number];
export class CompassShell extends Component<
CompassShellProps,
CompassShellState
> {
- static propTypes = {
- emitShellPluginOpened: PropTypes.func,
- runtime: PropTypes.object,
- shellOutput: PropTypes.array,
- historyStorage: PropTypes.object,
- enableShell: PropTypes.bool,
- };
-
- shellRef = React.createRef();
+ shellRef: ShellRef = React.createRef();
shellOutput: readonly ShellOutputEntry[];
static defaultProps = {
- emitShellPluginOpened: () => {
- /* ignore */
- },
runtime: null,
};
constructor(props: CompassShellProps) {
@@ -109,34 +94,11 @@ export class CompassShell extends Component<
this.state = {
height: shellHeightClosed,
prevHeight: defaultShellHeightOpened,
- initialHistory: this.props.historyStorage ? null : [],
isOperationInProgress: false,
showInfoModal: false,
};
}
- componentDidMount() {
- void this.loadHistory();
- window.addEventListener('beforeunload', this.terminateRuntime);
- }
-
- componentDidUpdate(
- prevProps: CompassShellProps,
- prevState: CompassShellState
- ) {
- const { height } = this.state;
- if (
- prevState.height < shellMinHeightOpened &&
- height > shellMinHeightOpened
- ) {
- this.props.emitShellPluginOpened?.();
- }
- }
-
- componentWillUnmount() {
- window.removeEventListener('beforeunload', this.terminateRuntime);
- }
-
onShellOutputChanged = (output: readonly ShellOutputEntry[]) => {
this.shellOutput = output;
};
@@ -159,40 +121,6 @@ export class CompassShell extends Component<
}
};
- saveHistory = (history: readonly string[]) => {
- void (async () => {
- if (!this.props.historyStorage) {
- return;
- }
-
- try {
- await this.props.historyStorage.save([...history]);
- } catch (error) {
- // eslint-disable-next-line no-console
- console.error(error);
- }
- })();
- };
-
- loadHistory = async () => {
- if (!this.props.historyStorage) {
- return;
- }
-
- try {
- const history = await this.props.historyStorage.load();
- this.setState({
- initialHistory: history,
- });
- } catch (error) {
- // eslint-disable-next-line no-console
- console.error(error);
- this.setState({
- initialHistory: [],
- });
- }
- };
-
updateHeight(height: number) {
if (height > shellMinHeightOpened) {
this.setState({
@@ -214,16 +142,10 @@ export class CompassShell extends Component<
focusEditor() {
if (this.shellRef.current && window.getSelection()?.type !== 'Range') {
- (this.shellRef.current as any) /* private ... */
- .focusEditor();
+ this.shellRef.current.focusEditor();
}
}
- /**
- * Render CompassShell component.
- *
- * @returns {React.Component} The rendered component.
- */
render() {
const { height, prevHeight, isOperationInProgress, showInfoModal } =
this.state;
@@ -231,7 +153,7 @@ export class CompassShell extends Component<
if (
!this.props.enableShell ||
!this.props.runtime ||
- !this.state.initialHistory
+ !this.props.initialHistory
) {
return ;
}
@@ -288,9 +210,11 @@ export class CompassShell extends Component<
{
+ this.props.onHistoryChange([...history]);
+ }}
onOutputChanged={this.onShellOutputChanged}
onOperationStarted={this.onOperationStarted}
onOperationEnd={this.onOperationEnd}
@@ -302,9 +226,12 @@ export class CompassShell extends Component<
}
}
-export default connect((state: RootState) => ({
- emitShellPluginOpened: () => {
- state.runtime.appRegistry?.emit('compass:compass-shell:opened');
+export default connect(
+ (state: RootState) => {
+ return {
+ runtime: selectRuntimeById(state),
+ initialHistory: state.history,
+ };
},
- runtime: state.runtime ? state.runtime.runtime : null,
-}))(withPreferences(CompassShell, ['enableShell']));
+ { onHistoryChange: saveHistory }
+)(withPreferences(CompassShell, ['enableShell']));
diff --git a/packages/compass-shell/src/components/compass-shell/tab-compass-shell.tsx b/packages/compass-shell/src/components/compass-shell/tab-compass-shell.tsx
index 47688bf22bf..04f0d9463f0 100644
--- a/packages/compass-shell/src/components/compass-shell/tab-compass-shell.tsx
+++ b/packages/compass-shell/src/components/compass-shell/tab-compass-shell.tsx
@@ -1,28 +1,25 @@
import { connect } from 'react-redux';
import React, { useCallback, useEffect, useRef, useState } from 'react';
-import { useTabState } from '@mongodb-js/compass-workspaces/provider';
+import {
+ useOnTabReplace,
+ useTabState,
+} from '@mongodb-js/compass-workspaces/provider';
import {
Banner,
Link,
css,
getScrollbarStyles,
palette,
+ rafraf,
spacing,
} from '@mongodb-js/compass-components';
-import type { MapStateToProps } from 'react-redux';
-import type { Shell as ShellType } from '@mongosh/browser-repl';
import type { WorkerRuntime } from '@mongosh/node-runtime-worker-thread';
-
import ShellInfoModal from '../shell-info-modal';
import ShellHeader from '../shell-header/shell-header';
-import type { HistoryStorage } from '../../modules/history-storage';
-import type { RootState } from '../../modules';
import { usePreference } from 'compass-preferences-model/provider';
-
-// The browser-repl package.json defines exports['.'].require but not .module, hence require() instead of import
-const { Shell } =
- // eslint-disable-next-line @typescript-eslint/no-var-requires, @typescript-eslint/consistent-type-imports
- require('@mongosh/browser-repl') as typeof import('@mongosh/browser-repl');
+import { Shell as _Shell } from '@mongosh/browser-repl';
+import type { RootState } from '../../stores/store';
+import { selectRuntimeById, saveHistory } from '../../stores/store';
const compassShellStyles = css(
{
@@ -47,54 +44,88 @@ const compassShellContainerStyles = css({
borderTop: `1px solid ${palette.gray.dark2}`,
});
-type ShellOutputEntry = ShellType['state']['output'][number];
+type ShellProps = React.ComponentProps;
+
+type ShellRef = Extract['ref'], { current: any }>;
+
+type ShellType = ShellRef['current'];
+
+type ShellOutputEntry = Required['initialOutput'][number];
type CompassShellProps = {
runtime: WorkerRuntime | null;
- historyStorage?: HistoryStorage;
- emitShellPluginOpened?(): void;
+ initialHistory: string[] | null;
+ onHistoryChange: (history: string[]) => void;
+ initialEvaluate?: string | string[];
+ initialInput?: string;
};
+function useInitialEval(initialEvaluate?: string | string[]) {
+ const [initialEvalApplied, setInitialEvalApplied] = useTabState(
+ 'initialEvalApplied',
+ false
+ );
+ useEffect(() => {
+ setInitialEvalApplied(true);
+ }, [setInitialEvalApplied]);
+ return initialEvalApplied ? undefined : initialEvaluate;
+}
+
+const Shell = React.forwardRef(function Shell(
+ { initialEvaluate: _initialEvaluate, ...props },
+ ref
+) {
+ const shellRef = useRef(null);
+ const initialEvaluate = useInitialEval(_initialEvaluate);
+ const mergeRef = useCallback(
+ (shell: ShellType | null) => {
+ shellRef.current = shell;
+ if (typeof ref === 'function') {
+ ref(shell);
+ } else if (ref) {
+ ref.current = shell;
+ }
+ },
+ [ref]
+ );
+ useEffect(() => {
+ return rafraf(() => {
+ shellRef.current?.focusEditor();
+ });
+ }, []);
+ return (
+ <_Shell
+ ref={mergeRef}
+ initialEvaluate={initialEvaluate}
+ {...props}
+ >
+ );
+});
+
const CompassShell: React.FC = ({
runtime,
- historyStorage,
- emitShellPluginOpened,
+ initialHistory,
+ onHistoryChange,
+ initialEvaluate,
+ initialInput,
}) => {
const enableShell = usePreference('enableShell');
- const shellRef = useRef(null);
- const emitShellPluginOpenedRef = useRef(emitShellPluginOpened);
- emitShellPluginOpenedRef.current =
- emitShellPluginOpened ??
- (() => {
- // noop
- });
- const historyStorageRef = useRef(historyStorage);
- historyStorageRef.current = historyStorage;
-
+ const shellRef: ShellRef = useRef(null);
const [infoModalVisible, setInfoModalVisible] = useState(false);
const [isOperationInProgress, setIsOperationInProgress] = useState(false);
- const [initialHistory, setInitialHistory] = useState(null);
const [shellOutput, setShellOutput] = useTabState<
readonly ShellOutputEntry[]
>('shellOutput', []);
- useEffect(() => {
- async function loadHistory(historyStorage: HistoryStorage) {
- try {
- const history = await historyStorage.load();
- setInitialHistory(history);
- } catch (error) {
- // eslint-disable-next-line no-console
- console.error(error);
- setInitialHistory([]);
- }
- }
-
- emitShellPluginOpenedRef.current?.();
+ const [shellInput, setShellInput] = useTabState(
+ 'shellInput',
+ initialInput ?? ''
+ );
- if (historyStorageRef.current) {
- void loadHistory(historyStorageRef.current);
- }
- }, []);
+ useOnTabReplace(() => {
+ // Never allow to replace the shell tab to avoid destroying the runtime
+ // unnecessarily
+ return false;
+ });
const showInfoModal = useCallback(() => {
setInfoModalVisible(true);
@@ -106,23 +137,8 @@ const CompassShell: React.FC = ({
const focusEditor = useCallback(() => {
if (shellRef.current && window.getSelection()?.type !== 'Range') {
- shellRef.current['focusEditor']();
+ shellRef.current.focusEditor();
}
- }, [shellRef]);
-
- const saveHistory = useCallback((history: readonly string[]) => {
- void (async (historyStorage: HistoryStorage | undefined) => {
- if (!historyStorage) {
- return;
- }
-
- try {
- await historyStorage.save([...history]);
- } catch (error) {
- // eslint-disable-next-line no-console
- console.error(error);
- }
- })(historyStorageRef.current);
}, []);
const updateShellOutput = useCallback(
@@ -140,6 +156,8 @@ const CompassShell: React.FC = ({
setIsOperationInProgress(false);
}, []);
+ const canRenderShell = enableShell && initialHistory && runtime;
+
if (!enableShell) {
return (
@@ -155,7 +173,7 @@ const CompassShell: React.FC
= ({
);
}
- if (!runtime || !initialHistory) {
+ if (!canRenderShell) {
return ;
}
@@ -185,12 +203,19 @@ const CompassShell: React.FC = ({
{
+ onHistoryChange([...history]);
+ }}
onOperationStarted={notifyOperationStarted}
onOperationEnd={notifyOperationEnd}
+ maxOutputLength={1000}
+ maxHistoryLength={1000}
/>
@@ -198,15 +223,12 @@ const CompassShell: React.FC = ({
);
};
-const mapState: MapStateToProps<
- Pick,
- Pick,
- RootState
-> = (state) => ({
- emitShellPluginOpened() {
- state.runtime.appRegistry?.emit('compass:compass-shell:opened');
+export default connect(
+ (state: RootState) => {
+ return {
+ runtime: selectRuntimeById(state),
+ initialHistory: state.history,
+ };
},
- runtime: state.runtime ? state.runtime.runtime : null,
-});
-
-export default connect(mapState)(CompassShell);
+ { onHistoryChange: saveHistory }
+)(CompassShell);
diff --git a/packages/compass-shell/src/components/shell-header/shell-header.tsx b/packages/compass-shell/src/components/shell-header/shell-header.tsx
index 3ad687c5f4a..dc1855db0f0 100644
--- a/packages/compass-shell/src/components/shell-header/shell-header.tsx
+++ b/packages/compass-shell/src/components/shell-header/shell-header.tsx
@@ -10,7 +10,6 @@ import {
useHotkeys,
} from '@mongodb-js/compass-components';
import React from 'react';
-import PropTypes from 'prop-types';
const shellHeaderStyles = css({
height: spacing[5],
@@ -157,14 +156,6 @@ export const ShellHeader = ({
);
};
-ShellHeader.propTypes = {
- darkMode: PropTypes.bool,
- isExpanded: PropTypes.bool.isRequired,
- isOperationInProgress: PropTypes.bool.isRequired,
- onShellToggleClicked: PropTypes.func.isRequired,
- showInfoModal: PropTypes.func.isRequired,
-};
-
export default withDarkMode(
ShellHeader
) as React.FunctionComponent;
diff --git a/packages/compass-shell/src/components/shell-info-modal/shell-info-modal.tsx b/packages/compass-shell/src/components/shell-info-modal/shell-info-modal.tsx
index 399eb3e154a..e0d00802cc6 100644
--- a/packages/compass-shell/src/components/shell-info-modal/shell-info-modal.tsx
+++ b/packages/compass-shell/src/components/shell-info-modal/shell-info-modal.tsx
@@ -1,4 +1,3 @@
-import PropTypes from 'prop-types';
import React, { useCallback } from 'react';
import {
css,
@@ -77,9 +76,4 @@ function ShellInfoModal({
);
}
-ShellInfoModal.propTypes = {
- hideInfoModal: PropTypes.func.isRequired,
- show: PropTypes.bool.isRequired,
-};
-
export default ShellInfoModal;
diff --git a/packages/compass-shell/src/index.ts b/packages/compass-shell/src/index.ts
index 87353600fbf..dd0d732b248 100644
--- a/packages/compass-shell/src/index.ts
+++ b/packages/compass-shell/src/index.ts
@@ -1,28 +1,17 @@
-import type { Logger } from '@mongodb-js/compass-logging/provider';
import { createLoggerLocator } from '@mongodb-js/compass-logging/provider';
-import { createTelemetryLocator } from '@mongodb-js/compass-telemetry/provider';
+import { telemetryLocator } from '@mongodb-js/compass-telemetry/provider';
import { ShellPlugin, onActivated } from './plugin';
import { registerHadronPlugin } from 'hadron-app-registry';
+import { preferencesLocator } from 'compass-preferences-model/provider';
+import { type WorkspaceComponent } from '@mongodb-js/compass-workspaces';
import {
dataServiceLocator,
type DataService,
+ connectionInfoAccessLocator,
+ type DataServiceLocator,
} from '@mongodb-js/compass-connections/provider';
-import {
- preferencesLocator,
- type PreferencesAccess,
-} from 'compass-preferences-model/provider';
-import { type WorkspaceComponent } from '@mongodb-js/compass-workspaces';
-import type { TrackFunction } from '@mongodb-js/compass-telemetry';
-export const CompassShellPlugin = registerHadronPlugin<
- unknown,
- {
- logger: () => Logger;
- track: () => TrackFunction;
- dataService: () => DataService;
- preferences: () => PreferencesAccess;
- }
->(
+export const CompassShellPlugin = registerHadronPlugin(
{
name: 'CompassShell',
component: ShellPlugin,
@@ -30,8 +19,9 @@ export const CompassShellPlugin = registerHadronPlugin<
},
{
logger: createLoggerLocator('COMPASS-SHELL'),
- track: createTelemetryLocator(),
- dataService: dataServiceLocator,
+ track: telemetryLocator,
+ dataService: dataServiceLocator as DataServiceLocator,
+ connectionInfo: connectionInfoAccessLocator,
preferences: preferencesLocator,
}
);
diff --git a/packages/compass-shell/src/modules/index.ts b/packages/compass-shell/src/modules/index.ts
deleted file mode 100644
index ee9ea4560d2..00000000000
--- a/packages/compass-shell/src/modules/index.ts
+++ /dev/null
@@ -1,15 +0,0 @@
-import { combineReducers } from 'redux';
-import type { RuntimeAction, RuntimeState } from './runtime';
-import runtime from './runtime';
-
-export interface RootState {
- runtime: RuntimeState;
-}
-
-export type RootAction = RuntimeAction;
-
-const reducer = combineReducers({
- runtime,
-});
-
-export default reducer;
diff --git a/packages/compass-shell/src/modules/runtime.ts b/packages/compass-shell/src/modules/runtime.ts
deleted file mode 100644
index fa52137965c..00000000000
--- a/packages/compass-shell/src/modules/runtime.ts
+++ /dev/null
@@ -1,164 +0,0 @@
-import type { DataService } from '@mongodb-js/compass-connections/provider';
-import { WorkerRuntime } from './worker-runtime';
-import type AppRegistry from 'hadron-app-registry';
-import type { RootAction } from '.';
-
-/**
- * The prefix.
- */
-const PREFIX = 'shell/runtime' as const;
-
-/**
- * Data service connected.
- */
-export const SETUP_RUNTIME = `${PREFIX}/SETUP_RUNTIME` as const;
-type SetupRuntimeAction = {
- type: typeof SETUP_RUNTIME;
- error: Error | null;
- dataService: DataService | null;
- appRegistry: AppRegistry | null;
-};
-
-/**
- * enableShell preference changed.
- */
-export const CHANGE_ENABLE_SHELL = `${PREFIX}/CHANGE_ENABLE_SHELL` as const;
-type ChangeEnableShellAction = {
- type: typeof CHANGE_ENABLE_SHELL;
- enableShell: boolean;
-};
-export type RuntimeAction = SetupRuntimeAction | ChangeEnableShellAction;
-
-/**
- * The initial state.
- */
-export const INITIAL_STATE: RuntimeState = {
- error: null,
- dataService: null,
- runtime: null,
- appRegistry: null,
- enableShell: false,
-};
-
-export interface RuntimeState {
- error: null | Error;
- dataService: null | DataService;
- runtime: null | typeof WorkerRuntime['prototype'];
- appRegistry: null | AppRegistry;
- enableShell: boolean;
-}
-
-/**
- * Reducer function for handling data service connected actions.
- *
- * @param {Object} state - The data service state.
- * @param {Object} action - The action.
- *
- * @returns {String} The new state.
- */
-export default function reducer(
- state: RuntimeState = INITIAL_STATE,
- action: RootAction
-): RuntimeState {
- if (action.type === SETUP_RUNTIME) {
- return reduceSetupRuntime(state, action);
- }
-
- if (action.type === CHANGE_ENABLE_SHELL) {
- return reduceChangeEnableShell(state, action);
- }
-
- return state;
-}
-
-function createOrDestroyRuntimeForState(state: RuntimeState): RuntimeState {
- if (!state.runtime && state.dataService && state.enableShell) {
- return {
- ...state,
- runtime: createWorkerRuntime(state.dataService, state.appRegistry!),
- };
- } else if (state.runtime && (!state.dataService || !state.enableShell)) {
- void state.runtime.terminate();
- return {
- ...state,
- runtime: null,
- };
- }
- return { ...state };
-}
-
-function reduceSetupRuntime(
- state: RuntimeState,
- action: SetupRuntimeAction
-): RuntimeState {
- return createOrDestroyRuntimeForState({
- ...state,
- error: action.error,
- dataService: action.error ? null : action.dataService,
- appRegistry: action.error ? null : action.appRegistry,
- });
-}
-
-function reduceChangeEnableShell(
- state: RuntimeState,
- action: ChangeEnableShellAction
-): RuntimeState {
- return createOrDestroyRuntimeForState({
- ...state,
- enableShell: action.enableShell,
- });
-}
-
-/**
- * Setup the shell runtime with the supplied dataService instance.
- *
- * @param {Error} error - The connection error.
- * @param {DataService} dataService - The data service.
- * @param {EventEmitter} appRegistry - A message bus for runtime events.
- *
- * @returns {Object} The data service connected action.
- */
-export const setupRuntime = (
- error: Error | null,
- dataService: DataService | null,
- appRegistry: AppRegistry | null
-) => ({
- type: SETUP_RUNTIME,
- error,
- dataService,
- appRegistry,
-});
-
-export const changeEnableShell = (
- enableShell: boolean
-): ChangeEnableShellAction => ({
- type: CHANGE_ENABLE_SHELL,
- enableShell,
-});
-
-function createWorkerRuntime(
- dataService: DataService,
- appRegistry: AppRegistry
-): typeof WorkerRuntime['prototype'] {
- const {
- url: driverUrl,
- options: driverOptions,
- // Not really provided by dataService, used only for testing purposes
- cliOptions,
- } = {
- cliOptions: {},
- url: '',
- ...dataService.getMongoClientConnectionOptions(),
- };
-
- return new WorkerRuntime(
- driverUrl,
- driverOptions,
- cliOptions ?? {},
- {
- env: { ...process.env, ELECTRON_RUN_AS_NODE: '1' },
- serialization: 'advanced',
- },
- appRegistry
- );
-}
diff --git a/packages/compass-shell/src/modules/worker-runtime.ts b/packages/compass-shell/src/modules/worker-runtime.ts
index 93eefc2cd4b..ec875d90358 100644
--- a/packages/compass-shell/src/modules/worker-runtime.ts
+++ b/packages/compass-shell/src/modules/worker-runtime.ts
@@ -1,3 +1,12 @@
+import type {
+ ConnectionInfoAccess,
+ DataService,
+} from '@mongodb-js/compass-connections/provider';
+import type { MongoLogWriter } from '@mongodb-js/compass-logging/provider';
+import type { TrackFunction } from '@mongodb-js/compass-telemetry/provider';
+import { setupLoggerAndTelemetry } from '@mongosh/logging';
+import { EventEmitter } from 'events';
+
declare const __webpack_require__: typeof require;
declare const __non_webpack_require__: typeof require;
@@ -34,3 +43,69 @@ const { WorkerRuntime } = (() => {
})() as typeof import('@mongosh/node-runtime-worker-thread');
export { WorkerRuntime };
+
+export function createWorkerRuntime(
+ dataService: DataService,
+ log: MongoLogWriter,
+ track: TrackFunction,
+ connectionInfo: ConnectionInfoAccess
+): typeof WorkerRuntime['prototype'] {
+ const emitter = new EventEmitter();
+
+ setupLoggerAndTelemetry(
+ emitter,
+ log,
+ {
+ identify: () => {
+ /* not needed */
+ },
+ // Prefix Segment events with `Shell ` to avoid event name collisions.
+ // We always enable telemetry here, since the track call will
+ // already check whether Compass telemetry is enabled or not.
+ track: ({ event, properties }) => {
+ return track(
+ `Shell ${event}`,
+ properties,
+ connectionInfo.getCurrentConnectionInfo()
+ );
+ },
+ flush: () => {
+ return Promise.resolve(); // not needed
+ },
+ },
+ {
+ platform: process.platform,
+ arch: process.arch,
+ },
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-var-requires
+ require('../../package.json').version
+ );
+
+ // We also don't need to pass a proper user id, since that is
+ // handled by the Compass tracking code.
+ emitter.emit('mongosh:new-user', '');
+
+ const {
+ url: driverUrl,
+ options: driverOptions,
+ // Not really provided by dataService, used only for testing purposes
+ cliOptions,
+ } = {
+ cliOptions: {},
+ url: '',
+ ...dataService.getMongoClientConnectionOptions(),
+ };
+
+ const runtime = new WorkerRuntime(
+ driverUrl,
+ driverOptions,
+ cliOptions ?? {},
+ {
+ env: { ...process.env, ELECTRON_RUN_AS_NODE: '1' },
+ serialization: 'advanced',
+ },
+ emitter
+ );
+
+ return runtime;
+}
diff --git a/packages/compass-shell/src/plugin.spec.tsx b/packages/compass-shell/src/plugin.spec.tsx
index e1c9841af59..a4e98309ad7 100644
--- a/packages/compass-shell/src/plugin.spec.tsx
+++ b/packages/compass-shell/src/plugin.spec.tsx
@@ -6,7 +6,7 @@ import { expect } from 'chai';
import { CompassShell } from './components/compass-shell';
import { CompassShellPlugin } from './index';
-import { AppRegistryProvider, globalAppRegistry } from 'hadron-app-registry';
+import { AppRegistryProvider } from 'hadron-app-registry';
import {
ConnectionsManager,
ConnectionsManagerProvider,
@@ -51,6 +51,7 @@ describe('CompassShellPlugin', function () {
const connectionsManager = new ConnectionsManager({
logger: createNoopLogger().log.unbound,
});
+
sinon.replace(connectionsManager, 'getDataServiceForConnection', () => {
return fakeDataService;
});
@@ -61,8 +62,9 @@ describe('CompassShellPlugin', function () {
wrapper?.unmount();
wrapper = null;
});
+
it('returns a renderable plugin', async function () {
- (connectionsManager as any).connectionStatuses.set('1', 'connected');
+ connectionsManager['connectionStatuses'].set('1', 'connected');
wrapper = mount(
{/* global */}
@@ -85,40 +87,4 @@ describe('CompassShellPlugin', function () {
expect(component?.exists()).to.equal(true);
});
-
- it('emits an event on the app registry when it is expanded', async function () {
- let eventOccured = false;
- globalAppRegistry.on('compass:compass-shell:opened', () => {
- eventOccured = true;
- });
- (connectionsManager as any).connectionStatuses.set('1', 'connected');
-
- wrapper = mount(
-
- {/* global */}
-
- {/* local */}
-
-
-
-
-
-
-
-
-
- );
-
- const shellComponentWrapper = await waitForAsyncComponent(
- wrapper,
- CompassShell
- );
-
- const { emitShellPluginOpened } = shellComponentWrapper?.props() ?? {};
- emitShellPluginOpened?.();
-
- expect(eventOccured).to.equal(true);
- });
});
diff --git a/packages/compass-shell/src/plugin.tsx b/packages/compass-shell/src/plugin.tsx
index dde2755e21d..24400fe298b 100644
--- a/packages/compass-shell/src/plugin.tsx
+++ b/packages/compass-shell/src/plugin.tsx
@@ -1,91 +1,106 @@
-import React, { useState, useRef, useEffect } from 'react';
-import CompassShellStore from './stores';
+import React from 'react';
+import thunk from 'redux-thunk';
import { HistoryStorage } from './modules/history-storage';
-import type CompassShellComponentType from './components/compass-shell';
-import type AppRegistry from 'hadron-app-registry';
-import {
- createLoggerLocator,
- type Logger,
-} from '@mongodb-js/compass-logging/provider';
-import type { DataService } from '@mongodb-js/compass-connections/provider';
+import { type Logger } from '@mongodb-js/compass-logging/provider';
+import type {
+ ConnectionInfoAccess,
+ DataService,
+} from '@mongodb-js/compass-connections/provider';
import type { PreferencesAccess } from 'compass-preferences-model';
import { usePreference } from 'compass-preferences-model/provider';
import type { TrackFunction } from '@mongodb-js/compass-telemetry';
+import TabShell from './components/compass-shell/tab-compass-shell';
+import Shell from './components/compass-shell/compass-shell';
+import { applyMiddleware, createStore } from 'redux';
+import reducer, {
+ createAndStoreRuntime,
+ createRuntime,
+ destroyCurrentRuntime,
+ loadHistory,
+} from './stores/store';
+import type { ActivateHelpers } from 'hadron-app-registry';
+import { Theme, ThemeProvider } from '@mongodb-js/compass-components';
-export function ShellPlugin() {
+const SHELL_THEME = { theme: Theme.Dark, enabled: true };
+
+type ShellPluginProps = {
+ initialEvaluate?: string | string[];
+ initialInput?: string;
+};
+
+export function ShellPlugin(props: ShellPluginProps) {
const multiConnectionsEnabled = usePreference(
'enableNewMultipleConnectionSystem'
);
- const [ShellComponent, setShellComponent] = useState<
- typeof CompassShellComponentType | null
- >(null);
- const historyStorage = useRef(null);
+ const ShellComponent = multiConnectionsEnabled ? TabShell : Shell;
+ return (
+
+
+
+ );
+}
- if (!historyStorage.current) {
- historyStorage.current = new HistoryStorage();
- }
+export type ShellPluginServices = {
+ logger: Logger;
+ track: TrackFunction;
+ dataService: DataService;
+ preferences: PreferencesAccess;
+ connectionInfo: ConnectionInfoAccess;
+};
- useEffect(() => {
- let mounted = true;
- async function importShellComponent() {
- let component: typeof CompassShellComponentType | null = null;
- try {
- if (multiConnectionsEnabled) {
- component = (
- await import('./components/compass-shell/tab-compass-shell')
- ).default;
- } else {
- component = (await import('./components/compass-shell/compass-shell'))
- .default;
- }
- } finally {
- if (mounted) {
- setShellComponent(component);
- }
- }
- }
+export type ShellPluginExtraArgs = ShellPluginServices & {
+ historyStorage: HistoryStorage;
+};
- void importShellComponent();
+export function onActivated(
+ _initialProps: ShellPluginProps,
+ services: ShellPluginServices,
+ { addCleanup, cleanup }: ActivateHelpers
+) {
+ const { preferences, dataService, logger, track, connectionInfo } = services;
- return () => {
- mounted = false;
- };
- }, [multiConnectionsEnabled]);
+ const store = createStore(
+ reducer,
+ {
+ runtimeId: preferences.getPreferences().enableShell
+ ? createAndStoreRuntime(dataService, logger, track, connectionInfo).id
+ : null,
+ history: null,
+ },
+ applyMiddleware(
+ thunk.withExtraArgument({
+ ...services,
+ historyStorage: new HistoryStorage(),
+ })
+ )
+ );
- if (ShellComponent) {
- return ;
- }
+ setTimeout(() => {
+ void store.dispatch(loadHistory());
+ });
- return null;
-}
+ addCleanup(
+ preferences.onPreferenceValueChanged('enableShell', (enabled) => {
+ if (enabled) {
+ store.dispatch(createRuntime());
+ } else {
+ store.dispatch(destroyCurrentRuntime());
+ }
+ })
+ );
-export function onActivated(
- _: unknown,
- {
- globalAppRegistry,
- logger,
- track,
- dataService,
- preferences,
- }: {
- globalAppRegistry: AppRegistry;
- logger: Logger;
- track: TrackFunction;
- dataService: DataService;
- preferences: PreferencesAccess;
+ function destroyRuntime() {
+ store.dispatch(destroyCurrentRuntime());
}
-) {
- const store = new CompassShellStore();
- const deactivate = store.onActivated({
- globalAppRegistry,
- logger,
- track,
- dataService,
- preferences,
+
+ addCleanup(destroyRuntime);
+
+ // Trigger terminate when page unloads to kill the spawned child process
+ window.addEventListener('beforeunload', destroyRuntime);
+
+ addCleanup(() => {
+ window.removeEventListener('beforeunload', destroyRuntime);
});
- return {
- store: store.reduxStore,
- deactivate,
- logger: createLoggerLocator('COMPASS-SHELL'),
- };
+
+ return { store, deactivate: cleanup };
}
diff --git a/packages/compass-shell/src/stores/index.ts b/packages/compass-shell/src/stores/index.ts
deleted file mode 100644
index f44c9f34f50..00000000000
--- a/packages/compass-shell/src/stores/index.ts
+++ /dev/null
@@ -1,4 +0,0 @@
-import CompassShellStore from './store';
-
-export default CompassShellStore;
-export { CompassShellStore };
diff --git a/packages/compass-shell/src/stores/store.spec.ts b/packages/compass-shell/src/stores/store.spec.ts
deleted file mode 100644
index 4966df1d300..00000000000
--- a/packages/compass-shell/src/stores/store.spec.ts
+++ /dev/null
@@ -1,105 +0,0 @@
-import { EventEmitter } from 'events';
-import { expect } from 'chai';
-
-import { WorkerRuntime } from '../modules/worker-runtime';
-import CompassShellStore from './';
-import { createNoopLogger } from '@mongodb-js/compass-logging/provider';
-import { createSandboxFromDefaultPreferences } from 'compass-preferences-model';
-
-function createMockDataService() {
- return {
- getMongoClientConnectionOptions() {
- return {
- url: 'mongodb://nodb/',
- options: {},
- cliOptions: { nodb: true },
- };
- },
- };
-}
-
-describe('CompassShellStore [Store]', function () {
- let store: CompassShellStore;
- let appRegistry: EventEmitter;
- let deactivate: () => void;
-
- const getRuntimeState = () => store.reduxStore.getState().runtime;
-
- beforeEach(async function () {
- store = new CompassShellStore();
- appRegistry = new EventEmitter();
- deactivate = store.onActivated({
- globalAppRegistry: appRegistry,
- logger: createNoopLogger('COMPASS-SHELL'),
- dataService: createMockDataService(),
- preferences: await createSandboxFromDefaultPreferences(),
- } as any);
- });
-
- afterEach(async function () {
- const { runtime } = getRuntimeState();
-
- await runtime?.terminate();
- });
-
- describe('appRegistry', function () {
- it('sets the global appRegistry', function () {
- expect(store.reduxStore.getState().runtime.appRegistry).to.not.equal(
- null
- );
- expect(store.reduxStore.getState().runtime.appRegistry).to.be.instanceOf(
- EventEmitter
- );
- });
- });
-
- describe('runtime', function () {
- it('sets runtime on data-service-connected', function () {
- let runtimeState = getRuntimeState();
-
- expect(runtimeState.error).to.equal(null);
- expect(runtimeState.runtime).to.be.instanceOf(WorkerRuntime);
-
- store.onEnableShellChanged(false);
- runtimeState = getRuntimeState();
-
- expect(runtimeState.error).to.equal(null);
- expect(runtimeState.runtime).to.equal(null);
- });
-
- it('emits mongosh events to the appRegistry', async function () {
- store.onEnableShellChanged(true);
- let eventReceived = false;
- appRegistry.on('mongosh:setCtx', () => {
- eventReceived = true;
- });
-
- const runtimeState = getRuntimeState();
-
- // Any command will do, just making sure we waited for the runtime to
- // become available
- await runtimeState.runtime?.evaluate('help');
-
- expect(eventReceived).to.equal(true);
- });
-
- it('does not change state if dataService is the same', function () {
- const fakeDataService = createMockDataService();
-
- appRegistry.emit('data-service-connected', null, fakeDataService);
- const runtimeState1 = getRuntimeState();
-
- appRegistry.emit('data-service-connected', null, fakeDataService);
- const runtimeState2 = getRuntimeState();
-
- expect(runtimeState1).to.deep.equal(runtimeState2);
- });
-
- it('resets the runtime on deactivate', function () {
- deactivate();
- const runtimeState = getRuntimeState();
-
- expect(runtimeState.runtime).to.equal(null);
- });
- });
-});
diff --git a/packages/compass-shell/src/stores/store.ts b/packages/compass-shell/src/stores/store.ts
index a1166ffbe0a..f4c60a52abd 100644
--- a/packages/compass-shell/src/stores/store.ts
+++ b/packages/compass-shell/src/stores/store.ts
@@ -1,87 +1,164 @@
-import type { Store } from 'redux';
-import { createStore } from 'redux';
-import type { RootAction, RootState } from '../modules';
-import reducer from '../modules';
-import { changeEnableShell, setupRuntime } from '../modules/runtime';
-import { setupLoggerAndTelemetry } from '@mongosh/logging';
-import type { Logger } from '@mongodb-js/compass-logging/provider';
-import type { PreferencesAccess } from 'compass-preferences-model';
-import type AppRegistry from 'hadron-app-registry';
-import type { DataService } from '@mongodb-js/compass-connections/provider';
-import type { TrackFunction } from '@mongodb-js/compass-telemetry';
-
-export default class CompassShellStore {
- reduxStore: Store;
-
- constructor() {
- this.reduxStore = createStore(reducer);
- }
+import type { Reducer } from 'redux';
+import type { AnyAction } from 'redux';
+import type { ThunkAction } from 'redux-thunk';
+import type { WorkerRuntime } from '@mongosh/node-runtime-worker-thread';
+import { ObjectId } from 'bson';
+import { createWorkerRuntime } from '../modules/worker-runtime';
+import type { ShellPluginExtraArgs } from '../plugin';
- globalAppRegistry: AppRegistry | null = null;
- preferences: PreferencesAccess | null = null;
+const RuntimeMap = new Map();
- onActivated({
- globalAppRegistry,
- logger: { log, debug },
- track,
- dataService,
- preferences,
- }: {
- globalAppRegistry: AppRegistry;
- logger: Logger;
- track: TrackFunction;
- dataService: DataService;
- preferences: PreferencesAccess;
- }): () => void {
- debug('activated');
-
- this.globalAppRegistry = globalAppRegistry;
- this.preferences = preferences;
-
- const unsubscribePreference = preferences.onPreferenceValueChanged(
- 'enableShell',
- this.onEnableShellChanged
- );
- this.onEnableShellChanged(preferences.getPreferences().enableShell);
-
- setupLoggerAndTelemetry(
- globalAppRegistry,
- log.unbound,
- {
- identify: () => {
- /* not needed */
- },
- // Prefix Segment events with `Shell ` to avoid event name collisions.
- // We always enable telemetry here, since the track call will
- // already check whether Compass telemetry is enabled or not.
- track: ({ event, properties }) => track(`Shell ${event}`, properties),
- flush: () => {
- return Promise.resolve(); // not needed
- },
- },
- {
- platform: process.platform,
- arch: process.arch,
- },
- // eslint-disable-next-line @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-var-requires
- require('../../package.json').version
- );
- // We also don't need to pass a proper user id, since that is
- // handled by the Compass tracking code.
- globalAppRegistry.emit('mongosh:new-user', '');
+type State = {
+ // Reference to the shell runtime stored by id
+ runtimeId: string | null;
+ history: string[] | null;
+};
- // Set the global app registry in the store.
- this.reduxStore.dispatch(
- setupRuntime(null, dataService, this.globalAppRegistry)
- );
+type ShellPluginThunkAction = ThunkAction<
+ R,
+ State,
+ ShellPluginExtraArgs,
+ A
+>;
+
+enum ActionTypes {
+ RuntimeCreated = 'compass-shell/RuntimeCreated',
+ RuntimeDestroyed = 'compass-shell/RuntimeDestroyed',
+ HistoryLoaded = 'compass-shell/HistoryLoaded',
+ HistorySaved = 'compass-shell/HistorySaved',
+}
+
+type RuntimeCreatedAction = { type: ActionTypes.RuntimeCreated; id: string };
+
+type RuntimeDestroyedAction = { type: ActionTypes.RuntimeDestroyed };
- return () => {
- unsubscribePreference();
- this.reduxStore.dispatch(setupRuntime(null, null, null));
+type HistoryLoadedAction = {
+ type: ActionTypes.HistoryLoaded;
+ history: string[];
+};
+
+type HistorySavedAction = {
+ type: ActionTypes.HistorySaved;
+ history: string[];
+};
+
+export function isAction(
+ action: AnyAction,
+ type: A['type']
+): action is A {
+ return action.type === type;
+}
+
+const reducer: Reducer = (
+ state = { runtimeId: null, history: null },
+ action
+) => {
+ if (isAction(action, ActionTypes.RuntimeCreated)) {
+ return {
+ ...state,
+ runtimeId: action.id,
};
}
+ if (isAction(action, ActionTypes.RuntimeDestroyed)) {
+ return {
+ ...state,
+ runtimeId: null,
+ };
+ }
+ if (isAction(action, ActionTypes.HistoryLoaded)) {
+ return {
+ ...state,
+ history: action.history,
+ };
+ }
+ if (isAction(action, ActionTypes.HistorySaved)) {
+ return {
+ ...state,
+ history: action.history,
+ };
+ }
+ return state;
+};
+
+export function createAndStoreRuntime(
+ dataService: ShellPluginExtraArgs['dataService'],
+ { log }: ShellPluginExtraArgs['logger'],
+ track: ShellPluginExtraArgs['track'],
+ connectionInfo: ShellPluginExtraArgs['connectionInfo']
+) {
+ const id = new ObjectId().toString();
+ const runtime = createWorkerRuntime(
+ dataService,
+ log.unbound,
+ track,
+ connectionInfo
+ );
+ RuntimeMap.set(id, runtime);
+ return { id, runtime };
+}
+
+export function createRuntime(): ShellPluginThunkAction<
+ void,
+ RuntimeCreatedAction
+> {
+ return (
+ dispatch,
+ getState,
+ { dataService, logger, track, connectionInfo }
+ ) => {
+ // Do not allow to re-create runtime multiple times if it already exists
+ if (RuntimeMap.get(getState().runtimeId ?? '')) {
+ return;
+ }
+ const { id } = createAndStoreRuntime(
+ dataService,
+ logger,
+ track,
+ connectionInfo
+ );
+ dispatch({ type: ActionTypes.RuntimeCreated, id });
+ };
+}
- onEnableShellChanged = (value: boolean) => {
- this.reduxStore.dispatch(changeEnableShell(value));
+export function destroyCurrentRuntime(): ShellPluginThunkAction<
+ void,
+ RuntimeDestroyedAction
+> {
+ return (dispatch, getState) => {
+ const id = getState().runtimeId ?? '';
+ const runtime = RuntimeMap.get(id);
+ runtime?.['eventEmitter'].removeAllListeners();
+ void runtime?.terminate();
+ RuntimeMap.delete(id);
+ dispatch({ type: ActionTypes.RuntimeDestroyed });
};
}
+
+export function loadHistory(): ShellPluginThunkAction<
+ Promise,
+ HistoryLoadedAction
+> {
+ return async (dispatch, _getState, { historyStorage }) => {
+ const history = await historyStorage.load();
+ dispatch({ type: ActionTypes.HistoryLoaded, history });
+ };
+}
+
+export function saveHistory(
+ newHistory: string[]
+): ShellPluginThunkAction {
+ return (dispatch, _getState, { historyStorage }) => {
+ void historyStorage.save(newHistory).catch(() => {
+ // ignore saving errors
+ });
+ dispatch({ type: ActionTypes.HistorySaved, history: newHistory });
+ };
+}
+
+export const selectRuntimeById = (state: State) => {
+ return RuntimeMap.get(state.runtimeId ?? '') ?? null;
+};
+
+export type RootState = State;
+
+export default reducer;
diff --git a/packages/compass-sidebar/package.json b/packages/compass-sidebar/package.json
index 85a4ec784f8..529f974a273 100644
--- a/packages/compass-sidebar/package.json
+++ b/packages/compass-sidebar/package.json
@@ -11,7 +11,7 @@
"email": "compass@mongodb.com"
},
"homepage": "https://github.com/mongodb-js/compass",
- "version": "5.33.0",
+ "version": "5.36.0",
"repository": {
"type": "git",
"url": "https://github.com/mongodb-js/compass.git"
@@ -48,23 +48,23 @@
"reformat": "npm run eslint . -- --fix && npm run prettier -- --write ."
},
"dependencies": {
- "@mongodb-js/compass-app-stores": "^7.19.0",
- "@mongodb-js/compass-components": "^1.26.0",
- "@mongodb-js/compass-connection-import-export": "^0.29.0",
- "@mongodb-js/compass-connections": "^1.33.0",
- "@mongodb-js/compass-connections-navigation": "^1.32.0",
- "@mongodb-js/compass-logging": "^1.3.1",
- "@mongodb-js/compass-maybe-protect-connection-string": "^0.21.1",
- "@mongodb-js/compass-telemetry": "^1.0.1",
- "@mongodb-js/compass-workspaces": "^0.14.0",
- "@mongodb-js/connection-form": "^1.31.0",
- "@mongodb-js/connection-info": "^0.4.1",
- "compass-preferences-model": "^2.23.1",
- "hadron-app-registry": "^9.1.12",
+ "@mongodb-js/compass-app-stores": "^7.22.0",
+ "@mongodb-js/compass-components": "^1.28.0",
+ "@mongodb-js/compass-connection-import-export": "^0.32.0",
+ "@mongodb-js/compass-connections": "^1.36.0",
+ "@mongodb-js/compass-connections-navigation": "^1.35.0",
+ "@mongodb-js/compass-logging": "^1.4.1",
+ "@mongodb-js/compass-maybe-protect-connection-string": "^0.23.0",
+ "@mongodb-js/compass-telemetry": "^1.1.1",
+ "@mongodb-js/compass-workspaces": "^0.17.0",
+ "@mongodb-js/connection-form": "^1.34.0",
+ "@mongodb-js/connection-info": "^0.5.1",
+ "compass-preferences-model": "^2.25.0",
+ "hadron-app-registry": "^9.2.1",
"lodash": "^4.17.21",
"mongodb": "^6.7.0",
"mongodb-build-info": "^1.7.2",
- "mongodb-instance-model": "^12.22.1",
+ "mongodb-instance-model": "^12.23.1",
"mongodb-ns": "^2.4.2",
"react": "^17.0.2",
"react-redux": "^8.1.3",
@@ -72,8 +72,8 @@
"redux-thunk": "^2.4.2"
},
"devDependencies": {
- "@mongodb-js/connection-storage": "^0.14.1",
- "@mongodb-js/eslint-config-compass": "^1.1.2",
+ "@mongodb-js/connection-storage": "^0.16.0",
+ "@mongodb-js/eslint-config-compass": "^1.1.3",
"@mongodb-js/mocha-config-compass": "^1.3.9",
"@mongodb-js/prettier-config-compass": "^1.0.2",
"@mongodb-js/tsconfig-compass": "^1.0.4",
@@ -91,7 +91,7 @@
"electron-mocha": "^12.2.0",
"eslint": "^7.25.0",
"mocha": "^10.2.0",
- "mongodb-data-service": "^22.21.1",
+ "mongodb-data-service": "^22.22.1",
"nyc": "^15.1.0",
"prettier": "^2.7.1",
"react-dom": "^17.0.2",
diff --git a/packages/compass-sidebar/src/components/legacy/sidebar-databases-navigation.tsx b/packages/compass-sidebar/src/components/legacy/sidebar-databases-navigation.tsx
index 71599f848f0..1746cea22ad 100644
--- a/packages/compass-sidebar/src/components/legacy/sidebar-databases-navigation.tsx
+++ b/packages/compass-sidebar/src/components/legacy/sidebar-databases-navigation.tsx
@@ -52,7 +52,8 @@ const filterDatabases = (
results.push({
...db,
isMatch,
- collections: childMatches.length ? childMatches : db.collections,
+ collections:
+ !isMatch && childMatches.length ? childMatches : db.collections,
});
}
}
@@ -115,7 +116,7 @@ type MapStateProps = {
};
type MapDispatchProps = {
- fetchAllCollections(): void;
+ fetchAllCollections(connectionId: string): void;
onNamespaceAction(
connectionId: string,
namespace: string,
@@ -219,7 +220,7 @@ function SidebarDatabasesNavigation({
// When filtering, emit an event so that we can fetch all collections. This
// is required as a workaround for the synchronous nature of the current
// filtering feature
- _fetchAllCollections();
+ _fetchAllCollections(connectionId);
const results = filterDatabases(
databasesButOnlyIfFilterIsActive,
@@ -229,6 +230,7 @@ function SidebarDatabasesNavigation({
temporarilyExpand(results);
}
}, [
+ connectionId,
filterRegex,
databasesButOnlyIfFilterIsActive,
setFilteredDatabases,
diff --git a/packages/compass-sidebar/src/components/legacy/sidebar.tsx b/packages/compass-sidebar/src/components/legacy/sidebar.tsx
index eba38f4e10c..4a1179c047a 100644
--- a/packages/compass-sidebar/src/components/legacy/sidebar.tsx
+++ b/packages/compass-sidebar/src/components/legacy/sidebar.tsx
@@ -150,6 +150,13 @@ export function Sidebar({
return;
}
+ if (action === 'refresh-databases') {
+ onSidebarAction(action, ...rest, {
+ connectionId: initialConnectionInfo.id,
+ });
+ return;
+ }
+
onSidebarAction(action, ...rest);
},
[
diff --git a/packages/compass-sidebar/src/components/multiple-connections/connections-navigation.tsx b/packages/compass-sidebar/src/components/multiple-connections/connections-navigation.tsx
index f599bf4a9a1..69c81896a3c 100644
--- a/packages/compass-sidebar/src/components/multiple-connections/connections-navigation.tsx
+++ b/packages/compass-sidebar/src/components/multiple-connections/connections-navigation.tsx
@@ -131,6 +131,7 @@ type MapStateProps = {
type MapDispatchProps = {
fetchAllCollections(): void;
onDatabaseExpand(connectionId: string, dbId: string): void;
+ onRefreshDatabases(connectionId: string): void;
onNamespaceAction(
connectionId: string,
namespace: string,
@@ -164,6 +165,7 @@ const ConnectionsNavigation: React.FC = ({
onDisconnect,
onDatabaseExpand,
fetchAllCollections,
+ onRefreshDatabases: _onRefreshDatabases,
onNamespaceAction: _onNamespaceAction,
}) => {
const {
@@ -281,6 +283,9 @@ const ConnectionsNavigation: React.FC = ({
case 'select-connection':
openDatabasesWorkspace(item.connectionInfo.id);
return;
+ case 'refresh-databases':
+ _onRefreshDatabases(item.connectionInfo.id);
+ return;
case 'create-database':
_onNamespaceAction(item.connectionInfo.id, '', action);
return;
@@ -326,6 +331,7 @@ const ConnectionsNavigation: React.FC = ({
}
},
[
+ _onRefreshDatabases,
_onNamespaceAction,
openShellWorkspace,
openDatabasesWorkspace,
@@ -497,6 +503,12 @@ const ConnectionsNavigation: React.FC = ({
);
};
+const onRefreshDatabases = (connectionId: string): SidebarThunkAction => {
+ return (_dispatch, getState, { globalAppRegistry }) => {
+ globalAppRegistry.emit('refresh-databases', { connectionId });
+ };
+};
+
const onNamespaceAction = (
connectionId: string,
namespace: string,
@@ -567,6 +579,7 @@ const mapDispatchToProps: MapDispatchToProps<
MapDispatchProps,
ConnectionsNavigationComponentProps
> = {
+ onRefreshDatabases,
onNamespaceAction,
onDatabaseExpand,
fetchAllCollections,
diff --git a/packages/compass-sidebar/src/components/multiple-connections/sidebar.spec.tsx b/packages/compass-sidebar/src/components/multiple-connections/sidebar.spec.tsx
index 04eb4f19759..22149507052 100644
--- a/packages/compass-sidebar/src/components/multiple-connections/sidebar.spec.tsx
+++ b/packages/compass-sidebar/src/components/multiple-connections/sidebar.spec.tsx
@@ -63,7 +63,7 @@ function andSucceed(): PromiseFunction {
const savedFavoriteConnection: ConnectionInfo = {
id: '12345',
connectionOptions: {
- connectionString: 'mongodb://localhost:27017',
+ connectionString: 'mongodb://localhost:12345/',
},
favorite: {
name: 'localhost',
@@ -75,7 +75,7 @@ const savedFavoriteConnection: ConnectionInfo = {
const savedRecentConnection: ConnectionInfo = {
id: '54321',
connectionOptions: {
- connectionString: 'mongodb://localhost:27020',
+ connectionString: 'mongodb://localhost:27020/',
},
};
@@ -619,6 +619,18 @@ describe('Multiple Connections Sidebar Component', function () {
expect(disconnectSpy).to.be.calledWith(savedFavoriteConnection.id);
});
+ it('should connect when the user tries to expand an inactive connection', async function () {
+ const connectSpy = sinon.spy(connectionsManager, 'connect');
+ await renderWithConnections();
+ const connectionItem = screen.getByTestId(savedRecentConnection.id);
+
+ userEvent.click(
+ within(connectionItem).getByLabelText('Caret Right Icon')
+ );
+
+ expect(connectSpy).to.be.calledWith(savedRecentConnection);
+ });
+
it('should open edit connection modal when clicked on edit connection action', function () {
// note that we only click on non-connected item because for
// connected item we cannot edit connection
@@ -681,7 +693,7 @@ describe('Multiple Connections Sidebar Component', function () {
});
});
- it('should duplicate connection when clicked on duplicate action', async function () {
+ it('should open a connection form when clicked on duplicate action', async function () {
const saveSpy = sinon.spy(connectionStorage, 'save');
const connectionItem = screen.getByTestId(
@@ -697,16 +709,18 @@ describe('Multiple Connections Sidebar Component', function () {
userEvent.click(screen.getByText('Duplicate'));
+ // Does not save the duplicate yet
await waitFor(() => {
- expect(saveSpy).to.have.been.called;
+ expect(saveSpy).not.to.have.been.called;
});
- await waitFor(() => {
- // 3 connections and one database from the connected one
- return expect(screen.getAllByRole('treeitem')).to.have.lengthOf(
- 4
- );
- });
+ // We see the connect button in the form modal
+ expect(screen.getByTestId('connect-button')).to.be.visible;
+
+ // Connection string is pre-filled with a duplicate
+ expect(screen.getByTestId('connectionString')).to.have.value(
+ savedFavoriteConnection.connectionOptions.connectionString
+ );
});
it('should disconnect and remove the connection when clicked on remove action', async function () {
diff --git a/packages/compass-sidebar/src/components/multiple-connections/sidebar.tsx b/packages/compass-sidebar/src/components/multiple-connections/sidebar.tsx
index 7372ce31466..882c02063e8 100644
--- a/packages/compass-sidebar/src/components/multiple-connections/sidebar.tsx
+++ b/packages/compass-sidebar/src/components/multiple-connections/sidebar.tsx
@@ -28,7 +28,6 @@ import {
import { getGenuineMongoDB } from 'mongodb-build-info';
import { SidebarHeader } from './header/sidebar-header';
import { ConnectionFormModal } from '@mongodb-js/connection-form';
-import { cloneDeep } from 'lodash';
import { usePreference } from 'compass-preferences-model/provider';
import { type RootState, type SidebarThunkAction } from '../../modules';
import { Navigation } from './navigation/navigation';
@@ -103,7 +102,7 @@ function ConnectionErrorToastBody({
}: ConnectionErrorToastBodyProps): React.ReactElement {
return (
-
+
There was a problem connecting{' '}
{info ? `to ${getConnectionTitle(info)}` : ''}
@@ -112,6 +111,7 @@ function ConnectionErrorToastBody({
className={connectionErrorToastActionMessageStyles}
hideExternalIcon={true}
onClick={onReview}
+ data-testid="connection-error-review"
>
REVIEW
@@ -207,8 +207,8 @@ export function MultipleConnectionSidebar({
cancelConnectionAttempt,
removeConnection,
saveConnection,
- duplicateConnection,
createNewConnection,
+ createDuplicateConnection,
state: { activeConnectionId, activeConnectionInfo, connectionErrorMessage },
} = useConnections();
@@ -312,8 +312,8 @@ export function MultipleConnectionSidebar({
[openToast]
);
- const onConnect = useCallback(
- (info: ConnectionInfo) => {
+ const _onConnect = useCallback(
+ async (info: ConnectionInfo): Promise => {
if (activeConnections.length >= maxConcurrentConnections) {
onMaxConcurrentConnectionsLimitReached(
activeConnections.length,
@@ -324,7 +324,7 @@ export function MultipleConnectionSidebar({
}
setActiveConnectionById(info.id);
onConnectionAttemptStarted(info);
- void connect(info).then(
+ await connect(info).then(
() => {
onConnected(info);
},
@@ -345,6 +345,13 @@ export function MultipleConnectionSidebar({
]
);
+ const onConnect = useCallback(
+ (info: ConnectionInfo) => {
+ void _onConnect(info);
+ },
+ [_onConnect]
+ );
+
const onNewConnectionOpen = useCallback(() => {
createNewConnection();
setIsConnectionFormOpen(true);
@@ -362,11 +369,11 @@ export function MultipleConnectionSidebar({
const onNewConnectionConnect = useCallback(
(connectionInfo: ConnectionInfo) => {
- void connect({
- ...cloneDeep(connectionInfo),
- }).then(() => setIsConnectionFormOpen(false));
+ void _onConnect(connectionInfo).then(() => {
+ setIsConnectionFormOpen(false);
+ });
},
- [connect]
+ [_onConnect]
);
const onSaveNewConnection = useCallback(
@@ -394,10 +401,10 @@ export function MultipleConnectionSidebar({
const onDuplicateConnection = useCallback(
(info: ConnectionInfo) => {
- duplicateConnection(info);
+ createDuplicateConnection(info);
setIsConnectionFormOpen(true);
},
- [duplicateConnection, setIsConnectionFormOpen]
+ [setIsConnectionFormOpen, createDuplicateConnection]
);
const onToggleFavoriteConnectionInfo = useCallback(
diff --git a/packages/compass-sidebar/src/components/use-filtered-connections.spec.ts b/packages/compass-sidebar/src/components/use-filtered-connections.spec.ts
index 5bd7935b390..ff02247291d 100644
--- a/packages/compass-sidebar/src/components/use-filtered-connections.spec.ts
+++ b/packages/compass-sidebar/src/components/use-filtered-connections.spec.ts
@@ -104,6 +104,13 @@ const sidebarConnections: SidebarConnection[] = [
sourceName: '',
pipeline: [],
},
+ {
+ _id: 'coll_ready_2_2',
+ name: 'coll_ready_2_2',
+ type: 'collection',
+ sourceName: '',
+ pipeline: [],
+ },
],
collectionsLength: 1,
collectionsStatus: 'ready',
@@ -499,6 +506,40 @@ describe('useFilteredConnections', function () {
});
});
+ it('should not filter the database items if the parent is also a match', async function () {
+ const { result } = renderHookWithContext(useFilteredConnections, {
+ initialProps: {
+ connections: [
+ {
+ ...mockSidebarConnections[0],
+ name: 'Matching connection',
+ databases: [
+ {
+ ...(mockSidebarConnections[0] as SidebarConnectedConnection)
+ .databases[0],
+ name: 'Matching database',
+ },
+ {
+ ...(mockSidebarConnections[0] as SidebarConnectedConnection)
+ .databases[1],
+ name: 'Another database',
+ },
+ ],
+ } as SidebarConnectedConnection,
+ ],
+ filterRegex: new RegExp('Matching', 'i'), // this matches connection as well as database
+ fetchAllCollections: fetchAllCollectionsStub,
+ onDatabaseExpand: onDatabaseExpandStub,
+ },
+ });
+
+ await waitFor(() => {
+ expect(
+ (result.current.filtered?.[0] as SidebarConnectedConnection).databases
+ ).to.have.length(2); // both databases are included
+ });
+ });
+
it('should match the collection items', async function () {
const { result } = renderHookWithContext(useFilteredConnections, {
initialProps: {
@@ -516,17 +557,40 @@ describe('useFilteredConnections', function () {
{
...matchedItem,
// will only match the second database's collection
- databases: [matchedItem.databases[0]],
+ databases: [
+ {
+ ...matchedItem.databases[0],
+ collections: [matchedItem.databases[0].collections[0]],
+ },
+ ],
},
]);
});
});
+ it('should not filter the collection items if the parent is also a match', async function () {
+ const { result } = renderHookWithContext(useFilteredConnections, {
+ initialProps: {
+ connections: mockSidebarConnections,
+ filterRegex: new RegExp('ready_2_1', 'i'), // this matches 1 database and 1 collection
+ fetchAllCollections: fetchAllCollectionsStub,
+ onDatabaseExpand: onDatabaseExpandStub,
+ },
+ });
+
+ await waitFor(() => {
+ expect(
+ (result.current.filtered?.[0] as SidebarConnectedConnection)
+ .databases[0].collections
+ ).to.have.length(2); // the result has 2 collections
+ });
+ });
+
it('as expanded, it should return an object containing an expanded object for the matching items', async function () {
const { result } = renderHookWithContext(useFilteredConnections, {
initialProps: {
connections: mockSidebarConnections,
- filterRegex: new RegExp('_1_1', 'i'),
+ filterRegex: new RegExp('coll_ready_1_1', 'i'),
fetchAllCollections: fetchAllCollectionsStub,
onDatabaseExpand: onDatabaseExpandStub,
},
@@ -568,7 +632,7 @@ describe('useFilteredConnections', function () {
rerender({
connections: mockSidebarConnections,
- filterRegex: new RegExp('_1_1', 'i'),
+ filterRegex: new RegExp('coll_ready_1_1', 'i'),
fetchAllCollections: fetchAllCollectionsStub,
onDatabaseExpand: onDatabaseExpandStub,
});
@@ -591,7 +655,7 @@ describe('useFilteredConnections', function () {
{
initialProps: {
connections: mockSidebarConnections,
- filterRegex: new RegExp('_1_1', 'i'),
+ filterRegex: new RegExp('coll_ready_1_1', 'i'),
fetchAllCollections: fetchAllCollectionsStub,
onDatabaseExpand: onDatabaseExpandStub,
},
@@ -630,7 +694,7 @@ describe('useFilteredConnections', function () {
const { result } = renderHookWithContext(useFilteredConnections, {
initialProps: {
connections: mockSidebarConnections,
- filterRegex: new RegExp('_1_1', 'i'),
+ filterRegex: new RegExp('coll_ready_1_1', 'i'),
fetchAllCollections: fetchAllCollectionsStub,
onDatabaseExpand: onDatabaseExpandStub,
},
@@ -662,7 +726,7 @@ describe('useFilteredConnections', function () {
const { result } = renderHookWithContext(useFilteredConnections, {
initialProps: {
connections: mockSidebarConnections,
- filterRegex: new RegExp('_1_1', 'i'),
+ filterRegex: new RegExp('coll_ready_1_1', 'i'),
fetchAllCollections: fetchAllCollectionsStub,
onDatabaseExpand: onDatabaseExpandStub,
},
@@ -700,7 +764,7 @@ describe('useFilteredConnections', function () {
const { result } = renderHookWithContext(useFilteredConnections, {
initialProps: {
connections: mockSidebarConnections,
- filterRegex: new RegExp('_1_1', 'i'),
+ filterRegex: new RegExp('coll_ready_1_1', 'i'),
fetchAllCollections: fetchAllCollectionsStub,
onDatabaseExpand: onDatabaseExpandStub,
},
diff --git a/packages/compass-sidebar/src/components/use-filtered-connections.ts b/packages/compass-sidebar/src/components/use-filtered-connections.ts
index 05dc466d7c4..dd583de519a 100644
--- a/packages/compass-sidebar/src/components/use-filtered-connections.ts
+++ b/packages/compass-sidebar/src/components/use-filtered-connections.ts
@@ -59,9 +59,10 @@ const filterConnections = (
isMatch,
...(connection.connectionStatus === ConnectionStatus.Connected
? {
- databases: childMatches.length
- ? childMatches
- : connection.databases,
+ databases:
+ !isMatch && childMatches.length
+ ? childMatches
+ : connection.databases,
}
: {}),
});
@@ -80,10 +81,21 @@ const filterDatabases = (
const childMatches = filterCollections(db.collections, regex);
if (isMatch || childMatches.length) {
+ // If the db doesn't match, we want to use just the matching collections.
+ // if the db does match we include all the collections but we still record
+ // if they match because if something does match then we want to expand
+ // the database in temporarilyExpand below.
+ const collections =
+ !isMatch && childMatches.length
+ ? childMatches
+ : db.collections.map((collection) => ({
+ ...collection,
+ isMatch: regex.test(collection.name),
+ }));
results.push({
...db,
isMatch,
- collections: childMatches.length ? childMatches : db.collections,
+ collections,
});
}
}
@@ -127,7 +139,7 @@ const temporarilyExpand = (
}
databases.forEach(({ _id: databaseId, collections }) => {
const childrenCollsAreMatch =
- collections.length && collections[0].isMatch;
+ collections.length && collections.some((col) => col.isMatch);
if (childrenCollsAreMatch && collections.length) {
if (newExpanded[connectionId].state === 'collapsed') {
newExpanded[connectionId].state = 'tempExpanded';
diff --git a/packages/compass-sidebar/src/modules/databases.ts b/packages/compass-sidebar/src/modules/databases.ts
index 8a05e0d6219..aafb967676b 100644
--- a/packages/compass-sidebar/src/modules/databases.ts
+++ b/packages/compass-sidebar/src/modules/databases.ts
@@ -118,10 +118,12 @@ export const changeDatabases = (
databases,
});
+// Receives connectionId only to support filtering for single connections
+// navigation tree
export const fetchAllCollections =
- (): SidebarThunkAction =>
+ (connectionId?: string): SidebarThunkAction =>
(dispatch, getState, { globalAppRegistry }) => {
- globalAppRegistry.emit('sidebar-filter-navigation-list');
+ globalAppRegistry.emit('sidebar-filter-navigation-list', { connectionId });
dispatch({ type: FETCH_ALL_COLLECTIONS });
};
@@ -131,6 +133,8 @@ export const onDatabaseExpand =
databaseId: string
): SidebarThunkAction =>
(dispatch, getState, { globalAppRegistry }) => {
- globalAppRegistry.emit('sidebar-expand-database', connectionId, databaseId);
+ globalAppRegistry.emit('sidebar-expand-database', databaseId, {
+ connectionId,
+ });
dispatch({ type: EXPAND_DATABASE, connectionId, databaseId });
};
diff --git a/packages/compass-telemetry/package.json b/packages/compass-telemetry/package.json
index 26e27439b8d..1ce537a1b16 100644
--- a/packages/compass-telemetry/package.json
+++ b/packages/compass-telemetry/package.json
@@ -13,7 +13,7 @@
"email": "compass@mongodb.com"
},
"homepage": "https://github.com/mongodb-js/compass",
- "version": "1.0.1",
+ "version": "1.1.1",
"repository": {
"type": "git",
"url": "https://github.com/mongodb-js/compass.git"
@@ -52,13 +52,13 @@
"reformat": "npm run eslint . -- --fix && npm run prettier -- --write ."
},
"dependencies": {
- "@mongodb-js/compass-logging": "^1.3.1",
- "hadron-app-registry": "^9.1.12",
- "hadron-ipc": "^3.2.16",
+ "@mongodb-js/compass-logging": "^1.4.1",
+ "hadron-app-registry": "^9.2.1",
+ "hadron-ipc": "^3.2.18",
"react": "^17.0.2"
},
"devDependencies": {
- "@mongodb-js/eslint-config-compass": "^1.1.2",
+ "@mongodb-js/eslint-config-compass": "^1.1.3",
"@mongodb-js/mocha-config-compass": "^1.3.9",
"@mongodb-js/prettier-config-compass": "^1.0.2",
"@mongodb-js/tsconfig-compass": "^1.0.4",
diff --git a/packages/compass-telemetry/src/generic-track.ts b/packages/compass-telemetry/src/generic-track.ts
index 104206914e4..12ad1f7be3c 100644
--- a/packages/compass-telemetry/src/generic-track.ts
+++ b/packages/compass-telemetry/src/generic-track.ts
@@ -1,16 +1,17 @@
import { type Logger, mongoLogId } from '@mongodb-js/compass-logging/provider';
-
-export type TrackProps = Record | (() => Record);
-export type TrackFunction = (event: string, properties?: TrackProps) => void;
+import type { TrackFunction, AsyncTrackFunction } from './types';
export interface TelemetryPreferences {
getPreferences(): { trackUsageStatistics: boolean };
}
+export type TelemetryConnectionInfoHook = () => { id: string };
+
export interface TelemetryServiceOptions {
- sendTrack: (event: string, properties: Record) => void;
+ sendTrack: TrackFunction;
logger?: Logger;
preferences?: TelemetryPreferences;
+ useConnectionInfo?: TelemetryConnectionInfoHook;
}
export const createTrack = ({
@@ -18,10 +19,11 @@ export const createTrack = ({
logger: { log, debug },
preferences,
}: TelemetryServiceOptions & { logger: Logger }) => {
- const trackAsync = async (
- event: string,
- properties: TrackProps = {}
- ): Promise => {
+ const trackAsync: AsyncTrackFunction = async (
+ event,
+ parameters,
+ connectionInfo
+ ) => {
// Note that this preferences check is mainly a performance optimization,
// since the main process telemetry code also checks this preference value,
// so it is safe to fall back to 'true'.
@@ -31,9 +33,9 @@ export const createTrack = ({
return;
}
- if (typeof properties === 'function') {
+ if (typeof parameters === 'function') {
try {
- properties = await properties();
+ parameters = await parameters();
} catch (error) {
// When an error arises during the fetching of properties,
// for instance if we can't fetch host information,
@@ -55,10 +57,16 @@ export const createTrack = ({
return;
}
}
- sendTrack(event, properties);
+
+ if (typeof parameters === 'object' && connectionInfo) {
+ parameters.connection_id = connectionInfo.id;
+ }
+
+ debug('sendTrack()', event, parameters);
+ sendTrack(event, parameters || {});
};
- const track = (...args: [string, TrackProps?]) => {
+ const track: TrackFunction = (...args) => {
void Promise.resolve()
.then(() => trackAsync(...args))
.catch((error) => debug('track failed', error));
diff --git a/packages/compass-telemetry/src/index.ts b/packages/compass-telemetry/src/index.ts
index fd8acfc1230..36309c16853 100644
--- a/packages/compass-telemetry/src/index.ts
+++ b/packages/compass-telemetry/src/index.ts
@@ -1,2 +1,3 @@
export { createIpcTrack, createIpcSendTrack } from './ipc-track';
-export type { TrackFunction, TelemetryServiceOptions } from './generic-track';
+export type { TelemetryServiceOptions } from './generic-track';
+export type { TrackFunction, TrackParameters } from './types';
diff --git a/packages/compass-telemetry/src/ipc-track.ts b/packages/compass-telemetry/src/ipc-track.ts
index 9cd530bf847..1165c7baa5d 100644
--- a/packages/compass-telemetry/src/ipc-track.ts
+++ b/packages/compass-telemetry/src/ipc-track.ts
@@ -1,11 +1,7 @@
import { type HadronIpcRenderer } from 'hadron-ipc';
-import {
- type TelemetryPreferences,
- type TrackFunction,
- type TrackProps,
- createTrack,
-} from './generic-track';
+import { type TelemetryPreferences, createTrack } from './generic-track';
import { createLogger, type Logger } from '@mongodb-js/compass-logging';
+import type { TrackFunction } from './types';
function emit(
ipc: HadronIpcRenderer | null | undefined,
@@ -37,7 +33,7 @@ export function createIpcSendTrack() {
// eslint-disable-next-line @typescript-eslint/no-var-requires
require('hadron-ipc').ipcRenderer;
- const sendTrack = (event: string, properties: TrackProps) =>
+ const sendTrack: TrackFunction = (event, properties) =>
emit(ipc, 'compass:track', { event, properties });
return sendTrack;
diff --git a/packages/compass-telemetry/src/provider.tsx b/packages/compass-telemetry/src/provider.tsx
index 814beaf18ff..56905338cb8 100644
--- a/packages/compass-telemetry/src/provider.tsx
+++ b/packages/compass-telemetry/src/provider.tsx
@@ -1,11 +1,8 @@
import React, { useRef } from 'react';
import { createServiceLocator } from 'hadron-app-registry';
-import {
- createTrack,
- type TelemetryServiceOptions,
- type TrackFunction,
-} from './generic-track';
+import { createTrack, type TelemetryServiceOptions } from './generic-track';
import { useLogger } from '@mongodb-js/compass-logging/provider';
+import type { TrackFunction, TrackParameters } from './types';
const noop = () => {
// noop
@@ -36,12 +33,10 @@ export const TelemetryProvider: React.FC<{
);
};
-export function createTelemetryLocator() {
- return createServiceLocator(
- useTelemetry.bind(null),
- 'createTelemetryLocator'
- );
-}
+export const telemetryLocator = createServiceLocator(
+ useTelemetry.bind(null),
+ 'telemetryLocator'
+);
export function useTelemetry(): TrackFunction {
const track = React.useContext(TelemetryContext);
@@ -57,7 +52,7 @@ type FirstArgument = F extends (...args: [infer A, ...any]) => any
? A
: never;
-export function withTelemetry<
+function withTelemetry<
T extends ((...args: any[]) => any) | { new (...args: any[]): any }
>(ReactComponent: T): React.FunctionComponent, 'track'>> {
const WithTelemetry = (
@@ -69,6 +64,8 @@ export function withTelemetry<
return WithTelemetry;
}
+export { withTelemetry };
+
/**
* Hook that allows to track telemetry events as a side effect of dependencies changing.
*
@@ -79,7 +76,7 @@ export function withTelemetry<
*
* @example
* useTrackOnChange((track) => {
- * if (isShellOpen) { track('Shell Opened') }
+ * if (isShellOpen) { track('Shell Opened', {}, { id: 'connection123' }) }
* }, [isShellOpen], { skipOnMount: true });
*/
export function useTrackOnChange(
@@ -100,4 +97,4 @@ export function useTrackOnChange(
}, [...dependencies, track, options.skipOnMount]);
}
-export type { TrackFunction };
+export type { TrackFunction, TrackParameters };
diff --git a/packages/compass-telemetry/src/types.ts b/packages/compass-telemetry/src/types.ts
new file mode 100644
index 00000000000..bfa97b7c370
--- /dev/null
+++ b/packages/compass-telemetry/src/types.ts
@@ -0,0 +1,22 @@
+export type EventsPayload = Record;
+
+export type TelemetryConnectionInfo = {
+ id: string;
+};
+
+export type TrackParameters =
+ | EventsPayload
+ | (() => Promise)
+ | (() => EventsPayload);
+
+export type TrackFunction = (
+ event: string,
+ parameters?: TrackParameters,
+ connectionInfo?: TelemetryConnectionInfo
+) => void;
+
+export type AsyncTrackFunction = (
+ event: string,
+ parameters?: TrackParameters,
+ connectionInfo?: TelemetryConnectionInfo
+) => Promise;
diff --git a/packages/compass-test-server/package.json b/packages/compass-test-server/package.json
index 3d962569400..f8b3005744a 100644
--- a/packages/compass-test-server/package.json
+++ b/packages/compass-test-server/package.json
@@ -13,7 +13,7 @@
"email": "compass@mongodb.com"
},
"homepage": "https://github.com/mongodb-js/compass",
- "version": "0.1.17",
+ "version": "0.1.18",
"repository": {
"type": "git",
"url": "https://github.com/mongodb-js/compass.git"
@@ -53,7 +53,7 @@
"mongodb-runner": "^5.6.2"
},
"devDependencies": {
- "@mongodb-js/eslint-config-compass": "^1.1.2",
+ "@mongodb-js/eslint-config-compass": "^1.1.3",
"@mongodb-js/mocha-config-compass": "^1.3.9",
"@mongodb-js/prettier-config-compass": "^1.0.2",
"@mongodb-js/tsconfig-compass": "^1.0.4",
diff --git a/packages/compass-user-data/package.json b/packages/compass-user-data/package.json
index a1b9dc3f8f2..b7a5a6b698b 100644
--- a/packages/compass-user-data/package.json
+++ b/packages/compass-user-data/package.json
@@ -12,7 +12,7 @@
"email": "compass@mongodb.com"
},
"homepage": "https://github.com/mongodb-js/compass",
- "version": "0.2.1",
+ "version": "0.3.1",
"repository": {
"type": "git",
"url": "https://github.com/mongodb-js/compass.git"
@@ -49,13 +49,13 @@
"reformat": "npm run eslint . -- --fix && npm run prettier -- --write ."
},
"dependencies": {
- "@mongodb-js/compass-logging": "^1.3.1",
- "@mongodb-js/compass-utils": "^0.6.5",
+ "@mongodb-js/compass-logging": "^1.4.1",
+ "@mongodb-js/compass-utils": "^0.6.7",
"write-file-atomic": "^5.0.1",
"zod": "^3.22.3"
},
"devDependencies": {
- "@mongodb-js/eslint-config-compass": "^1.1.2",
+ "@mongodb-js/eslint-config-compass": "^1.1.3",
"@mongodb-js/mocha-config-compass": "^1.3.9",
"@mongodb-js/prettier-config-compass": "^1.0.2",
"@mongodb-js/tsconfig-compass": "^1.0.4",
diff --git a/packages/compass-utils/package.json b/packages/compass-utils/package.json
index 81ed35d986d..7a0a10a23da 100644
--- a/packages/compass-utils/package.json
+++ b/packages/compass-utils/package.json
@@ -13,7 +13,7 @@
"email": "compass@mongodb.com"
},
"homepage": "https://github.com/mongodb-js/compass",
- "version": "0.6.5",
+ "version": "0.6.7",
"repository": {
"type": "git",
"url": "https://github.com/mongodb-js/compass.git"
@@ -50,7 +50,7 @@
"reformat": "npm run eslint . -- --fix && npm run prettier -- --write ."
},
"devDependencies": {
- "@mongodb-js/eslint-config-compass": "^1.1.2",
+ "@mongodb-js/eslint-config-compass": "^1.1.3",
"@mongodb-js/mocha-config-compass": "^1.3.9",
"@mongodb-js/prettier-config-compass": "^1.0.2",
"@mongodb-js/tsconfig-compass": "^1.0.4",
@@ -69,6 +69,6 @@
},
"dependencies": {
"@electron/remote": "^2.1.2",
- "electron": "^29.4.3"
+ "electron": "^29.4.5"
}
}
diff --git a/packages/compass-web/package.json b/packages/compass-web/package.json
index de139861d7e..09f73cc4129 100644
--- a/packages/compass-web/package.json
+++ b/packages/compass-web/package.json
@@ -14,7 +14,7 @@
"email": "compass@mongodb.com"
},
"homepage": "https://github.com/mongodb-js/compass",
- "version": "0.5.1",
+ "version": "0.5.5",
"repository": {
"type": "git",
"url": "https://github.com/mongodb-js/compass.git"
@@ -62,32 +62,32 @@
"react-dom": "^17.0.2"
},
"devDependencies": {
- "@mongodb-js/atlas-service": "^0.22.0",
- "@mongodb-js/compass-aggregations": "^9.35.0",
- "@mongodb-js/compass-app-stores": "^7.19.0",
- "@mongodb-js/compass-collection": "^4.32.0",
- "@mongodb-js/compass-components": "^1.26.0",
- "@mongodb-js/compass-connections": "^1.33.0",
- "@mongodb-js/compass-crud": "^13.33.0",
- "@mongodb-js/compass-databases-collections": "^1.32.0",
- "@mongodb-js/compass-explain-plan": "^6.33.0",
- "@mongodb-js/compass-export-to-language": "^9.9.0",
- "@mongodb-js/compass-field-store": "^9.8.0",
- "@mongodb-js/compass-generative-ai": "^0.16.0",
- "@mongodb-js/compass-indexes": "^5.32.0",
- "@mongodb-js/compass-logging": "^1.3.1",
- "@mongodb-js/compass-telemetry": "^1.0.1",
- "@mongodb-js/compass-query-bar": "^8.34.0",
- "@mongodb-js/compass-schema": "^6.34.0",
- "@mongodb-js/compass-schema-validation": "^6.33.0",
- "@mongodb-js/compass-sidebar": "^5.33.0",
- "@mongodb-js/compass-workspaces": "^0.14.0",
- "@mongodb-js/connection-storage": "^0.14.1",
- "@mongodb-js/eslint-config-compass": "^1.1.2",
+ "@mongodb-js/atlas-service": "^0.25.0",
+ "@mongodb-js/compass-aggregations": "^9.38.0",
+ "@mongodb-js/compass-app-stores": "^7.22.0",
+ "@mongodb-js/compass-collection": "^4.35.0",
+ "@mongodb-js/compass-components": "^1.28.0",
+ "@mongodb-js/compass-connections": "^1.36.0",
+ "@mongodb-js/compass-crud": "^13.36.0",
+ "@mongodb-js/compass-databases-collections": "^1.35.0",
+ "@mongodb-js/compass-explain-plan": "^6.36.0",
+ "@mongodb-js/compass-export-to-language": "^9.12.0",
+ "@mongodb-js/compass-field-store": "^9.11.0",
+ "@mongodb-js/compass-generative-ai": "^0.19.0",
+ "@mongodb-js/compass-indexes": "^5.35.0",
+ "@mongodb-js/compass-logging": "^1.4.1",
+ "@mongodb-js/compass-telemetry": "^1.1.1",
+ "@mongodb-js/compass-query-bar": "^8.37.0",
+ "@mongodb-js/compass-schema": "^6.37.0",
+ "@mongodb-js/compass-schema-validation": "^6.36.0",
+ "@mongodb-js/compass-sidebar": "^5.36.0",
+ "@mongodb-js/compass-workspaces": "^0.17.0",
+ "@mongodb-js/connection-storage": "^0.16.0",
+ "@mongodb-js/eslint-config-compass": "^1.1.3",
"@mongodb-js/mocha-config-compass": "^1.3.9",
"@mongodb-js/prettier-config-compass": "^1.0.2",
"@mongodb-js/tsconfig-compass": "^1.0.4",
- "@mongodb-js/webpack-config-compass": "^1.3.11",
+ "@mongodb-js/webpack-config-compass": "^1.3.13",
"@testing-library/react": "^12.1.5",
"@testing-library/react-hooks": "^7.0.2",
"@testing-library/user-event": "^13.5.0",
@@ -102,23 +102,23 @@
"bson": "^6.2.0",
"buffer": "^6.0.3",
"chai": "^4.3.6",
- "compass-preferences-model": "^2.23.1",
+ "compass-preferences-model": "^2.25.0",
"crypto-browserify": "^3.12.0",
"debug": "^4.3.4",
"depcheck": "^1.4.1",
"dns-query": "^0.11.2",
- "electron": "^29.4.3",
+ "electron": "^29.4.5",
"eslint": "^7.25.0",
"events": "^3.3.0",
"express": "^4.19.2",
"express-http-proxy": "^2.0.0",
- "hadron-app-registry": "^9.1.12",
+ "hadron-app-registry": "^9.2.1",
"is-ip": "^5.0.1",
"lodash": "^4.17.21",
"mocha": "^10.2.0",
"mongodb": "^6.7.0",
"mongodb-connection-string-url": "^3.0.1",
- "mongodb-data-service": "^22.21.1",
+ "mongodb-data-service": "^22.22.1",
"nyc": "^15.1.0",
"os-browserify": "^0.3.0",
"path-browserify": "^1.0.1",
diff --git a/packages/compass-welcome/package.json b/packages/compass-welcome/package.json
index 66a1f4d880d..bebc6248858 100644
--- a/packages/compass-welcome/package.json
+++ b/packages/compass-welcome/package.json
@@ -11,7 +11,7 @@
"email": "compass@mongodb.com"
},
"homepage": "https://github.com/mongodb-js/compass",
- "version": "0.31.0",
+ "version": "0.34.0",
"repository": {
"type": "git",
"url": "https://github.com/mongodb-js/compass.git"
@@ -49,18 +49,18 @@
"reformat": "npm run eslint . -- --fix && npm run prettier -- --write ."
},
"dependencies": {
- "@mongodb-js/compass-components": "^1.26.0",
- "@mongodb-js/compass-logging": "^1.3.1",
- "@mongodb-js/compass-telemetry": "^1.0.1",
- "@mongodb-js/compass-workspaces": "^0.14.0",
- "compass-preferences-model": "^2.23.1",
- "hadron-app-registry": "^9.1.12",
+ "@mongodb-js/compass-components": "^1.28.0",
+ "@mongodb-js/compass-logging": "^1.4.1",
+ "@mongodb-js/compass-telemetry": "^1.1.1",
+ "@mongodb-js/compass-workspaces": "^0.17.0",
+ "compass-preferences-model": "^2.25.0",
+ "hadron-app-registry": "^9.2.1",
"react": "^17.0.2",
"redux": "^4.2.1",
"redux-thunk": "^2.4.2"
},
"devDependencies": {
- "@mongodb-js/eslint-config-compass": "^1.1.2",
+ "@mongodb-js/eslint-config-compass": "^1.1.3",
"@mongodb-js/mocha-config-compass": "^1.3.9",
"@mongodb-js/prettier-config-compass": "^1.0.2",
"@mongodb-js/tsconfig-compass": "^1.0.4",
diff --git a/packages/compass-welcome/src/index.ts b/packages/compass-welcome/src/index.ts
index 177ad6df9f0..0bbc98e3e57 100644
--- a/packages/compass-welcome/src/index.ts
+++ b/packages/compass-welcome/src/index.ts
@@ -4,11 +4,11 @@ import { workspacesServiceLocator } from '@mongodb-js/compass-workspaces/provide
import type { WorkspaceComponent } from '@mongodb-js/compass-workspaces';
import { WelcomeModal, WelcomeTab } from './components';
import { activatePlugin } from './stores';
-import { createTelemetryLocator } from '@mongodb-js/compass-telemetry/provider';
+import { telemetryLocator } from '@mongodb-js/compass-telemetry/provider';
const serviceLocators = {
logger: createLoggerLocator('COMPASS-MY-QUERIES-UI'),
- track: createTelemetryLocator(),
+ track: telemetryLocator,
workspaces: workspacesServiceLocator,
};
diff --git a/packages/compass-workspaces/package.json b/packages/compass-workspaces/package.json
index 3e8c3801f7f..b990d5bc9cb 100644
--- a/packages/compass-workspaces/package.json
+++ b/packages/compass-workspaces/package.json
@@ -11,7 +11,7 @@
"email": "compass@mongodb.com"
},
"homepage": "https://github.com/mongodb-js/compass",
- "version": "0.14.0",
+ "version": "0.17.0",
"repository": {
"type": "git",
"url": "https://github.com/mongodb-js/compass.git"
@@ -51,15 +51,15 @@
"reformat": "npm run eslint . -- --fix && npm run prettier -- --write ."
},
"dependencies": {
- "@mongodb-js/compass-app-stores": "^7.19.0",
- "@mongodb-js/compass-components": "^1.26.0",
- "@mongodb-js/compass-connections": "^1.33.0",
- "@mongodb-js/compass-logging": "^1.3.1",
+ "@mongodb-js/compass-app-stores": "^7.22.0",
+ "@mongodb-js/compass-components": "^1.28.0",
+ "@mongodb-js/compass-connections": "^1.36.0",
+ "@mongodb-js/compass-logging": "^1.4.1",
"bson": "^6.7.0",
- "hadron-app-registry": "^9.1.12",
+ "hadron-app-registry": "^9.2.1",
"lodash": "^4.17.21",
- "mongodb-collection-model": "^5.21.1",
- "mongodb-database-model": "^2.21.1",
+ "mongodb-collection-model": "^5.22.1",
+ "mongodb-database-model": "^2.22.1",
"mongodb-ns": "^2.4.2",
"react": "^17.0.2",
"react-redux": "^8.1.3",
@@ -67,7 +67,7 @@
"redux-thunk": "^2.4.2"
},
"devDependencies": {
- "@mongodb-js/eslint-config-compass": "^1.1.2",
+ "@mongodb-js/eslint-config-compass": "^1.1.3",
"@mongodb-js/mocha-config-compass": "^1.3.9",
"@mongodb-js/prettier-config-compass": "^1.0.2",
"@mongodb-js/tsconfig-compass": "^1.0.4",
diff --git a/packages/compass-workspaces/src/components/workspaces.tsx b/packages/compass-workspaces/src/components/workspaces.tsx
index c8d7ba259d6..435746eb5e3 100644
--- a/packages/compass-workspaces/src/components/workspaces.tsx
+++ b/packages/compass-workspaces/src/components/workspaces.tsx
@@ -161,18 +161,22 @@ const CompassWorkspaces: React.FunctionComponent = ({
case 'Welcome':
return {
id: tab.id,
+ type: tab.type,
title: tab.type,
iconGlyph: 'Logo',
} as const;
case 'My Queries':
return {
id: tab.id,
+ type: tab.type,
title: tab.type,
iconGlyph: 'CurlyBraces',
} as const;
case 'Shell':
return {
id: tab.id,
+ connectionName: getConnectionTitleById(tab.connectionId),
+ type: tab.type,
title: getConnectionTitleById(tab.connectionId) ?? 'MongoDB Shell',
iconGlyph: 'Shell',
tabTheme: getThemeOf(tab.connectionId),
@@ -180,6 +184,8 @@ const CompassWorkspaces: React.FunctionComponent = ({
case 'Databases':
return {
id: tab.id,
+ connectionName: getConnectionTitleById(tab.connectionId),
+ type: tab.type,
title: tab.type,
iconGlyph: 'Database',
tabTheme: getThemeOf(tab.connectionId),
@@ -187,6 +193,8 @@ const CompassWorkspaces: React.FunctionComponent = ({
case 'Performance':
return {
id: tab.id,
+ connectionName: getConnectionTitleById(tab.connectionId),
+ type: tab.type,
title: tab.type,
iconGlyph: 'Gauge',
tabTheme: getThemeOf(tab.connectionId),
@@ -194,6 +202,8 @@ const CompassWorkspaces: React.FunctionComponent = ({
case 'Collections':
return {
id: tab.id,
+ connectionName: getConnectionTitleById(tab.connectionId),
+ type: tab.type,
title: tab.namespace,
iconGlyph: 'Database',
'data-namespace': tab.namespace,
@@ -218,6 +228,8 @@ const CompassWorkspaces: React.FunctionComponent = ({
: `${database} > ${collection}`;
return {
id: tab.id,
+ connectionName: getConnectionTitleById(tab.connectionId),
+ type: tab.type,
title: collection,
subtitle,
iconGlyph:
@@ -243,8 +255,17 @@ const CompassWorkspaces: React.FunctionComponent = ({
const Component = getWorkspacePluginByName(activeTab.type);
return ;
}
-
- case 'Shell':
+ case 'Shell': {
+ const Component = getWorkspacePluginByName(activeTab.type);
+ return (
+
+
+
+ );
+ }
case 'Performance':
case 'Databases': {
const Component = getWorkspacePluginByName(activeTab.type);
diff --git a/packages/compass-workspaces/src/provider.tsx b/packages/compass-workspaces/src/provider.tsx
index fa60a6ddfc8..463841f3497 100644
--- a/packages/compass-workspaces/src/provider.tsx
+++ b/packages/compass-workspaces/src/provider.tsx
@@ -48,7 +48,11 @@ export type WorkspacesService = {
openShellWorkspace(
this: void,
connectionId: string,
- tabOptions?: TabOptions
+ options?: TabOptions &
+ Pick<
+ Extract,
+ 'initialInput' | 'initialEvaluate'
+ >
): void;
/**
* Open "Databases" workspace showing list of all databases in the cluster
@@ -237,9 +241,13 @@ export const WorkspacesServiceProvider: React.FunctionComponent<{
openWorkspaceAction({ type: 'My Queries' }, tabOptions)
);
},
- openShellWorkspace(connectionId, tabOptions) {
+ openShellWorkspace(connectionId, options = {}) {
+ const { newTab, ...workspaceOptions } = options;
return void store.dispatch(
- openWorkspaceAction({ type: 'Shell', connectionId }, tabOptions)
+ openWorkspaceAction(
+ { type: 'Shell', connectionId, ...workspaceOptions },
+ { newTab }
+ )
);
},
openDatabasesWorkspace: (connectionId, tabOptions) => {
diff --git a/packages/compass-workspaces/src/stores/workspaces.ts b/packages/compass-workspaces/src/stores/workspaces.ts
index ab48db3438c..2c6209cb277 100644
--- a/packages/compass-workspaces/src/stores/workspaces.ts
+++ b/packages/compass-workspaces/src/stores/workspaces.ts
@@ -599,7 +599,10 @@ export const getActiveTab = (state: WorkspacesState): WorkspaceTab | null => {
export type OpenWorkspaceOptions =
| Pick, 'type'>
| Pick, 'type'>
- | Pick, 'type' | 'connectionId'>
+ | Pick<
+ Workspace<'Shell'>,
+ 'type' | 'connectionId' | 'initialEvaluate' | 'initialInput'
+ >
| Pick, 'type' | 'connectionId'>
| Pick, 'type' | 'connectionId'>
| Pick, 'type' | 'connectionId' | 'namespace'>
diff --git a/packages/compass-workspaces/src/types.ts b/packages/compass-workspaces/src/types.ts
index 82d710c06cc..c489c713b28 100644
--- a/packages/compass-workspaces/src/types.ts
+++ b/packages/compass-workspaces/src/types.ts
@@ -16,6 +16,8 @@ export type MyQueriesWorkspace = {
export type ShellWorkspace = {
type: 'Shell';
connectionId: string;
+ initialEvaluate?: string | string[];
+ initialInput?: string;
};
export type ServerStatsWorkspace = {
diff --git a/packages/compass/package.json b/packages/compass/package.json
index 97348d0de4e..438413bdc89 100644
--- a/packages/compass/package.json
+++ b/packages/compass/package.json
@@ -155,8 +155,10 @@
"generate-3rd-party-notices": "mongodb-sbom-tools generate-3rd-party-notices --product='Mongodb Compass' --dependencies=../../.sbom/dependencies.json > THIRD-PARTY-NOTICES.md",
"postgenerate-3rd-party-notices": "prettier --write THIRD-PARTY-NOTICES.md",
"run-compiled": "electron .",
- "package-compass": "hadron-build release",
- "package-compass-debug": "DEBUG='*' HADRON_SKIP_INSTALLER=true NO_ASAR=true hadron-build release",
+ "package-compass-nocompile": "hadron-build release",
+ "prepackage-compass": "npm run compile",
+ "package-compass": "npm run package-compass-nocompile",
+ "package-compass-debug": "DEBUG='*' HADRON_SKIP_INSTALLER=true NO_ASAR=true npm run package-compass",
"upload": "hadron-build upload",
"download": "hadron-build download",
"evergreen-expansions": "hadron-build info --format=yaml --flatten > expansions.yml",
@@ -179,58 +181,58 @@
"email": "compass@mongodb.com"
},
"dependencies": {
- "@mongosh/node-runtime-worker-thread": "^2.2.10",
+ "@mongosh/node-runtime-worker-thread": "^2.2.12",
"clipboard": "^2.0.6",
"kerberos": "^2.1.0",
"keytar": "^7.9.0",
"mongodb-client-encryption": "^6.0.0",
"os-dns-native": "^1.2.1",
- "system-ca": "^1.0.3"
+ "system-ca": "^2.0.0"
},
"devDependencies": {
"@electron/rebuild": "^3.6.0",
"@electron/remote": "^2.1.2",
- "@mongodb-js/atlas-service": "^0.22.0",
- "@mongodb-js/compass-aggregations": "^9.35.0",
- "@mongodb-js/compass-app-stores": "^7.19.0",
- "@mongodb-js/compass-collection": "^4.32.0",
- "@mongodb-js/compass-components": "^1.26.0",
- "@mongodb-js/compass-connections": "^1.33.0",
- "@mongodb-js/compass-connection-import-export": "^0.29.0",
- "@mongodb-js/compass-crud": "^13.33.0",
- "@mongodb-js/compass-databases-collections": "^1.32.0",
- "@mongodb-js/compass-explain-plan": "^6.33.0",
- "@mongodb-js/compass-export-to-language": "^9.9.0",
- "@mongodb-js/compass-field-store": "^9.8.0",
- "@mongodb-js/compass-find-in-page": "^4.26.0",
- "@mongodb-js/compass-generative-ai": "^0.16.0",
- "@mongodb-js/compass-import-export": "^7.32.0",
- "@mongodb-js/compass-indexes": "^5.32.0",
- "@mongodb-js/compass-intercom": "^0.7.1",
- "@mongodb-js/compass-logging": "^1.3.1",
- "@mongodb-js/compass-telemetry": "^1.0.1",
- "@mongodb-js/compass-query-bar": "^8.34.0",
- "@mongodb-js/compass-saved-aggregations-queries": "^1.33.0",
- "@mongodb-js/compass-schema": "^6.34.0",
- "@mongodb-js/compass-schema-validation": "^6.33.0",
- "@mongodb-js/compass-serverstats": "^16.32.0",
- "@mongodb-js/compass-settings": "^0.34.0",
- "@mongodb-js/compass-shell": "^3.32.0",
- "@mongodb-js/compass-sidebar": "^5.33.0",
- "@mongodb-js/compass-utils": "^0.6.5",
- "@mongodb-js/compass-welcome": "^0.31.0",
- "@mongodb-js/compass-workspaces": "^0.14.0",
- "@mongodb-js/connection-info": "^0.4.1",
- "@mongodb-js/connection-storage": "^0.14.1",
- "@mongodb-js/eslint-config-compass": "^1.1.2",
+ "@mongodb-js/atlas-service": "^0.25.0",
+ "@mongodb-js/compass-aggregations": "^9.38.0",
+ "@mongodb-js/compass-app-stores": "^7.22.0",
+ "@mongodb-js/compass-collection": "^4.35.0",
+ "@mongodb-js/compass-components": "^1.28.0",
+ "@mongodb-js/compass-connections": "^1.36.0",
+ "@mongodb-js/compass-connection-import-export": "^0.32.0",
+ "@mongodb-js/compass-crud": "^13.36.0",
+ "@mongodb-js/compass-databases-collections": "^1.35.0",
+ "@mongodb-js/compass-explain-plan": "^6.36.0",
+ "@mongodb-js/compass-export-to-language": "^9.12.0",
+ "@mongodb-js/compass-field-store": "^9.11.0",
+ "@mongodb-js/compass-find-in-page": "^4.29.0",
+ "@mongodb-js/compass-generative-ai": "^0.19.0",
+ "@mongodb-js/compass-import-export": "^7.35.0",
+ "@mongodb-js/compass-indexes": "^5.35.0",
+ "@mongodb-js/compass-intercom": "^0.9.0",
+ "@mongodb-js/compass-logging": "^1.4.1",
+ "@mongodb-js/compass-telemetry": "^1.1.1",
+ "@mongodb-js/compass-query-bar": "^8.37.0",
+ "@mongodb-js/compass-saved-aggregations-queries": "^1.36.0",
+ "@mongodb-js/compass-schema": "^6.37.0",
+ "@mongodb-js/compass-schema-validation": "^6.36.0",
+ "@mongodb-js/compass-serverstats": "^16.35.0",
+ "@mongodb-js/compass-settings": "^0.37.0",
+ "@mongodb-js/compass-shell": "^3.35.0",
+ "@mongodb-js/compass-sidebar": "^5.36.0",
+ "@mongodb-js/compass-utils": "^0.6.7",
+ "@mongodb-js/compass-welcome": "^0.34.0",
+ "@mongodb-js/compass-workspaces": "^0.17.0",
+ "@mongodb-js/connection-info": "^0.5.1",
+ "@mongodb-js/connection-storage": "^0.16.0",
+ "@mongodb-js/eslint-config-compass": "^1.1.3",
"@mongodb-js/get-os-info": "^0.3.24",
"@mongodb-js/mocha-config-compass": "^1.3.9",
"@mongodb-js/mongodb-downloader": "^0.3.0",
- "@mongodb-js/my-queries-storage": "^0.10.0",
+ "@mongodb-js/my-queries-storage": "^0.13.0",
"@mongodb-js/prettier-config-compass": "^1.0.2",
"@mongodb-js/sbom-tools": "^0.7.0",
"@mongodb-js/tsconfig-compass": "^1.0.4",
- "@mongodb-js/webpack-config-compass": "^1.3.11",
+ "@mongodb-js/webpack-config-compass": "^1.3.13",
"@segment/analytics-node": "^1.1.4",
"@testing-library/react": "^12.1.5",
"@testing-library/user-event": "^13.5.0",
@@ -238,19 +240,19 @@
"chai": "^4.3.4",
"chalk": "^4.1.2",
"clean-stack": "^2.0.0",
- "compass-preferences-model": "^2.23.1",
+ "compass-preferences-model": "^2.25.0",
"debug": "^4.3.4",
"depcheck": "^1.4.1",
- "electron": "^29.4.3",
+ "electron": "^29.4.5",
"electron-devtools-installer": "^3.2.0",
"electron-dl": "^3.5.0",
"electron-mocha": "^12.2.0",
"electron-squirrel-startup": "^1.0.1",
"ensure-error": "^3.0.1",
"eslint": "^7.25.0",
- "hadron-app-registry": "^9.1.12",
- "hadron-build": "^25.5.3",
- "hadron-ipc": "^3.2.16",
+ "hadron-app-registry": "^9.2.1",
+ "hadron-build": "^25.5.5",
+ "hadron-ipc": "^3.2.18",
"local-links": "^1.4.0",
"make-fetch-happen": "^8.0.14",
"marky": "^1.2.1",
@@ -258,8 +260,8 @@
"mongodb-build-info": "^1.7.2",
"mongodb-cloud-info": "^2.1.2",
"mongodb-connection-string-url": "^3.0.1",
- "mongodb-data-service": "^22.21.1",
- "mongodb-instance-model": "^12.22.1",
+ "mongodb-data-service": "^22.22.1",
+ "mongodb-instance-model": "^12.23.1",
"mongodb-log-writer": "^1.4.2",
"mongodb-ns": "^2.4.2",
"node-fetch": "^2.7.0",
@@ -275,6 +277,6 @@
},
"optionalDependencies": {
"macos-export-certificate-and-key": "^1.1.2",
- "win-export-certificate-and-key": "^1.1.2"
+ "win-export-certificate-and-key": "^2.0.1"
}
}
diff --git a/packages/compass/src/app/components/entrypoint.tsx b/packages/compass/src/app/components/entrypoint.tsx
index 100977886e4..c263e42c6a9 100644
--- a/packages/compass/src/app/components/entrypoint.tsx
+++ b/packages/compass/src/app/components/entrypoint.tsx
@@ -25,8 +25,10 @@ import { LoggerProvider } from '@mongodb-js/compass-logging/provider';
import { TelemetryProvider } from '@mongodb-js/compass-telemetry/provider';
import { getAppName, getAppVersion } from '@mongodb-js/compass-utils';
import Home, { type HomeProps } from './home';
-import { createIpcSendTrack } from '@mongodb-js/compass-telemetry';
-import type { TelemetryServiceOptions } from '@mongodb-js/compass-telemetry/dist/generic-track';
+import {
+ type TelemetryServiceOptions,
+ createIpcSendTrack,
+} from '@mongodb-js/compass-telemetry';
const WithPreferencesAndLoggerProviders: React.FC = ({ children }) => {
const loggerProviderValue = useRef({
diff --git a/packages/compass/src/app/utils/telemetry.spec.ts b/packages/compass/src/app/utils/telemetry.spec.ts
index f46f86eec60..0bf9b63aa68 100644
--- a/packages/compass/src/app/utils/telemetry.spec.ts
+++ b/packages/compass/src/app/utils/telemetry.spec.ts
@@ -35,6 +35,13 @@ const dataService: Pick = {
getCurrentTopologyType: () => 'Unknown',
};
+const connectionInfo: ConnectionInfo = {
+ id: 'TEST',
+ connectionOptions: {
+ connectionString: 'mongodb://localhost:27017',
+ },
+};
+
describe('connection tracking', function () {
let trackUsageStatistics: boolean;
const logger = createLogger('TEST-CONNECTION');
@@ -57,6 +64,7 @@ describe('connection tracking', function () {
const trackEvent = once(process, 'compass:track');
trackConnectionAttemptEvent(
{
+ ...connectionInfo,
favorite: { name: 'example' },
lastUsed: undefined,
},
@@ -69,13 +77,14 @@ describe('connection tracking', function () {
is_favorite: true,
is_recent: false,
is_new: true,
+ connection_id: 'TEST',
});
});
it('tracks a new connection attempt event - recent', async function () {
const trackEvent = once(process, 'compass:track');
trackConnectionAttemptEvent(
- { favorite: undefined, lastUsed: new Date() },
+ { ...connectionInfo, favorite: undefined, lastUsed: new Date() },
logger,
track
);
@@ -84,13 +93,14 @@ describe('connection tracking', function () {
is_favorite: false,
is_recent: true,
is_new: false,
+ connection_id: 'TEST',
});
});
it('tracks a new connection attempt event - new', async function () {
const trackEvent = once(process, 'compass:track');
trackConnectionAttemptEvent(
- { favorite: undefined, lastUsed: undefined },
+ { ...connectionInfo, favorite: undefined, lastUsed: undefined },
logger,
track
);
@@ -99,6 +109,7 @@ describe('connection tracking', function () {
is_favorite: false,
is_recent: false,
is_new: true,
+ connection_id: 'TEST',
});
});
@@ -106,6 +117,7 @@ describe('connection tracking', function () {
const trackEvent = once(process, 'compass:track');
trackConnectionAttemptEvent(
{
+ ...connectionInfo,
favorite: { name: 'example' },
lastUsed: new Date(),
},
@@ -117,18 +129,20 @@ describe('connection tracking', function () {
is_favorite: true,
is_recent: false,
is_new: false,
+ connection_id: 'TEST',
});
});
it('tracks a new connection event - localhost', async function () {
const trackEvent = once(process, 'compass:track');
- const connectionInfo = {
+ const connection: ConnectionInfo = {
+ ...connectionInfo,
connectionOptions: {
connectionString: 'mongodb://localhost:27017',
},
};
- trackNewConnectionEvent(connectionInfo, dataService, logger, track);
+ trackNewConnectionEvent(connection, dataService, logger, track);
const [{ properties }] = await trackEvent;
const expected = {
is_localhost: true,
@@ -155,6 +169,7 @@ describe('connection tracking', function () {
has_kms_gcp: false,
has_kms_kmip: false,
has_kms_azure: false,
+ connection_id: 'TEST',
};
expect(properties).to.deep.equal(expected);
@@ -162,13 +177,14 @@ describe('connection tracking', function () {
it('tracks a new connection event - digital ocean', async function () {
const trackEvent = once(process, 'compass:track');
- const connectionInfo = {
+ const connection: ConnectionInfo = {
+ ...connectionInfo,
connectionOptions: {
connectionString: 'mongodb://example.mongo.ondigitalocean.com:27017',
},
};
- trackNewConnectionEvent(connectionInfo, dataService, logger, track);
+ trackNewConnectionEvent(connection, dataService, logger, track);
const [{ properties }] = await trackEvent;
const expected = {
@@ -196,6 +212,7 @@ describe('connection tracking', function () {
has_kms_gcp: false,
has_kms_kmip: false,
has_kms_azure: false,
+ connection_id: 'TEST',
};
expect(properties).to.deep.equal(expected);
@@ -216,13 +233,14 @@ describe('connection tracking', function () {
]) {
it(`tracks a new connection event - ${title}`, async function () {
const trackEvent = once(process, 'compass:track');
- const connectionInfo = {
+ const connection: ConnectionInfo = {
+ ...connectionInfo,
connectionOptions: {
connectionString: url,
},
};
- trackNewConnectionEvent(connectionInfo, dataService, logger, track);
+ trackNewConnectionEvent(connection, dataService, logger, track);
const [{ properties }] = await trackEvent;
const expected = {
@@ -251,6 +269,7 @@ describe('connection tracking', function () {
has_kms_azure: false,
is_public_cloud: true,
public_cloud_name: 'AWS',
+ connection_id: 'TEST',
};
expect(properties).to.deep.equal(expected);
@@ -287,13 +306,14 @@ describe('connection tracking', function () {
getCurrentTopologyType: () => 'Unknown',
};
- const connectionInfo = {
+ const connection: ConnectionInfo = {
+ ...connectionInfo,
connectionOptions: {
connectionString: 'mongodb://localhost:27017/',
},
};
- trackNewConnectionEvent(connectionInfo, mockDataService, logger, track);
+ trackNewConnectionEvent(connection, mockDataService, logger, track);
const [{ properties }] = await trackEvent;
const expected = {
@@ -321,6 +341,7 @@ describe('connection tracking', function () {
has_kms_gcp: false,
has_kms_kmip: false,
has_kms_azure: false,
+ connection_id: 'TEST',
};
expect(properties).to.deep.equal(expected);
@@ -328,13 +349,14 @@ describe('connection tracking', function () {
it('tracks a new connection event - public cloud', async function () {
const trackEvent = once(process, 'compass:track');
- const connectionInfo = {
+ const connection: ConnectionInfo = {
+ ...connectionInfo,
connectionOptions: {
connectionString: 'mongodb://13.248.118.1',
},
};
- trackNewConnectionEvent(connectionInfo, dataService, logger, track);
+ trackNewConnectionEvent(connection, dataService, logger, track);
const [{ properties }] = await trackEvent;
const expected = {
@@ -363,6 +385,7 @@ describe('connection tracking', function () {
has_kms_gcp: false,
has_kms_kmip: false,
has_kms_azure: false,
+ connection_id: 'TEST',
};
expect(properties).to.deep.equal(expected);
@@ -370,13 +393,14 @@ describe('connection tracking', function () {
it('tracks a new connection event - public ip but not aws/gcp/azure', async function () {
const trackEvent = once(process, 'compass:track');
- const connectionInfo = {
+ const connection: ConnectionInfo = {
+ ...connectionInfo,
connectionOptions: {
connectionString: 'mongodb://google.com',
},
};
- trackNewConnectionEvent(connectionInfo, dataService, logger, track);
+ trackNewConnectionEvent(connection, dataService, logger, track);
const [{ properties }] = await trackEvent;
const expected = {
@@ -404,6 +428,7 @@ describe('connection tracking', function () {
has_kms_gcp: false,
has_kms_kmip: false,
has_kms_azure: false,
+ connection_id: 'TEST',
};
expect(properties).to.deep.equal(expected);
@@ -411,13 +436,14 @@ describe('connection tracking', function () {
it('tracks a new connection event - nonexistent', async function () {
const trackEvent = once(process, 'compass:track');
- const connectionInfo = {
+ const connection: ConnectionInfo = {
+ ...connectionInfo,
connectionOptions: {
connectionString: 'mongodb://nonexistent',
},
};
- trackNewConnectionEvent(connectionInfo, dataService, logger, track);
+ trackNewConnectionEvent(connection, dataService, logger, track);
const [{ properties }] = await trackEvent;
const expected = {
@@ -444,6 +470,7 @@ describe('connection tracking', function () {
has_kms_gcp: false,
has_kms_kmip: false,
has_kms_azure: false,
+ connection_id: 'TEST',
};
expect(properties).to.deep.equal(expected);
@@ -451,13 +478,14 @@ describe('connection tracking', function () {
it('tracks a new connection event - nonexistent SRV', async function () {
const trackEvent = once(process, 'compass:track');
- const connectionInfo = {
+ const connection: ConnectionInfo = {
+ ...connectionInfo,
connectionOptions: {
connectionString: 'mongodb+srv://nonexistent',
},
};
- trackNewConnectionEvent(connectionInfo, dataService, logger, track);
+ trackNewConnectionEvent(connection, dataService, logger, track);
const [{ properties }] = await trackEvent;
const expected = {
@@ -484,6 +512,7 @@ describe('connection tracking', function () {
has_kms_gcp: false,
has_kms_kmip: false,
has_kms_azure: false,
+ connection_id: 'TEST',
};
expect(properties).to.deep.equal(expected);
@@ -496,12 +525,13 @@ describe('connection tracking', function () {
authMechanism || 'DEFAULT'
} auth`, async function () {
const trackEvent = once(process, 'compass:track');
- const connectionInfo = {
+ const connection: ConnectionInfo = {
+ ...connectionInfo,
connectionOptions: {
connectionString: `mongodb://root:pwd@127.0.0.1?authMechanism=${authMechanism}`,
},
};
- trackNewConnectionEvent(connectionInfo, dataService, logger, track);
+ trackNewConnectionEvent(connection, dataService, logger, track);
const [{ properties }] = await trackEvent;
expect(properties.auth_type).to.equal(authMechanism || 'DEFAULT');
});
@@ -510,31 +540,34 @@ describe('connection tracking', function () {
it('tracks a new connection event - no auth', async function () {
const trackEvent = once(process, 'compass:track');
- const connectionInfo = {
+ const connection: ConnectionInfo = {
+ ...connectionInfo,
connectionOptions: {
connectionString: 'mongodb://127.0.0.1?authMechanism=',
},
};
- trackNewConnectionEvent(connectionInfo, dataService, logger, track);
+ trackNewConnectionEvent(connection, dataService, logger, track);
const [{ properties }] = await trackEvent;
expect(properties.auth_type).to.equal('NONE');
});
it('tracks a new connection event - no tunnel', async function () {
const trackEvent = once(process, 'compass:track');
- const connectionInfo = {
+ const connection: ConnectionInfo = {
+ ...connectionInfo,
connectionOptions: {
connectionString: 'mongodb://127.0.0.1?authMechanism=',
},
};
- trackNewConnectionEvent(connectionInfo, dataService, logger, track);
+ trackNewConnectionEvent(connection, dataService, logger, track);
const [{ properties }] = await trackEvent;
expect(properties.tunnel).to.equal('none');
});
it('tracks a new connection event - ssh tunnel', async function () {
const trackEvent = once(process, 'compass:track');
- const connectionInfo = {
+ const connection: ConnectionInfo = {
+ ...connectionInfo,
connectionOptions: {
connectionString: 'mongodb://127.0.0.1?authMechanism=',
sshTunnel: {
@@ -544,19 +577,20 @@ describe('connection tracking', function () {
},
},
};
- trackNewConnectionEvent(connectionInfo, dataService, logger, track);
+ trackNewConnectionEvent(connection, dataService, logger, track);
const [{ properties }] = await trackEvent;
expect(properties.tunnel).to.equal('ssh');
});
it('tracks a new connection event - SRV', async function () {
const trackEvent = once(process, 'compass:track');
- const connectionInfo = {
+ const connection: ConnectionInfo = {
+ ...connectionInfo,
connectionOptions: {
connectionString: 'mongodb+srv://127.0.0.1',
},
};
- trackNewConnectionEvent(connectionInfo, dataService, logger, track);
+ trackNewConnectionEvent(connection, dataService, logger, track);
const [{ properties }] = await trackEvent;
expect(properties.is_srv).to.equal(true);
});
@@ -592,12 +626,13 @@ describe('connection tracking', function () {
getCurrentTopologyType: () => 'Unknown',
};
const trackEvent = once(process, 'compass:track');
- const connectionInfo = {
+ const connection: ConnectionInfo = {
+ ...connectionInfo,
connectionOptions: {
connectionString: 'mongodb://127.0.0.1',
},
};
- trackNewConnectionEvent(connectionInfo, mockDataService, logger, track);
+ trackNewConnectionEvent(connection, mockDataService, logger, track);
const [{ properties }] = await trackEvent;
expect(properties.is_atlas).to.equal(true);
@@ -642,12 +677,13 @@ describe('connection tracking', function () {
getCurrentTopologyType: () => 'Sharded',
};
const trackEvent = once(process, 'compass:track');
- const connectionInfo = {
+ const connection: ConnectionInfo = {
+ ...connectionInfo,
connectionOptions: {
connectionString: 'mongodb://127.0.0.1',
},
};
- trackNewConnectionEvent(connectionInfo, mockDataService, logger, track);
+ trackNewConnectionEvent(connection, mockDataService, logger, track);
const [{ properties }] = await trackEvent;
expect(properties.is_atlas).to.equal(false);
@@ -664,7 +700,8 @@ describe('connection tracking', function () {
it('tracks connection error event', async function () {
const trackEvent = once(process, 'compass:track');
- const connectionInfo = {
+ const connection: ConnectionInfo = {
+ ...connectionInfo,
connectionOptions: {
connectionString: 'mongodb://localhost:27017',
},
@@ -672,7 +709,7 @@ describe('connection tracking', function () {
const connectionError = new Error();
- trackConnectionFailedEvent(connectionInfo, connectionError, logger, track);
+ trackConnectionFailedEvent(connection, connectionError, logger, track);
const [{ properties }] = await trackEvent;
const expected = {
@@ -692,6 +729,7 @@ describe('connection tracking', function () {
has_kms_gcp: false,
has_kms_kmip: false,
has_kms_azure: false,
+ connection_id: 'TEST',
};
expect(properties).to.deep.equal(expected);
@@ -699,7 +737,8 @@ describe('connection tracking', function () {
it('tracks a new connection event - csfle on', async function () {
const trackEvent = once(process, 'compass:track');
- const connectionInfo: Pick = {
+ const connection: ConnectionInfo = {
+ ...connectionInfo,
connectionOptions: {
connectionString: 'mongodb://127.128.0.0',
fleOptions: {
@@ -717,7 +756,7 @@ describe('connection tracking', function () {
},
};
- trackNewConnectionEvent(connectionInfo, dataService, logger, track);
+ trackNewConnectionEvent(connection, dataService, logger, track);
const [{ properties }] = await trackEvent;
const expected = {
@@ -745,6 +784,7 @@ describe('connection tracking', function () {
has_kms_gcp: false,
has_kms_kmip: false,
has_kms_azure: false,
+ connection_id: 'TEST',
};
expect(properties).to.deep.equal(expected);
diff --git a/packages/compass/src/app/utils/telemetry.ts b/packages/compass/src/app/utils/telemetry.ts
index 96172df3cc9..75760b364b8 100644
--- a/packages/compass/src/app/utils/telemetry.ts
+++ b/packages/compass/src/app/utils/telemetry.ts
@@ -151,24 +151,25 @@ async function getConnectionData({
}
export function trackConnectionAttemptEvent(
- { favorite, lastUsed }: Pick,
+ connectionInfo: ConnectionInfo,
{ debug }: Logger,
track: TrackFunction
): void {
try {
+ const { favorite, lastUsed } = connectionInfo;
const trackEvent = {
is_favorite: Boolean(favorite),
is_recent: Boolean(lastUsed && !favorite),
is_new: !lastUsed,
};
- track('Connection Attempt', trackEvent);
+ track('Connection Attempt', trackEvent, connectionInfo);
} catch (error) {
debug('trackConnectionAttemptEvent failed', error);
}
}
export function trackNewConnectionEvent(
- connectionInfo: Pick,
+ connectionInfo: ConnectionInfo,
dataService: Pick,
{ debug }: Logger,
track: TrackFunction
@@ -193,14 +194,14 @@ export function trackNewConnectionEvent(
};
return trackEvent;
};
- track('New Connection', callback);
+ track('New Connection', callback, connectionInfo);
} catch (error) {
debug('trackNewConnectionEvent failed', error);
}
}
export function trackConnectionFailedEvent(
- connectionInfo: Pick | null,
+ connectionInfo: ConnectionInfo | null,
connectionError: Error & Partial>,
{ debug }: Logger,
track: TrackFunction
@@ -216,7 +217,7 @@ export function trackConnectionFailedEvent(
};
return trackEvent;
};
- track('Connection Failed', callback);
+ track('Connection Failed', callback, connectionInfo ?? undefined);
} catch (error) {
debug('trackConnectionFailedEvent failed', error);
}
diff --git a/packages/connection-form/package.json b/packages/connection-form/package.json
index af1e72e2a81..ae25ea705bf 100644
--- a/packages/connection-form/package.json
+++ b/packages/connection-form/package.json
@@ -13,7 +13,7 @@
"email": "compass@mongodb.com"
},
"homepage": "https://github.com/mongodb-js/compass",
- "version": "1.31.0",
+ "version": "1.34.0",
"repository": {
"type": "git",
"url": "https://github.com/mongodb-js/compass.git"
@@ -47,21 +47,21 @@
"reformat": "npm run eslint . -- --fix && npm run prettier -- --write ."
},
"dependencies": {
- "@mongodb-js/compass-components": "^1.26.0",
- "@mongodb-js/compass-editor": "^0.25.0",
- "@mongodb-js/connection-info": "^0.4.1",
- "compass-preferences-model": "^2.23.1",
- "ejson-shell-parser": "^2.0.1",
+ "@mongodb-js/compass-components": "^1.28.0",
+ "@mongodb-js/compass-editor": "^0.27.0",
+ "@mongodb-js/connection-info": "^0.5.1",
+ "@mongodb-js/shell-bson-parser": "^1.1.0",
+ "compass-preferences-model": "^2.25.0",
"lodash": "^4.17.21",
"mongodb": "^6.7.0",
"mongodb-build-info": "^1.7.2",
"mongodb-connection-string-url": "^3.0.1",
- "mongodb-data-service": "^22.21.1",
- "mongodb-query-parser": "^4.1.2",
+ "mongodb-data-service": "^22.22.1",
+ "mongodb-query-parser": "^4.2.0",
"react": "^17.0.2"
},
"devDependencies": {
- "@mongodb-js/eslint-config-compass": "^1.1.2",
+ "@mongodb-js/eslint-config-compass": "^1.1.3",
"@mongodb-js/mocha-config-compass": "^1.3.9",
"@mongodb-js/prettier-config-compass": "^1.0.2",
"@mongodb-js/tsconfig-compass": "^1.0.4",
diff --git a/packages/connection-form/src/utils/csfle-handler.ts b/packages/connection-form/src/utils/csfle-handler.ts
index 27605d7cf9a..8afc3b71eac 100644
--- a/packages/connection-form/src/utils/csfle-handler.ts
+++ b/packages/connection-form/src/utils/csfle-handler.ts
@@ -8,7 +8,9 @@ import type {
} from 'mongodb';
import type { KMSProviderName } from './csfle-kms-fields';
import { toJSString } from 'mongodb-query-parser';
-import parseShellStringToEJSON, { ParseMode } from 'ejson-shell-parser';
+import parseShellStringToEJSON, {
+ ParseMode,
+} from '@mongodb-js/shell-bson-parser';
const DEFAULT_FLE_OPTIONS: NonNullable = {
storeCredentials: false,
diff --git a/packages/connection-info/package.json b/packages/connection-info/package.json
index e98a6170588..b6cec10a409 100644
--- a/packages/connection-info/package.json
+++ b/packages/connection-info/package.json
@@ -13,7 +13,7 @@
"email": "compass@mongodb.com"
},
"homepage": "https://github.com/mongodb-js/compass",
- "version": "0.4.1",
+ "version": "0.5.1",
"repository": {
"type": "git",
"url": "https://github.com/mongodb-js/compass.git"
@@ -53,10 +53,10 @@
"lodash": "^4.17.21",
"mongodb": "^6.7.0",
"mongodb-connection-string-url": "^3.0.1",
- "mongodb-data-service": "^22.21.1"
+ "mongodb-data-service": "^22.22.1"
},
"devDependencies": {
- "@mongodb-js/eslint-config-compass": "^1.1.2",
+ "@mongodb-js/eslint-config-compass": "^1.1.3",
"@mongodb-js/mocha-config-compass": "^1.3.9",
"@mongodb-js/prettier-config-compass": "^1.0.2",
"@mongodb-js/tsconfig-compass": "^1.0.4",
diff --git a/packages/connection-storage/package.json b/packages/connection-storage/package.json
index dc50b16af1d..5c19bcfeca6 100644
--- a/packages/connection-storage/package.json
+++ b/packages/connection-storage/package.json
@@ -13,7 +13,7 @@
"email": "compass@mongodb.com"
},
"homepage": "https://github.com/mongodb-js/compass",
- "version": "0.14.1",
+ "version": "0.16.0",
"repository": {
"type": "git",
"url": "https://github.com/mongodb-js/compass.git"
@@ -56,23 +56,23 @@
"reformat": "npm run eslint . -- --fix && npm run prettier -- --write ."
},
"dependencies": {
- "@mongodb-js/compass-logging": "^1.3.1",
- "@mongodb-js/compass-telemetry": "^1.0.1",
- "@mongodb-js/compass-user-data": "^0.2.1",
- "@mongodb-js/compass-utils": "^0.6.5",
- "@mongodb-js/connection-info": "^0.4.1",
+ "@mongodb-js/compass-logging": "^1.4.1",
+ "@mongodb-js/compass-telemetry": "^1.1.1",
+ "@mongodb-js/compass-user-data": "^0.3.1",
+ "@mongodb-js/compass-utils": "^0.6.7",
+ "@mongodb-js/connection-info": "^0.5.1",
"bson": "^6.7.0",
- "compass-preferences-model": "^2.23.1",
- "electron": "^29.4.3",
- "hadron-app-registry": "^9.1.12",
- "hadron-ipc": "^3.2.16",
+ "compass-preferences-model": "^2.25.0",
+ "electron": "^29.4.5",
+ "hadron-app-registry": "^9.2.1",
+ "hadron-ipc": "^3.2.18",
"keytar": "^7.9.0",
"lodash": "^4.17.21",
"mongodb-connection-string-url": "^3.0.1",
"react": "^17.0.2"
},
"devDependencies": {
- "@mongodb-js/eslint-config-compass": "^1.1.2",
+ "@mongodb-js/eslint-config-compass": "^1.1.3",
"@mongodb-js/mocha-config-compass": "^1.3.9",
"@mongodb-js/prettier-config-compass": "^1.0.2",
"@mongodb-js/tsconfig-compass": "^1.0.4",
diff --git a/packages/data-service/package.json b/packages/data-service/package.json
index 41152cdb7c5..542843b5487 100644
--- a/packages/data-service/package.json
+++ b/packages/data-service/package.json
@@ -7,7 +7,7 @@
"email": "compass@mongodb.com"
},
"homepage": "https://github.com/mongodb-js/compass",
- "version": "22.21.1",
+ "version": "22.22.1",
"repository": {
"type": "git",
"url": "https://github.com/mongodb-js/compass.git"
@@ -51,10 +51,10 @@
"reformat": "npm run eslint . -- --fix && npm run prettier -- --write ."
},
"dependencies": {
- "@mongodb-js/compass-logging": "^1.3.1",
- "@mongodb-js/compass-utils": "^0.6.5",
+ "@mongodb-js/compass-logging": "^1.4.1",
+ "@mongodb-js/compass-utils": "^0.6.7",
"@mongodb-js/devtools-connect": "^3.0.1",
- "@mongodb-js/ssh-tunnel": "^2.2.1",
+ "@mongodb-js/ssh-tunnel": "^2.3.1",
"bson": "^6.7.0",
"lodash": "^4.17.21",
"mongodb": "^6.7.0",
@@ -63,9 +63,9 @@
"mongodb-ns": "^2.4.2"
},
"devDependencies": {
- "@mongodb-js/compass-test-server": "^0.1.17",
+ "@mongodb-js/compass-test-server": "^0.1.18",
"@mongodb-js/devtools-docker-test-envs": "^1.3.2",
- "@mongodb-js/eslint-config-compass": "^1.1.2",
+ "@mongodb-js/eslint-config-compass": "^1.1.3",
"@mongodb-js/mocha-config-compass": "^1.3.9",
"@mongodb-js/oidc-plugin": "^1.0.0",
"@mongodb-js/prettier-config-compass": "^1.0.2",
diff --git a/packages/database-model/package.json b/packages/database-model/package.json
index 652820dda3b..67672d8710c 100644
--- a/packages/database-model/package.json
+++ b/packages/database-model/package.json
@@ -2,7 +2,7 @@
"name": "mongodb-database-model",
"description": "MongoDB database model",
"author": "Lucas Hrabovsky ",
- "version": "2.21.1",
+ "version": "2.22.1",
"bugs": {
"url": "https://jira.mongodb.org/projects/COMPASS/issues",
"email": "compass@mongodb.com"
@@ -30,11 +30,11 @@
"dependencies": {
"ampersand-collection": "^2.0.2",
"ampersand-model": "^8.0.1",
- "mongodb-collection-model": "^5.21.1",
- "mongodb-data-service": "^22.21.1"
+ "mongodb-collection-model": "^5.22.1",
+ "mongodb-data-service": "^22.22.1"
},
"devDependencies": {
- "@mongodb-js/eslint-config-compass": "^1.1.2",
+ "@mongodb-js/eslint-config-compass": "^1.1.3",
"@mongodb-js/prettier-config-compass": "^1.0.2",
"depcheck": "^1.4.1",
"eslint": "^7.25.0",
diff --git a/packages/databases-collections-list/package.json b/packages/databases-collections-list/package.json
index b7fdae15cc1..f5497e236ab 100644
--- a/packages/databases-collections-list/package.json
+++ b/packages/databases-collections-list/package.json
@@ -13,7 +13,7 @@
"email": "compass@mongodb.com"
},
"homepage": "https://github.com/mongodb-js/compass",
- "version": "1.30.0",
+ "version": "1.33.0",
"repository": {
"type": "git",
"url": "https://github.com/mongodb-js/compass.git"
@@ -48,13 +48,17 @@
"reformat": "npm run eslint . -- --fix && npm run prettier -- --write ."
},
"dependencies": {
- "@mongodb-js/compass-components": "^1.26.0",
- "@mongodb-js/compass-telemetry": "^1.0.1",
- "compass-preferences-model": "^2.23.1",
+ "@mongodb-js/compass-components": "^1.28.0",
+ "@mongodb-js/compass-connections": "^1.36.0",
+ "@mongodb-js/compass-telemetry": "^1.1.1",
+ "@mongodb-js/compass-workspaces": "^0.17.0",
+ "@mongodb-js/connection-info": "^0.5.1",
+ "compass-preferences-model": "^2.25.0",
+ "mongodb-ns": "^2.4.2",
"react": "^17.0.2"
},
"devDependencies": {
- "@mongodb-js/eslint-config-compass": "^1.1.2",
+ "@mongodb-js/eslint-config-compass": "^1.1.3",
"@mongodb-js/mocha-config-compass": "^1.3.9",
"@mongodb-js/prettier-config-compass": "^1.0.2",
"@mongodb-js/tsconfig-compass": "^1.0.4",
diff --git a/packages/databases-collections-list/src/collections.tsx b/packages/databases-collections-list/src/collections.tsx
index 6baa14c908a..792ec96bd75 100644
--- a/packages/databases-collections-list/src/collections.tsx
+++ b/packages/databases-collections-list/src/collections.tsx
@@ -1,11 +1,5 @@
-/* eslint-disable react/prop-types */
-import React, { useMemo } from 'react';
-import {
- type BreadcrumbItem,
- Breadcrumbs,
- css,
- spacing,
-} from '@mongodb-js/compass-components';
+import React from 'react';
+import { css, spacing } from '@mongodb-js/compass-components';
import { compactBytes, compactNumber } from './format';
import type { BadgeProp } from './namespace-card';
import { NamespaceItemCard } from './namespace-card';
@@ -86,47 +80,25 @@ const pageContainerStyles = css({
flexDirection: 'column',
});
-const breadcrumbStyles = css({
- paddingLeft: spacing[3],
- paddingTop: spacing[3],
- paddingBottom: spacing[2],
-});
-
const CollectionsList: React.FunctionComponent<{
- connectionTitle: string;
- databaseName: string;
+ namespace: string;
collections: Collection[];
onCollectionClick(id: string): void;
- onClickConnectionBreadcrumb(): void;
onDeleteCollectionClick?: (id: string) => void;
onCreateCollectionClick?: () => void;
onRefreshClick?: () => void;
}> = ({
- connectionTitle,
- databaseName,
+ namespace,
collections,
- onClickConnectionBreadcrumb,
onCollectionClick,
onCreateCollectionClick,
onDeleteCollectionClick,
onRefreshClick,
}) => {
- const breadcrumbItems = useMemo(() => {
- return [
- {
- name: connectionTitle,
- onClick: () => onClickConnectionBreadcrumb(),
- },
- {
- name: databaseName,
- },
- ] as BreadcrumbItem[];
- }, [connectionTitle, databaseName, onClickConnectionBreadcrumb]);
-
return (
-
void;
onCreateDatabaseClick?: () => void;
onRefreshClick?: () => void;
+ renderLoadSampleDataBanner?: () => React.ReactNode;
}> = ({
databases,
onDatabaseClick,
onCreateDatabaseClick,
onDeleteDatabaseClick,
onRefreshClick,
+ renderLoadSampleDataBanner,
}) => {
return (
);
}}
+ renderLoadSampleDataBanner={renderLoadSampleDataBanner}
>
);
};
diff --git a/packages/databases-collections-list/src/index.spec.tsx b/packages/databases-collections-list/src/index.spec.tsx
index fb61b66d3ee..7d6cccfb37e 100644
--- a/packages/databases-collections-list/src/index.spec.tsx
+++ b/packages/databases-collections-list/src/index.spec.tsx
@@ -101,11 +101,9 @@ describe('databases and collections list', function () {
render(
{}}
>
);
@@ -122,32 +120,11 @@ describe('databases and collections list', function () {
expect(clickSpy).to.be.calledWith('bar.bar');
});
- it('should notify when the connection name is clicked', function () {
- const clickSpy = Sinon.spy();
- const connectionClickSpy = Sinon.spy();
-
- render(
-
- );
-
- userEvent.click(screen.getByText('My Connection'));
-
- expect(connectionClickSpy).to.be.called;
- });
-
it('should not display statistics (except storage size) on timeseries collection card', function () {
render(
{}}
onCollectionClick={() => {}}
>
);
diff --git a/packages/databases-collections-list/src/items-grid.tsx b/packages/databases-collections-list/src/items-grid.tsx
index 6cbb0a39597..c2bb0e2dc0c 100644
--- a/packages/databases-collections-list/src/items-grid.tsx
+++ b/packages/databases-collections-list/src/items-grid.tsx
@@ -1,5 +1,4 @@
-/* eslint-disable react/prop-types */
-import React, { useContext, useCallback } from 'react';
+import React, { useCallback, useMemo } from 'react';
import {
css,
cx,
@@ -7,26 +6,34 @@ import {
VirtualGrid,
useSortControls,
useSortedItems,
+ WorkspaceContainer,
+ Button,
+ Icon,
+ Breadcrumbs,
} from '@mongodb-js/compass-components';
import { useTelemetry } from '@mongodb-js/compass-telemetry/provider';
import type { NamespaceItemCardProps } from './namespace-card';
import { useViewTypeControls } from './use-view-type';
import type { ViewType } from './use-view-type';
-import { useCreateControls } from './use-create';
-import { useRefreshControls } from './use-refresh';
+import { useConnectionInfo } from '@mongodb-js/compass-connections/provider';
+import toNS from 'mongodb-ns';
+import { getConnectionTitle } from '@mongodb-js/connection-info';
+import { useOpenWorkspace } from '@mongodb-js/compass-workspaces/provider';
+import { useConnectionInfoAccess } from '@mongodb-js/compass-connections/provider';
+import { usePreferences } from 'compass-preferences-model/provider';
type Item = { _id: string } & Record;
-const row = css({
+const rowStyles = css({
paddingLeft: spacing[3],
paddingRight: spacing[3],
paddingBottom: spacing[2],
columnGap: spacing[2],
});
-const container = css({
+const containerStyles = css({
width: '100%',
- flex: 1,
+ height: '100%',
overflow: 'hidden',
display: 'grid',
gridTemplateRows: 'auto 1fr',
@@ -37,21 +44,10 @@ const container = css({
outline: 'none',
});
-const controls = css({
- display: 'flex',
- padding: spacing[3],
- gap: spacing[2],
- flex: 'none',
-});
-
-export const createButton = css({
+export const createButtonStyles = css({
whiteSpace: 'nowrap',
});
-const control = css({
- flex: 'none',
-});
-
type CallbackProps = {
onItemClick(id: string): void;
onCreateItemClick?: () => void;
@@ -72,6 +68,7 @@ interface RenderItem {
}
type ItemsGridProps = {
+ namespace?: string;
itemType: 'collection' | 'database';
itemGridWidth: number;
itemGridHeight: number;
@@ -84,54 +81,212 @@ type ItemsGridProps = {
onCreateItemClick?: () => void;
onRefreshClick?: () => void;
renderItem: RenderItem;
+ renderLoadSampleDataBanner?: () => React.ReactNode;
};
-const CONTROLS_HEIGHT = (spacing[5] as number) + 36;
+const controlsContainerStyles = css({
+ paddingTop: spacing[200],
+ paddingRight: spacing[400],
+ paddingBottom: spacing[400],
+ paddingLeft: spacing[400],
+
+ display: 'grid',
+ gridTemplate: '1fr / 100%',
+ gap: spacing[200],
+});
+
+const controlRowStyles = css({
+ display: 'flex',
+ alignItems: 'center',
+ gap: spacing[200],
+});
+
+const controlStyles = css({
+ flex: 'none',
+});
-const pushRight = css({
+const breadcrumbContainerStyles = css({
+ display: 'flex',
+ minWidth: 0,
+ paddingTop: spacing[200],
+ paddingBottom: spacing[200],
+});
+
+const pushRightStyles = css({
marginLeft: 'auto',
});
-// We use this context to pass components that are aware of outer state of the
-// v-list to the list header. This is needed so that we can define this outer
-// component outside of the list component scope and avoid constant re-mounts
-// when component constructor is re-created. We do this so that controls can be
-// part of the list header and scroll up when the list is scrolled
-const ControlsContext = React.createContext<{
- createControls: React.ReactElement | null;
- refreshControls: React.ReactElement | null;
- viewTypeControls: React.ReactElement | null;
- sortControls: React.ReactElement | null;
-}>({
- createControls: null,
- refreshControls: null,
- viewTypeControls: null,
- sortControls: null,
+const bannerRowStyles = css({
+ paddingTop: spacing[200],
});
-const GridControls = () => {
- const { createControls, refreshControls, viewTypeControls, sortControls } =
- useContext(ControlsContext);
+function buildChartsUrl(
+ groupId: string,
+ clusterName: string,
+ namespace?: string
+) {
+ const { database } = toNS(namespace ?? '');
+ const url = new URL(`/charts/${groupId}`, window.location.origin);
+ url.searchParams.set('sourceType', 'cluster');
+ url.searchParams.set('instanceName', clusterName);
+ if (database) {
+ url.searchParams.set('database', database);
+ }
+ return url.toString();
+}
+
+const GridControls: React.FunctionComponent<{
+ namespace?: string;
+ itemType: string;
+ sortControls?: React.ReactNode;
+ viewTypeControls?: React.ReactNode;
+ onCreateItemClick?: () => void;
+ onRefreshClick?: () => void;
+ renderLoadSampleDataBanner?: () => React.ReactNode;
+}> = ({
+ namespace,
+ itemType,
+ sortControls,
+ viewTypeControls,
+ onCreateItemClick,
+ onRefreshClick,
+ renderLoadSampleDataBanner,
+}) => {
+ const connectionInfo = useConnectionInfo();
+ const connectionTitle = getConnectionTitle(connectionInfo);
+ const {
+ openDatabasesWorkspace,
+ openCollectionsWorkspace,
+ openShellWorkspace,
+ } = useOpenWorkspace();
+ const { enableShell, enableNewMultipleConnectionSystem } = usePreferences([
+ 'enableShell',
+ 'enableNewMultipleConnectionSystem',
+ ]);
+
+ const showOpenShellButton = enableShell && enableNewMultipleConnectionSystem;
+
+ const breadcrumbs = useMemo(() => {
+ const { database } = toNS(namespace ?? '');
+ const items = [
+ {
+ name: connectionTitle,
+ onClick: () => {
+ openDatabasesWorkspace(connectionInfo.id);
+ },
+ },
+ ];
+
+ if (database) {
+ items.push({
+ name: database,
+ onClick: () => {
+ openCollectionsWorkspace(connectionInfo.id, database);
+ },
+ });
+ }
+
+ return items;
+ }, [
+ connectionInfo.id,
+ connectionTitle,
+ namespace,
+ openCollectionsWorkspace,
+ openDatabasesWorkspace,
+ ]);
+
+ const banner = renderLoadSampleDataBanner?.();
return (
- <>
- {createControls && (
-
- {createControls}
+
+
+
+
- )}
- {refreshControls && (
-
- {refreshControls}
+
+
+ {showOpenShellButton && (
+
+ )}
+
+ {connectionInfo.atlasMetadata && (
+
}
+ >
+ Visualize your data
+
+ )}
+
+ {onCreateItemClick && (
+
+ }
+ onClick={onCreateItemClick}
+ className={createButtonStyles}
+ size="small"
+ >
+ Create {itemType}
+
+
+ )}
+
+ {onRefreshClick && (
+
+ }
+ onClick={onRefreshClick}
+ size="small"
+ >
+ Refresh
+
+
+ )}
+
+
+ {sortControls && viewTypeControls && (
+
+
{sortControls}
+
+ {viewTypeControls}
+
)}
-
{viewTypeControls}
-
{sortControls}
- >
+ {banner &&
{banner}
}
+
);
};
+const itemsGridContainerStyles = css({
+ width: '100%',
+ height: '100%',
+});
+
export const ItemsGrid =
({
+ namespace,
itemType,
itemGridWidth,
itemGridHeight,
@@ -144,16 +299,21 @@ export const ItemsGrid = ({
onCreateItemClick,
onRefreshClick,
renderItem: _renderItem,
+ renderLoadSampleDataBanner,
}: ItemsGridProps): React.ReactElement => {
const track = useTelemetry();
+ const connectionInfoAccess = useConnectionInfoAccess();
const onViewTypeChange = useCallback(
(newType) => {
- track('Switch View Type', { view_type: newType, item_type: itemType });
+ track(
+ 'Switch View Type',
+ { view_type: newType, item_type: itemType },
+ connectionInfoAccess.getCurrentConnectionInfo()
+ );
},
- [itemType, track]
+ [itemType, track, connectionInfoAccess]
);
- const createControls = useCreateControls(itemType, onCreateItemClick);
- const refreshControls = useRefreshControls(onRefreshClick);
+
const [sortControls, sortState] = useSortControls(sortBy);
const [viewTypeControls, viewType] = useViewTypeControls({
onChange: onViewTypeChange,
@@ -181,31 +341,40 @@ export const ItemsGrid = ({
);
return (
-
- sortedItems[index]._id}
- headerHeight={CONTROLS_HEIGHT}
- renderHeader={GridControls}
- classNames={{
- container,
- header: controls,
- row: row,
+
+
+ }
+ >
+ {(scrollTriggerRef) => {
+ return (
+ {
+ return ;
+ }}
+ headerHeight={0}
+ itemKey={(index: number) => sortedItems[index]._id}
+ classNames={{ container: containerStyles, row: rowStyles }}
+ resetActiveItemOnBlur={false}
+ data-testid={`${itemType}-grid`}
+ >
+ );
}}
- resetActiveItemOnBlur={false}
- data-testid={`${itemType}-grid`}
- >
-
+
+
);
};
diff --git a/packages/databases-collections-list/src/namespace-card.tsx b/packages/databases-collections-list/src/namespace-card.tsx
index 50b2852b039..9ef2a8b760d 100644
--- a/packages/databases-collections-list/src/namespace-card.tsx
+++ b/packages/databases-collections-list/src/namespace-card.tsx
@@ -25,7 +25,6 @@ import type {
SignalPopover,
} from '@mongodb-js/compass-components';
import { NamespaceParam } from './namespace-param';
-import type { ItemType } from './use-create';
import type { ViewType } from './use-view-type';
import { usePreference } from 'compass-preferences-model/provider';
@@ -162,7 +161,7 @@ export type DataProp = {
export type NamespaceItemCardProps = {
id: string;
- type: ItemType;
+ type: 'database' | 'collection';
viewType: ViewType;
name: string;
status: 'initial' | 'fetching' | 'refreshing' | 'ready' | 'error';
diff --git a/packages/databases-collections-list/src/use-create.tsx b/packages/databases-collections-list/src/use-create.tsx
deleted file mode 100644
index 308f492dcb5..00000000000
--- a/packages/databases-collections-list/src/use-create.tsx
+++ /dev/null
@@ -1,27 +0,0 @@
-import React from 'react';
-import { Button, Icon } from '@mongodb-js/compass-components';
-import { createButton } from './items-grid';
-
-export type ItemType = 'database' | 'collection';
-
-export function useCreateControls(
- itemType: ItemType,
- onCreateClick?: () => void
-): React.ReactElement | null {
- if (!onCreateClick) {
- return null;
- }
-
- return (
- }
- onClick={() => {
- onCreateClick();
- }}
- className={createButton}
- >
- Create {itemType}
-
- );
-}
diff --git a/packages/databases-collections-list/src/use-refresh.tsx b/packages/databases-collections-list/src/use-refresh.tsx
deleted file mode 100644
index 6d52f018551..00000000000
--- a/packages/databases-collections-list/src/use-refresh.tsx
+++ /dev/null
@@ -1,22 +0,0 @@
-import React from 'react';
-import { Button, Icon } from '@mongodb-js/compass-components';
-
-export function useRefreshControls(
- onRefreshClick?: () => void
-): React.ReactElement | null {
- if (!onRefreshClick) {
- return null;
- }
-
- return (
- }
- onClick={() => {
- onRefreshClick();
- }}
- >
- Refresh
-
- );
-}
diff --git a/packages/databases-collections/package.json b/packages/databases-collections/package.json
index 1b51f769e32..3f17cc64fa2 100644
--- a/packages/databases-collections/package.json
+++ b/packages/databases-collections/package.json
@@ -2,7 +2,7 @@
"name": "@mongodb-js/compass-databases-collections",
"description": "Plugin for viewing the list of, creating, and dropping databases and collections",
"private": true,
- "version": "1.32.0",
+ "version": "1.35.0",
"license": "SSPL",
"homepage": "https://github.com/mongodb-js/compass",
"bugs": {
@@ -42,7 +42,7 @@
"reformat": "npm run eslint . -- --fix && npm run prettier -- --write ."
},
"devDependencies": {
- "@mongodb-js/eslint-config-compass": "^1.1.2",
+ "@mongodb-js/eslint-config-compass": "^1.1.3",
"@mongodb-js/mocha-config-compass": "^1.3.9",
"@mongodb-js/prettier-config-compass": "^1.0.2",
"@mongodb-js/tsconfig-compass": "^1.0.4",
@@ -60,24 +60,23 @@
"typescript": "^5.0.4"
},
"dependencies": {
- "@mongodb-js/compass-app-stores": "^7.19.0",
- "@mongodb-js/compass-components": "^1.26.0",
- "@mongodb-js/compass-connections": "^1.33.0",
- "@mongodb-js/compass-editor": "^0.25.0",
- "@mongodb-js/connection-info": "^0.4.1",
- "@mongodb-js/compass-logging": "^1.3.1",
- "@mongodb-js/compass-telemetry": "^1.0.1",
- "@mongodb-js/compass-workspaces": "^0.14.0",
- "@mongodb-js/databases-collections-list": "^1.30.0",
- "@mongodb-js/my-queries-storage": "^0.10.0",
- "compass-preferences-model": "^2.23.1",
- "hadron-app-registry": "^9.1.12",
+ "@mongodb-js/compass-app-stores": "^7.22.0",
+ "@mongodb-js/compass-components": "^1.28.0",
+ "@mongodb-js/compass-connections": "^1.36.0",
+ "@mongodb-js/compass-editor": "^0.27.0",
+ "@mongodb-js/compass-logging": "^1.4.1",
+ "@mongodb-js/compass-telemetry": "^1.1.1",
+ "@mongodb-js/compass-workspaces": "^0.17.0",
+ "@mongodb-js/databases-collections-list": "^1.33.0",
+ "@mongodb-js/my-queries-storage": "^0.13.0",
+ "compass-preferences-model": "^2.25.0",
+ "hadron-app-registry": "^9.2.1",
"lodash": "^4.17.21",
- "mongodb-collection-model": "^5.21.1",
- "mongodb-database-model": "^2.21.1",
- "mongodb-instance-model": "^12.22.1",
+ "mongodb-collection-model": "^5.22.1",
+ "mongodb-database-model": "^2.22.1",
+ "mongodb-instance-model": "^12.23.1",
"mongodb-ns": "^2.4.2",
- "mongodb-query-parser": "^4.1.2",
+ "mongodb-query-parser": "^4.2.0",
"prop-types": "^15.7.2",
"react": "^17.0.2",
"react-redux": "^8.1.3",
diff --git a/packages/databases-collections/src/components/collections.tsx b/packages/databases-collections/src/components/collections.tsx
index 89c5224164f..7a6b202a33a 100644
--- a/packages/databases-collections/src/components/collections.tsx
+++ b/packages/databases-collections/src/components/collections.tsx
@@ -17,7 +17,6 @@ import type Collection from 'mongodb-collection-model';
import toNS from 'mongodb-ns';
import { useOpenWorkspace } from '@mongodb-js/compass-workspaces/provider';
import { useConnectionInfo } from '@mongodb-js/compass-connections/provider';
-import { getConnectionTitle } from '@mongodb-js/connection-info';
import { usePreference } from 'compass-preferences-model/provider';
import {
useTrackOnChange,
@@ -57,14 +56,14 @@ const Collections: React.FunctionComponent = ({
}, [isCompassInWritableMode, isInstanceWritable]);
const connectionInfo = useConnectionInfo();
const { id: connectionId } = connectionInfo;
- const { openDatabasesWorkspace, openCollectionWorkspace } =
- useOpenWorkspace();
+ const { openCollectionWorkspace } = useOpenWorkspace();
- const parsedNS = toNS(namespace);
-
- useTrackOnChange((track: TrackFunction) => {
- track('Screen', { name: 'collections' });
- }, []);
+ useTrackOnChange(
+ (track: TrackFunction) => {
+ track('Screen', { name: 'collections' }, connectionInfo);
+ },
+ [connectionInfo]
+ );
const onCollectionClick = useCallback(
(ns: string) => {
@@ -84,10 +83,6 @@ const Collections: React.FunctionComponent = ({
[connectionId, _onDeleteCollectionClick]
);
- const onClickConnectionBreadcrumb = useCallback(() => {
- openDatabasesWorkspace(connectionId);
- }, [connectionId, openDatabasesWorkspace]);
-
if (collectionsLoadingStatus === 'error') {
return (
@@ -101,10 +96,7 @@ const Collections: React.FunctionComponent
= ({
}
const actions = Object.assign(
- {
- onCollectionClick,
- onRefreshClick,
- },
+ { onCollectionClick, onRefreshClick },
isEditable
? {
onCreateCollectionClick,
@@ -115,10 +107,8 @@ const Collections: React.FunctionComponent = ({
return (
);
diff --git a/packages/databases-collections/src/components/databases.tsx b/packages/databases-collections/src/components/databases.tsx
index 3372e77e8ad..cc64f157588 100644
--- a/packages/databases-collections/src/components/databases.tsx
+++ b/packages/databases-collections/src/components/databases.tsx
@@ -23,9 +23,14 @@ import {
useTrackOnChange,
type TrackFunction,
} from '@mongodb-js/compass-telemetry/provider';
+import toNS from 'mongodb-ns';
+import {
+ LoadSampleDataZeroBanner,
+ LoadSampleDataZeroState,
+} from './load-sample-data';
const errorContainerStyles = css({
- padding: spacing[3],
+ padding: spacing[400],
});
const nonGenuineErrorContainerStyles = css({
@@ -70,7 +75,7 @@ type DatabasesProps = {
isDataLake: boolean;
onDeleteDatabaseClick(connectionId: string, ns: string): void;
onCreateDatabaseClick(connectionId: string): void;
- onRefreshClick(): void;
+ onRefreshClick(connectionId: string): void;
};
const Databases: React.FunctionComponent = ({
@@ -82,9 +87,10 @@ const Databases: React.FunctionComponent = ({
isGenuineMongoDB,
onDeleteDatabaseClick: _onDeleteDatabaseClick,
onCreateDatabaseClick: _onCreateDatabaseClick,
- onRefreshClick,
+ onRefreshClick: _onRefreshClick,
}) => {
- const { id: connectionId } = useConnectionInfo();
+ const connectionInfo = useConnectionInfo();
+ const { id: connectionId, atlasMetadata } = connectionInfo;
const isPreferencesReadOnly = usePreference('readOnly');
const { openCollectionsWorkspace } = useOpenWorkspace();
@@ -106,9 +112,40 @@ const Databases: React.FunctionComponent = ({
_onCreateDatabaseClick(connectionId);
}, [connectionId, _onCreateDatabaseClick]);
- useTrackOnChange((track: TrackFunction) => {
- track('Screen', { name: 'databases' });
- }, []);
+ const onRefreshClick = useCallback(() => {
+ _onRefreshClick(connectionId);
+ }, [connectionId, _onRefreshClick]);
+
+ useTrackOnChange(
+ (track: TrackFunction) => {
+ track('Screen', { name: 'databases' }, connectionInfo);
+ },
+ [connectionInfo]
+ );
+
+ const renderLoadSampleDataBanner = useCallback(() => {
+ if (
+ !atlasMetadata ||
+ databases.some((db) => {
+ return !toNS(db.name).specialish;
+ })
+ ) {
+ return null;
+ }
+
+ return (
+
+ );
+ }, [databases, atlasMetadata]);
+
+ const editable = isWritable && !isPreferencesReadOnly;
+
+ if (databasesLoadingStatus === 'fetching') {
+ return null;
+ }
if (databasesLoadingStatus === 'error') {
return (
@@ -126,7 +163,17 @@ const Databases: React.FunctionComponent = ({
return ;
}
- const editable = isWritable && !isPreferencesReadOnly;
+ if (atlasMetadata && databases.length === 0) {
+ return (
+
+ );
+ }
+
const actions = Object.assign(
{
onDatabaseClick,
@@ -140,7 +187,13 @@ const Databases: React.FunctionComponent = ({
: {}
);
- return ;
+ return (
+
+ );
};
const mapStateToProps = (state: DatabasesState) => {
diff --git a/packages/databases-collections/src/components/load-sample-data.tsx b/packages/databases-collections/src/components/load-sample-data.tsx
new file mode 100644
index 00000000000..12b48eb8433
--- /dev/null
+++ b/packages/databases-collections/src/components/load-sample-data.tsx
@@ -0,0 +1,132 @@
+import React from 'react';
+import {
+ Banner,
+ Button,
+ EmptyContent,
+ css,
+ spacing,
+ Icon,
+} from '@mongodb-js/compass-components';
+import { LoadSampleDataZeroGraphic } from './zero-graphic';
+
+function buildAddDataUrl(projectId: string, clusterName: string) {
+ const url = new URL(
+ `/v2/${projectId}#/addData/${encodeURIComponent(clusterName)}/load`,
+ window.location.origin
+ );
+ return url.toString();
+}
+
+const addDataContainerStyles = css({
+ width: '100%',
+ padding: spacing[400],
+});
+
+const loadSampleDataActionsStyles = css({
+ display: 'flex',
+ gap: spacing[300],
+});
+
+export function LoadSampleDataZeroState({
+ projectId,
+ clusterName,
+ canCreateDatabase,
+ onCreateDatabase,
+}: {
+ projectId: string;
+ clusterName: string;
+ canCreateDatabase: boolean;
+ onCreateDatabase: () => void;
+}) {
+ return (
+
+
+ Create database or load sample data to your cluster to quickly get
+ started experimenting with data in MongoDB.
+ >
+ ) : (
+ <>
+ You can load sample data to quickly get started experimenting with
+ data in MongoDB.
+ >
+ )
+ }
+ callToActionLink={
+
+ {canCreateDatabase && (
+
+ )}
+
+
+ }
+ />
+
+ );
+}
+
+const addDataBannerContent = css({
+ display: 'flex',
+ alignItems: 'center',
+ gap: spacing[200],
+});
+
+const addDataBannerButtonStyles = css({
+ marginLeft: 'auto',
+ whiteSpace: 'nowrap',
+ textOverflow: 'ellipsis',
+});
+
+const EmptyElement = () => null;
+
+export function LoadSampleDataZeroBanner({
+ projectId,
+ clusterName,
+}: {
+ projectId: string;
+ clusterName: string;
+}) {
+ return (
+ }>
+
+
+ Working with MongoDB is easy, but first you’ll need some data to get
+ started. Sample data is available for loading.
+
+
+
+
+
+
+ );
+}
diff --git a/packages/databases-collections/src/components/zero-graphic.tsx b/packages/databases-collections/src/components/zero-graphic.tsx
index 1fee09d0745..fda96d6886d 100644
--- a/packages/databases-collections/src/components/zero-graphic.tsx
+++ b/packages/databases-collections/src/components/zero-graphic.tsx
@@ -36,4 +36,38 @@ const ZeroGraphic = () => {
);
};
-export { ZeroGraphic };
+function LoadSampleDataZeroGraphic(
+ props: React.SVGProps & { size?: number }
+) {
+ const size = props.size ?? 60;
+ return (
+
+ );
+}
+
+export { ZeroGraphic, LoadSampleDataZeroGraphic };
diff --git a/packages/databases-collections/src/index.ts b/packages/databases-collections/src/index.ts
index 48a7ec84091..7d4aaab7ba9 100644
--- a/packages/databases-collections/src/index.ts
+++ b/packages/databases-collections/src/index.ts
@@ -1,6 +1,6 @@
import { registerHadronPlugin } from 'hadron-app-registry';
import { createLoggerLocator } from '@mongodb-js/compass-logging/provider';
-import { createTelemetryLocator } from '@mongodb-js/compass-telemetry/provider';
+import { telemetryLocator } from '@mongodb-js/compass-telemetry/provider';
import { connectionsManagerLocator } from '@mongodb-js/compass-connections/provider';
import { mongoDBInstancesManagerLocator } from '@mongodb-js/compass-app-stores/provider';
import { CollectionsPlugin } from './collections-plugin';
@@ -19,6 +19,7 @@ import {
favoriteQueryStorageAccessLocator,
pipelineStorageLocator,
} from '@mongodb-js/my-queries-storage/provider';
+import { connectionRepositoryAccessLocator } from '@mongodb-js/compass-connections/provider';
export const CollectionsWorkspaceTab: WorkspaceComponent<'Collections'> = {
name: 'Collections' as const,
@@ -38,8 +39,9 @@ export const CreateNamespacePlugin = registerHadronPlugin(
},
{
logger: createLoggerLocator('COMPASS-CREATE-NAMESPACE-UI'),
- track: createTelemetryLocator(),
+ track: telemetryLocator,
connectionsManager: connectionsManagerLocator,
+ connectionRepository: connectionRepositoryAccessLocator,
instancesManager: mongoDBInstancesManagerLocator,
workspaces: workspacesServiceLocator,
}
@@ -53,7 +55,8 @@ export const DropNamespacePlugin = registerHadronPlugin(
},
{
logger: createLoggerLocator('COMPASS-DROP-NAMESPACE-UI'),
- track: createTelemetryLocator(),
+ track: telemetryLocator,
+ connectionRepository: connectionRepositoryAccessLocator,
connectionsManager: connectionsManagerLocator,
}
);
diff --git a/packages/databases-collections/src/modules/create-namespace.spec.ts b/packages/databases-collections/src/modules/create-namespace.spec.ts
index d8e1ebb3bd5..163ef3fe032 100644
--- a/packages/databases-collections/src/modules/create-namespace.spec.ts
+++ b/packages/databases-collections/src/modules/create-namespace.spec.ts
@@ -32,7 +32,12 @@ describe('create collection module', function () {
storeAction = action;
},
() => INITIAL_STATE,
- { track: createNoopTrack() } as any
+ {
+ track: createNoopTrack(),
+ connectionRepository: {
+ getConnectionInfoById: () => ({ id: 'TEST' }),
+ },
+ } as any
);
const state = reducer(undefined, storeAction);
expect(state).to.deep.equal({
@@ -54,7 +59,12 @@ describe('create collection module', function () {
storeAction = action;
},
() => INITIAL_STATE,
- { track: createNoopTrack() } as any
+ {
+ track: createNoopTrack(),
+ connectionRepository: {
+ getConnectionInfoById: () => ({ id: 'TEST' }),
+ },
+ } as any
);
const state = reducer(undefined, storeAction);
expect(state).to.deep.equal({
diff --git a/packages/databases-collections/src/modules/create-namespace.ts b/packages/databases-collections/src/modules/create-namespace.ts
index 4ca74e8f4f0..957a0d09a13 100644
--- a/packages/databases-collections/src/modules/create-namespace.ts
+++ b/packages/databases-collections/src/modules/create-namespace.ts
@@ -357,6 +357,7 @@ export const createNamespace = (
{
globalAppRegistry,
connectionsManager,
+ connectionRepository,
logger: { debug },
track,
workspaces,
@@ -391,7 +392,11 @@ export const createNamespace = (
expires: !!data.options.expireAfterSeconds,
};
- track(`${kind} Created`, trackEvent);
+ track(
+ `${kind} Created`,
+ trackEvent,
+ connectionRepository.getConnectionInfoById(connectionId)
+ );
globalAppRegistry.emit('collection-created', namespace, {
connectionId,
diff --git a/packages/databases-collections/src/modules/databases.ts b/packages/databases-collections/src/modules/databases.ts
index 138c723c3dc..511436a7d10 100644
--- a/packages/databases-collections/src/modules/databases.ts
+++ b/packages/databases-collections/src/modules/databases.ts
@@ -85,9 +85,11 @@ export const databasesChanged = (instance: MongoDBInstance) => ({
databases: instance.databases.toJSON(),
});
-export const refreshDatabases = (): DatabasesThunkAction => {
+export const refreshDatabases = (
+ connectionId: string
+): DatabasesThunkAction => {
return (_dispatch, _getState, { globalAppRegistry }) => {
- globalAppRegistry.emit('refresh-databases');
+ globalAppRegistry.emit('refresh-databases', { connectionId });
};
};
diff --git a/packages/databases-collections/src/stores/create-namespace.ts b/packages/databases-collections/src/stores/create-namespace.ts
index db0385e759c..1fbbece17b9 100644
--- a/packages/databases-collections/src/stores/create-namespace.ts
+++ b/packages/databases-collections/src/stores/create-namespace.ts
@@ -3,6 +3,7 @@ import {
ConnectionsManagerEvents,
type ConnectionsManager,
type DataService,
+ type ConnectionRepositoryAccess,
} from '@mongodb-js/compass-connections/provider';
import type { MongoDBInstance } from 'mongodb-instance-model';
import type { Logger } from '@mongodb-js/compass-logging';
@@ -29,6 +30,7 @@ type NS = ReturnType;
export type CreateNamespaceServices = {
connectionsManager: ConnectionsManager;
+ connectionRepository: ConnectionRepositoryAccess;
instancesManager: MongoDBInstancesManager;
globalAppRegistry: AppRegistry;
logger: Logger;
diff --git a/packages/explain-plan-helper/package.json b/packages/explain-plan-helper/package.json
index a0d2092f2a7..7822bed821b 100644
--- a/packages/explain-plan-helper/package.json
+++ b/packages/explain-plan-helper/package.json
@@ -13,7 +13,7 @@
"email": "compass@mongodb.com"
},
"homepage": "https://github.com/mongodb-js/compass",
- "version": "1.1.13",
+ "version": "1.1.14",
"repository": {
"type": "git",
"url": "https://github.com/mongodb-js/compass.git"
@@ -52,7 +52,7 @@
"mongodb-explain-compat": "^3.0.4"
},
"devDependencies": {
- "@mongodb-js/eslint-config-compass": "^1.1.2",
+ "@mongodb-js/eslint-config-compass": "^1.1.3",
"@mongodb-js/mocha-config-compass": "^1.3.9",
"@mongodb-js/prettier-config-compass": "^1.0.2",
"@mongodb-js/tsconfig-compass": "^1.0.4",
diff --git a/packages/hadron-app-registry/package.json b/packages/hadron-app-registry/package.json
index 18613339fab..ad5c07e29bf 100644
--- a/packages/hadron-app-registry/package.json
+++ b/packages/hadron-app-registry/package.json
@@ -7,7 +7,7 @@
"email": "compass@mongodb.com"
},
"homepage": "https://github.com/mongodb-js/compass",
- "version": "9.1.12",
+ "version": "9.2.1",
"repository": {
"type": "git",
"url": "https://github.com/mongodb-js/compass.git"
@@ -50,7 +50,7 @@
"reflux": "^0.4.1"
},
"devDependencies": {
- "@mongodb-js/eslint-config-compass": "^1.1.2",
+ "@mongodb-js/eslint-config-compass": "^1.1.3",
"@mongodb-js/mocha-config-compass": "^1.3.9",
"@mongodb-js/prettier-config-compass": "^1.0.2",
"@mongodb-js/tsconfig-compass": "^1.0.4",
diff --git a/packages/hadron-build/README.md b/packages/hadron-build/README.md
index ba6642497e1..7394ed59470 100644
--- a/packages/hadron-build/README.md
+++ b/packages/hadron-build/README.md
@@ -16,10 +16,6 @@ npm install --save-dev hadron-build;
### `hadron-build info`
-### `hadron-build develop`
-
-### `hadron-build clean`
-
### `hadron-build release`
### `hadron-build upload`
@@ -33,12 +29,9 @@ hadron-build [options]
Commands:
release :shipit:
- clean Remove generated directories.
config Configuration.
- develop [options] Run the app in development mode.
test [options] Run app tests.
upload [options] Upload assets from `release`.
- ui [options] Compile the app UI.
verify [options] Verify the current environment meets the app\'s requirements.
Options:
@@ -74,12 +67,9 @@ Options:
"scripts": {
"check": "hadron-build check",
"test-check-ci": "npm run test",
- "clean": "hadron-build clean",
"compile-ui": "hadron-build ui",
"fmt": "hadron-build fmt",
- "postuninstall": "hadron-build clean",
"release": "hadron-build release",
- "start": "hadron-build develop",
}
}
```
diff --git a/packages/hadron-build/cli.js b/packages/hadron-build/cli.js
index 3bdeea21be6..f05b8f627b7 100755
--- a/packages/hadron-build/cli.js
+++ b/packages/hadron-build/cli.js
@@ -8,12 +8,9 @@ const yargs = require('yargs')
.wrap(120)
.usage('$0 [options]')
.command(require('./commands/release'))
- .command(require('./commands/clean'))
.command(require('./commands/info'))
- .command(require('./commands/develop'))
.command(require('./commands/upload'))
.command(require('./commands/download'))
- .command(require('./commands/ui'))
.command(require('./commands/verify'))
.demand(1, 'Please specify a command.')
.strict()
diff --git a/packages/hadron-build/commands/clean.js b/packages/hadron-build/commands/clean.js
deleted file mode 100644
index daefc037024..00000000000
--- a/packages/hadron-build/commands/clean.js
+++ /dev/null
@@ -1,27 +0,0 @@
-'use strict';
-/**
- * @see [Atom's clean-task.coffee](https://git.io/vaZLw)
- */
-const _ = require('lodash');
-const del = require('del');
-const cli = require('mongodb-js-cli')('hadron-build:clean');
-const ui = require('./ui');
-
-exports.command = 'clean';
-
-exports.describe = 'Remove generated directories.';
-
-exports.builder = _.clone(ui.builder);
-
-exports.tasks = (argv) => {
- return del([
- 'dist/',
- 'node_modules/',
- argv.less_cache
- ]);
-};
-
-exports.handler = (argv) => {
- exports.tasks(argv)
- .catch((err) => cli.abortIfError(err));
-};
diff --git a/packages/hadron-build/commands/develop.js b/packages/hadron-build/commands/develop.js
deleted file mode 100644
index a5329df3300..00000000000
--- a/packages/hadron-build/commands/develop.js
+++ /dev/null
@@ -1,77 +0,0 @@
-'use strict';
-/**
- * TODO (imlucas) Use nodemon so main process has livereload.
- */
-const Promise = require('bluebird');
-const _ = require('lodash');
-const spawn = require('child_process').spawn;
-const ui = require('./ui');
-const verify = require('./verify');
-const cli = require('mongodb-js-cli')('hadron-build:develop');
-const ELECTRON_PREBUILT_EXECUTABLE = require('electron');
-
-exports.command = 'develop [options]';
-
-exports.describe = 'Run the app in development mode.';
-
-exports.builder = {
- devtools: {
- describe: 'Automatically open devtools?',
- type: 'boolean',
- default: false
- },
- interactive: {
- describe: 'Launch a main process repl after app started?',
- type: 'boolean',
- default: false
- }
-};
-
-_.assign(exports.builder, verify.builder, ui.builder);
-
-exports.tasks = function(argv) {
- process.env.NODE_ENV = 'development';
- process.env.DEBUG = 'hadron*,mongo*,electron*';
-
- if (argv.devtools) {
- process.env.DEVTOOLS = '1';
- }
-
- if (argv.options) {
- process.env.HADRON_DISTRIBUTION = argv.options;
- }
-
- return Promise.all([
- verify.tasks(argv),
- ui.tasks(argv)
- ])
- .then( () => exports.startElectronPrebuilt(argv));
-};
-
-exports.handler = (argv) => {
- exports.tasks(argv)
- .catch((err) => cli.abortIfError(err));
-};
-
-exports.startElectronPrebuilt = (argv) => {
- argv = argv || {};
-
- const cwd = argv.cwd || process.cwd();
- const options = {
- env: process.env,
- cwd: cwd,
- stdio: 'inherit'
- };
-
- let args = [];
- if (argv.interactive) {
- args.push('--interactive');
- }
- args.push(cwd);
-
- const p = Promise.defer();
- spawn(ELECTRON_PREBUILT_EXECUTABLE, args, options)
- .on('error', (err) => p.reject(err))
- .on('exit', () => p.resolve());
- return p.promise;
-};
diff --git a/packages/hadron-build/commands/release.js b/packages/hadron-build/commands/release.js
index 488e9c2aff7..4f02af27fd1 100644
--- a/packages/hadron-build/commands/release.js
+++ b/packages/hadron-build/commands/release.js
@@ -31,17 +31,12 @@ const run = require('./../lib/run');
const rebuild = require('@electron/rebuild').rebuild;
const { signArchive } = require('./../lib/signtool');
-const ui = require('./ui');
const verify = require('./verify');
exports.command = 'release';
exports.describe = ':shipit:';
-const compileAssets = module.exports.compileAssets = (CONFIG, done) => {
- run('npm', ['run', 'compile'], { cwd: CONFIG.dir }, done);
-};
-
/**
* Run `electron-packager`
*
@@ -165,6 +160,26 @@ const copy3rdPartyNoticesFile = (CONFIG, done) => {
}
};
+/**
+ * Copies the SBOM file from the compass dir to the root of the archive, similar to
+ * copy3rdPartyNoticesFile().
+ */
+const copySBOMFile = (CONFIG, done) => {
+ try {
+ const sbomPath = path.join(CONFIG.dir, '..', '..', '.sbom', 'sbom.json');
+ const contents = fs.readFileSync(sbomPath);
+ CONFIG.write('.sbom.json', contents).then(() => {
+ cli.debug(format('.sbom.json written'));
+ }).then(() => done(null, true));
+ } catch (err) {
+ if (err.code === 'ENOENT' && !process.env.COMPASS_WAS_COMPILED_AND_HAS_SBOM) {
+ cli.debug(format('Skipping sbom.json writing because the file is missing'));
+ return done(null, true);
+ }
+ done(err);
+ }
+};
+
// Remove a malicious link from chromium license
// See: COMPASS-5333
const fixCompass5333 = (CONFIG, done) => {
@@ -277,7 +292,7 @@ const transformPackageJson = async(CONFIG, done) => {
const depEdge = packageNode.edgesOut.get(depName);
if (!depEdge.to && !depEdge.optional) {
throw new Error(
- `Couldn\'t find node for package ${depName} in arborist tree`
+ `Couldn't find node for package ${depName} in arborist tree`
);
}
if (depEdge.to) {
@@ -480,7 +495,7 @@ exports.builder = {
}
};
-_.assign(exports.builder, ui.builder, verify.builder);
+_.assign(exports.builder, verify.builder);
/**
@@ -529,7 +544,6 @@ exports.run = (argv, done) => {
done
);
}),
- task('compile application assets with webpack', compileAssets),
task('create branded application', createBrandedApplication),
task('create executable symlink', symlinkExecutable),
task('cleanup branded application scaffold', cleanupBrandedApplicationScaffold),
@@ -539,6 +553,7 @@ exports.run = (argv, done) => {
task('fix COMPASS-5333', fixCompass5333),
task('write license file', writeLicenseFile),
task('write 3rd party notices file', copy3rdPartyNoticesFile),
+ task('write sbom file', copySBOMFile),
task('remove development files', removeDevelopmentFiles),
!noAsar && task('create application asar', createApplicationAsar),
!skipInstaller && task('create branded installer', createBrandedInstaller),
diff --git a/packages/hadron-build/commands/ui.js b/packages/hadron-build/commands/ui.js
deleted file mode 100644
index a7aba8d62cc..00000000000
--- a/packages/hadron-build/commands/ui.js
+++ /dev/null
@@ -1,96 +0,0 @@
-'use strict';
-
-const Promise = require('bluebird');
-const path = require('path');
-const LessCache = require('less-cache');
-const fs = require('fs-extra');
-const read = Promise.promisify(fs.readFile);
-
-const cli = require('mongodb-js-cli')('hadron-build:ui');
-const abortIfError = cli.abortIfError.bind(cli);
-
-exports.command = 'ui [options]';
-
-exports.describe = 'Compile the app UI.';
-
-const generateLessCache = (opts) => {
- /**
- * TODO (imlucas) Standardize to use CONFIG.
- */
- const appDir = path.join(opts.dir, 'src', 'app');
- const src = path.join(appDir, 'index.less');
- if (!fs.existsSync(src)) {
- return new Promise(function(resolve) {
- resolve();
- });
- }
-
- if (!opts.less_cache) {
- cli.warn('`less_cache` config option not set! skipping');
- return new Promise(function(resolve) {
- resolve();
- });
- }
- /**
- * TODO (imlucas) Ensure `opts.less_cache` and `src` exist.
- */
- const lessCache = new LessCache({
- cacheDir: opts.less_cache,
- resourcePath: appDir
- });
-
- return read(src, 'utf-8').then((contents) => lessCache.cssForFile(src, contents));
-};
-
-/**
- * @note Durran - quick hack fix to get help cache building. Can be
- * removed when we remove the help window.
- */
-const generateLessHelpCache = (opts) => {
- /**
- * TODO (imlucas) Standardize to use CONFIG.
- */
- const appDir = path.join(opts.dir, 'src', 'app');
- const src = path.join(appDir, 'help.less');
- if (!fs.existsSync(src)) {
- return new Promise(function(resolve) {
- resolve();
- });
- }
-
- if (!opts.less_cache) {
- cli.warn('`less_cache` config option not set! skipping');
- return new Promise(function(resolve) {
- resolve();
- });
- }
- /**
- * TODO (imlucas) Ensure `opts.less_cache` and `src` exist.
- */
- const lessCache = new LessCache({
- cacheDir: opts.less_cache,
- resourcePath: appDir
- });
-
- return read(src, 'utf-8').then((contents) => lessCache.cssForFile(src, contents));
-};
-
-exports.builder = {
- dir: {
- description: 'Project root directory',
- default: process.cwd()
- },
- less_cache: {
- description: 'Path for less cache',
- default: path.join('src', 'app', '.compiled-less')
- }
-};
-
-exports.handler = (argv) => {
- cli.argv = argv;
- exports.tasks(argv).catch(abortIfError);
-};
-
-exports.tasks = (argv) => {
- return generateLessCache(argv).then(() => generateLessHelpCache(argv));
-};
diff --git a/packages/hadron-build/images/logo.png b/packages/hadron-build/images/logo.png
deleted file mode 100644
index 97976939dce..00000000000
Binary files a/packages/hadron-build/images/logo.png and /dev/null differ
diff --git a/packages/hadron-build/images/logo.svg b/packages/hadron-build/images/logo.svg
deleted file mode 100644
index 1d8ecfa2aeb..00000000000
--- a/packages/hadron-build/images/logo.svg
+++ /dev/null
@@ -1,59 +0,0 @@
-
diff --git a/packages/hadron-build/index.js b/packages/hadron-build/index.js
index 8364ce7e2e9..d811147af8d 100644
--- a/packages/hadron-build/index.js
+++ b/packages/hadron-build/index.js
@@ -1,10 +1,7 @@
'use strict';
exports = function() {};
-exports.clean = require('./commands/clean');
-exports.develop = require('./commands/develop');
exports.release = require('./commands/release');
-exports.ui = require('./commands/ui');
exports.upload = require('./commands/upload');
exports.download = require('./commands/download');
exports.verify = require('./commands/verify');
diff --git a/packages/hadron-build/lib/git.js b/packages/hadron-build/lib/git.js
deleted file mode 100644
index 65b3e3919d8..00000000000
--- a/packages/hadron-build/lib/git.js
+++ /dev/null
@@ -1,66 +0,0 @@
-'use strict';
-/* eslint no-sync: 0 */
-const Promise = require('bluebird');
-const execFile = Promise.promisify(require('child_process').execFile);
-const execFileSync = require('child_process').execFileSync;
-const which = require('which');
-
-const parse = (stdout) => {
- const tag = stdout.toString('utf-8').split('\n')[0];
- return tag || null;
-};
-
-/**
- * @param {String} sha
- * @param {Function} done
- * @example
- * > git.isTag('2557def1585d4ac6752f9c21fc4e9af4e41979df');
- * > { '0': null, '1': false }
- * > git.isTag('1a65be32d833f0eb5b3e3c68b15dbeff20ddcd35');
- * > { '0': null, '1': true }
- * @return {Promise}
- */
-exports.isTag = (sha) => {
- return exports.getTag(sha)
- .then((tag) => tag !== null);
-};
-
-exports.isTagSync = (sha) => {
- return exports.getTagSync(sha) !== null;
-};
-
-const getExecArgs = (sha) => {
- const GIT = which.sync('git');
- const opts = {
- cwd: process.cwd(),
- env: process.env
- };
-
- const args = [
- 'describe',
- '--exact-match',
- sha
- ];
-
- return [
- GIT, args, opts
- ];
-};
-
-/**
- * @param {String} sha
- * @param {Function} done
- * @example
- * > git.getTag('2557def1585d4ac6752f9c21fc4e9af4e41979df');
- * > { '0': null, '1': null }
- * > git.getGitTag('1a65be32d833f0eb5b3e3c68b15dbeff20ddcd35');
- > { '0': null, '1': 'v1.2.0-pre.0' }
- * @return {Promise}
- */
-exports.getTag = (sha) => {
- return execFile.apply(null, getExecArgs(sha)).then(parse);
-};
-
-exports.getTagSync = (sha) => {
- return parse(execFileSync.apply(null, getExecArgs(sha)));
-};
diff --git a/packages/hadron-build/package.json b/packages/hadron-build/package.json
index 0634e904029..b76376804e3 100644
--- a/packages/hadron-build/package.json
+++ b/packages/hadron-build/package.json
@@ -1,7 +1,7 @@
{
"name": "hadron-build",
"description": "Tooling for Hadron apps like Compass",
- "version": "25.5.3",
+ "version": "25.5.5",
"scripts": {
"check": "npm run lint && npm run depcheck",
"test": "mocha -R spec",
@@ -28,13 +28,12 @@
"@octokit/rest": "^18.6.2",
"asar": "^3.0.3",
"async": "^3.2.2",
- "bluebird": "^3.7.2",
"chalk": "^4.1.2",
"cli-table": "^0.3.1",
"debug": "^4.3.4",
"del": "^2.0.2",
"download": "^8.0.0",
- "electron": "^29.4.3",
+ "electron": "^29.4.5",
"electron-packager": "^15.5.1",
"electron-packager-plugin-non-proprietary-codecs-ffmpeg": "^1.0.2",
"flatnest": "^1.0.0",
@@ -45,7 +44,6 @@
"js-yaml": "^4.1.0",
"json-diff": "^0.9.0",
"jszip": "^3.5.0",
- "less-cache": "^1.1.0",
"lodash": "^4.17.21",
"moment": "^2.29.4",
"mongodb-js-cli": "^0.0.3",
@@ -60,7 +58,7 @@
"zip-folder": "^1.0.0"
},
"devDependencies": {
- "@mongodb-js/eslint-config-compass": "^1.1.2",
+ "@mongodb-js/eslint-config-compass": "^1.1.3",
"chai": "^4.2.0",
"depcheck": "^1.4.1",
"eslint": "^7.25.0",
diff --git a/packages/hadron-build/test/fixtures/hadron-app/package.json b/packages/hadron-build/test/fixtures/hadron-app/package.json
index a16b1bb6485..2ebf3eda63c 100644
--- a/packages/hadron-build/test/fixtures/hadron-app/package.json
+++ b/packages/hadron-build/test/fixtures/hadron-app/package.json
@@ -56,12 +56,8 @@
}
},
"scripts": {
- "start": "hadron-build develop",
"prepublish": "hadron-build release",
- "postuninstall": "hadron-build clean",
"test-check-ci": "npm run test",
- "clean": "hadron-build clean",
- "compile-ui": "hadron-build ui",
"release": "hadron-build release",
"upload": "hadron-build upload"
},
diff --git a/packages/hadron-build/test/index.test.js b/packages/hadron-build/test/index.test.js
index 6b560f25e4e..714d24f7928 100644
--- a/packages/hadron-build/test/index.test.js
+++ b/packages/hadron-build/test/index.test.js
@@ -14,39 +14,7 @@ describe('hadron-build', () => {
expect(hadronBuild).to.be.a('function');
});
- describe('::clean', () => {
- it('should include options from commands::ui', () => {
- expect(commands.clean.builder).to.have.property('less_cache');
- });
- });
-
- describe('::develop', () => {
- it('should include options from commands::ui', () => {
- expect(commands.develop.builder).to.have.property('less_cache');
- });
-
- it('should include tasks from commands::ui');
-
- it('should include options from commands::verify', () => {
- expect(commands.develop.builder).to.have.property('nodejs_version');
- expect(commands.develop.builder).to.have.property('npm_version');
- });
-
- it('should include tasks from commands::verify');
-
-
- describe('::handler', () => {
- it('should set `NODE_ENV` to development');
- it('should set `DEVTOOLS` to `1` when --devtools is specified');
- it('should spawn electron-prebuilt');
- });
- });
-
describe('::release', () => {
- it('should include options from commands::ui', () => {
- expect(commands.release.builder).to.have.property('less_cache');
- });
-
it('should include options from commands::verify', () => {
expect(commands.release.builder).to.have.property('nodejs_version');
expect(commands.release.builder).to.have.property('npm_version');
@@ -116,18 +84,6 @@ describe('hadron-build', () => {
it('should spawn electron-mocha');
});
});
- describe('::upload', () => {
-
- });
- describe('::ui', () => {
- it('should include a `less_cache` option', () => {
- expect(commands.ui.builder).to.have.property('less_cache');
- });
-
- it('should default `less_cache` to `src/app/less-cache`');
-
- it('should generate the less cache');
- });
describe('::verify', () => {
it('should have a `nodejs_version` option', () => {
diff --git a/packages/hadron-document/package.json b/packages/hadron-document/package.json
index b84281ae1a7..c11ee148dee 100644
--- a/packages/hadron-document/package.json
+++ b/packages/hadron-document/package.json
@@ -7,7 +7,7 @@
"email": "compass@mongodb.com"
},
"homepage": "https://github.com/mongodb-js/compass",
- "version": "8.5.4",
+ "version": "8.5.5",
"repository": {
"type": "git",
"url": "https://github.com/mongodb-js/compass.git"
@@ -52,7 +52,7 @@
"lodash": "^4.17.21"
},
"devDependencies": {
- "@mongodb-js/eslint-config-compass": "^1.1.2",
+ "@mongodb-js/eslint-config-compass": "^1.1.3",
"@mongodb-js/mocha-config-compass": "^1.3.9",
"@mongodb-js/prettier-config-compass": "^1.0.2",
"@mongodb-js/tsconfig-compass": "^1.0.4",
diff --git a/packages/hadron-document/src/element.ts b/packages/hadron-document/src/element.ts
index bcb79bed419..b3bc37c4fd7 100644
--- a/packages/hadron-document/src/element.ts
+++ b/packages/hadron-document/src/element.ts
@@ -46,6 +46,12 @@ const UNEDITABLE_TYPES = [
'DBRef',
];
+export function isValueExpandable(
+ value: BSONValue
+): value is BSONObject | BSONArray {
+ return isPlainObject(value) || isArray(value);
+}
+
/**
* Represents an element in a document.
*/
@@ -58,6 +64,11 @@ export class Element extends EventEmitter {
added: boolean;
removed: boolean;
elements?: ElementList;
+ // With Arrays and Objects we store the value in the
+ // `elements` instead of currentValue. We use `originalExpandableValue`
+ // to store the original value that was passed in. This is necessary
+ // to be able to revert to the original value when the user cancels
+ // any changes.
originalExpandableValue?: BSONObject | BSONArray;
parent: Element | Document | null;
type: TypeCastTypes;
@@ -116,7 +127,7 @@ export class Element extends EventEmitter {
value = TypeChecker.cast(value, TypeChecker.type(value));
}
- if (this._isExpandable(value)) {
+ if (isValueExpandable(value)) {
// NB: Important to set `originalExpandableValue` first as element
// generation will depend on it
this.originalExpandableValue = value;
@@ -168,10 +179,10 @@ export class Element extends EventEmitter {
*/
edit(value: BSONValue): void {
this.currentType = TypeChecker.type(value);
- if (this._isExpandable(value) && !this._isExpandable(this.currentValue)) {
+ if (isValueExpandable(value) && !isValueExpandable(this.currentValue)) {
this.currentValue = null;
this.elements = this._generateElements(value);
- } else if (!this._isExpandable(value) && this.elements) {
+ } else if (!isValueExpandable(value) && this.elements) {
this.currentValue = value;
this.elements = undefined;
} else {
@@ -455,6 +466,10 @@ export class Element extends EventEmitter {
}
}
+ _isExpandable(): boolean {
+ return this.currentType === 'Array' || this.currentType === 'Object';
+ }
+
/**
* Is the element the last in the elements.
*
@@ -726,7 +741,7 @@ export class Element extends EventEmitter {
* will most expand the element itself.
*/
expand(expandChildren = false): void {
- if (!this._isExpandable(this.originalExpandableValue)) {
+ if (!this._isExpandable()) {
return;
}
@@ -743,7 +758,7 @@ export class Element extends EventEmitter {
* Collapses only the target element
*/
collapse(): void {
- if (!this._isExpandable(this.originalExpandableValue)) {
+ if (!this._isExpandable()) {
return;
}
@@ -801,17 +816,6 @@ export class Element extends EventEmitter {
return !!element && element.isAdded() && element.isBlank();
}
- /**
- * Check if the value is expandable.
- *
- * @param value - The value to check.
- *
- * @returns If the value is expandable.
- */
- _isExpandable(value: BSONValue): value is BSONObject | BSONArray {
- return isPlainObject(value) || isArray(value);
- }
-
/**
* Generates a sequence of child elements.
*
diff --git a/packages/hadron-document/test/element.test.ts b/packages/hadron-document/test/element.test.ts
index 5a08d1f65fe..39dfbc5d29c 100644
--- a/packages/hadron-document/test/element.test.ts
+++ b/packages/hadron-document/test/element.test.ts
@@ -12,7 +12,7 @@ import {
} from 'bson';
import { expect } from 'chai';
import { Document, Element, ElementEvents } from '../src/';
-import { DATE_FORMAT } from '../src/element';
+import { DATE_FORMAT, isValueExpandable } from '../src/element';
import moment from 'moment';
import Sinon from 'sinon';
@@ -2773,10 +2773,37 @@ describe('Element', function () {
expect(element.expanded).to.be.true;
for (const el of element.elements ?? []) {
- if (el._isExpandable(el.originalExpandableValue)) {
+ if (isValueExpandable(el.originalExpandableValue)) {
expect(el.expanded).to.be.true;
}
}
});
});
+
+ context(
+ 'when expanding an element that has been added with a changed type',
+ function () {
+ it('should expand the target element and its children', function () {
+ const element = new Element('names', {
+ firstName: 'A',
+ addresses: [1, 2],
+ });
+ expect(element.expanded).to.be.false;
+
+ element.insertEnd('pineapple', 'to be changed');
+ element.get('pineapple')?.changeType('Object');
+
+ element.insertEnd('pie', new Int32(123));
+ element.get('pie')?.changeType('Array');
+
+ expect(element.get('pineapple')?.expanded).to.be.false;
+ expect(element.get('pie')?.expanded).to.be.false;
+
+ element.expand(true);
+ expect(element.expanded).to.be.true;
+ expect(element.get('pineapple')?.expanded).to.be.true;
+ expect(element.get('pie')?.expanded).to.be.true;
+ });
+ }
+ );
});
diff --git a/packages/hadron-ipc/package.json b/packages/hadron-ipc/package.json
index e3b05ee681c..115112c9f36 100644
--- a/packages/hadron-ipc/package.json
+++ b/packages/hadron-ipc/package.json
@@ -1,7 +1,7 @@
{
"name": "hadron-ipc",
"description": "Simplified IPC for electron apps.",
- "version": "3.2.16",
+ "version": "3.2.18",
"author": {
"name": "MongoDB Inc",
"email": "compass@mongodb.com"
@@ -50,7 +50,7 @@
"reformat": "npm run eslint . -- --fix && npm run prettier -- --write ."
},
"devDependencies": {
- "@mongodb-js/eslint-config-compass": "^1.1.2",
+ "@mongodb-js/eslint-config-compass": "^1.1.3",
"@mongodb-js/mocha-config-compass": "^1.3.9",
"@mongodb-js/prettier-config-compass": "^1.0.2",
"@mongodb-js/tsconfig-compass": "^1.0.4",
@@ -69,7 +69,7 @@
},
"dependencies": {
"debug": "^4.3.4",
- "electron": "^29.4.3",
+ "electron": "^29.4.5",
"is-electron-renderer": "^2.0.1"
}
}
diff --git a/packages/instance-model/package.json b/packages/instance-model/package.json
index ee455f47d21..087fc2546bc 100644
--- a/packages/instance-model/package.json
+++ b/packages/instance-model/package.json
@@ -2,7 +2,7 @@
"name": "mongodb-instance-model",
"description": "MongoDB instance model",
"author": "Lucas Hrabovsky ",
- "version": "12.22.1",
+ "version": "12.23.1",
"bugs": {
"url": "https://jira.mongodb.org/projects/COMPASS/issues",
"email": "compass@mongodb.com"
@@ -29,12 +29,12 @@
},
"dependencies": {
"ampersand-model": "^8.0.1",
- "mongodb-collection-model": "^5.21.1",
- "mongodb-data-service": "^22.21.1",
- "mongodb-database-model": "^2.21.1"
+ "mongodb-collection-model": "^5.22.1",
+ "mongodb-data-service": "^22.22.1",
+ "mongodb-database-model": "^2.22.1"
},
"devDependencies": {
- "@mongodb-js/eslint-config-compass": "^1.1.2",
+ "@mongodb-js/eslint-config-compass": "^1.1.3",
"@mongodb-js/prettier-config-compass": "^1.0.2",
"chai": "^4.3.4",
"depcheck": "^1.4.1",
diff --git a/packages/mongodb-query-util/package.json b/packages/mongodb-query-util/package.json
index 180a070988f..3f6f6aba3b8 100644
--- a/packages/mongodb-query-util/package.json
+++ b/packages/mongodb-query-util/package.json
@@ -13,7 +13,7 @@
"email": "compass@mongodb.com"
},
"homepage": "https://github.com/mongodb-js/compass",
- "version": "2.2.3",
+ "version": "2.2.4",
"repository": {
"type": "git",
"url": "https://github.com/mongodb-js/compass.git"
@@ -50,7 +50,7 @@
"reformat": "npm run eslint . -- --fix && npm run prettier -- --write ."
},
"devDependencies": {
- "@mongodb-js/eslint-config-compass": "^1.1.2",
+ "@mongodb-js/eslint-config-compass": "^1.1.3",
"@mongodb-js/mocha-config-compass": "^1.3.9",
"@mongodb-js/prettier-config-compass": "^1.0.2",
"@mongodb-js/tsconfig-compass": "^1.0.4",
diff --git a/packages/my-queries-storage/package.json b/packages/my-queries-storage/package.json
index ff3f0f686b8..a048e488b32 100644
--- a/packages/my-queries-storage/package.json
+++ b/packages/my-queries-storage/package.json
@@ -13,7 +13,7 @@
"email": "compass@mongodb.com"
},
"homepage": "https://github.com/mongodb-js/compass",
- "version": "0.10.0",
+ "version": "0.13.0",
"repository": {
"type": "git",
"url": "https://github.com/mongodb-js/compass.git"
@@ -55,7 +55,7 @@
"reformat": "npm run eslint . -- --fix && npm run prettier -- --write ."
},
"devDependencies": {
- "@mongodb-js/eslint-config-compass": "^1.1.2",
+ "@mongodb-js/eslint-config-compass": "^1.1.3",
"@mongodb-js/mocha-config-compass": "^1.3.9",
"@mongodb-js/prettier-config-compass": "^1.0.2",
"@mongodb-js/tsconfig-compass": "^1.0.4",
@@ -73,10 +73,10 @@
"typescript": "^5.0.4"
},
"dependencies": {
- "@mongodb-js/compass-editor": "^0.25.0",
- "@mongodb-js/compass-user-data": "^0.2.1",
+ "@mongodb-js/compass-editor": "^0.27.0",
+ "@mongodb-js/compass-user-data": "^0.3.1",
"bson": "^6.7.0",
- "hadron-app-registry": "^9.1.12",
+ "hadron-app-registry": "^9.2.1",
"react": "^17.0.2"
}
}
diff --git a/packages/reflux-state-mixin/package.json b/packages/reflux-state-mixin/package.json
index 344fc2537a4..09ee7de2b95 100644
--- a/packages/reflux-state-mixin/package.json
+++ b/packages/reflux-state-mixin/package.json
@@ -13,7 +13,7 @@
"email": "compass@mongodb.com"
},
"homepage": "https://github.com/mongodb-js/compass",
- "version": "1.0.2",
+ "version": "1.0.3",
"repository": {
"type": "git",
"url": "https://github.com/mongodb-js/compass.git"
@@ -53,7 +53,7 @@
"reflux": "^0.4.1"
},
"devDependencies": {
- "@mongodb-js/eslint-config-compass": "^1.1.2",
+ "@mongodb-js/eslint-config-compass": "^1.1.3",
"@mongodb-js/mocha-config-compass": "^1.3.9",
"@mongodb-js/prettier-config-compass": "^1.0.2",
"@mongodb-js/tsconfig-compass": "^1.0.4",
diff --git a/packages/ssh-tunnel/package.json b/packages/ssh-tunnel/package.json
index 8b0bdb587d5..0cea0eb5896 100644
--- a/packages/ssh-tunnel/package.json
+++ b/packages/ssh-tunnel/package.json
@@ -13,7 +13,7 @@
"email": "compass@mongodb.com"
},
"homepage": "https://github.com/mongodb-js/compass",
- "version": "2.2.1",
+ "version": "2.3.1",
"repository": {
"type": "git",
"url": "https://github.com/mongodb-js/compass.git"
@@ -49,7 +49,7 @@
"reformat": "npm run eslint . -- --fix && npm run prettier -- --write ."
},
"devDependencies": {
- "@mongodb-js/eslint-config-compass": "^1.1.2",
+ "@mongodb-js/eslint-config-compass": "^1.1.3",
"@mongodb-js/mocha-config-compass": "^1.3.9",
"@mongodb-js/prettier-config-compass": "^1.0.2",
"@mongodb-js/tsconfig-compass": "^1.0.4",
@@ -73,7 +73,7 @@
"typescript": "^5.0.4"
},
"dependencies": {
- "@mongodb-js/compass-logging": "^1.3.1",
+ "@mongodb-js/compass-logging": "^1.4.1",
"socksv5": "0.0.6",
"ssh2": "^1.12.0"
}
diff --git a/scripts/package.json b/scripts/package.json
index 3b54af1f698..99a6f42d658 100644
--- a/scripts/package.json
+++ b/scripts/package.json
@@ -14,7 +14,7 @@
"email": "compass@mongodb.com"
},
"homepage": "https://github.com/mongodb-js/compass",
- "version": "0.16.13",
+ "version": "0.16.15",
"repository": {
"type": "git",
"url": "https://github.com/mongodb-js/compass.git"
@@ -30,7 +30,7 @@
"reformat": "npm run eslint . -- --fix && npm run prettier -- --write ."
},
"devDependencies": {
- "@mongodb-js/eslint-config-compass": "^1.1.2",
+ "@mongodb-js/eslint-config-compass": "^1.1.3",
"@mongodb-js/prettier-config-compass": "^1.0.2",
"depcheck": "^1.4.1",
"eslint": "^7.25.0",
@@ -40,7 +40,7 @@
"@babel/core": "^7.24.3",
"@mongodb-js/monorepo-tools": "^1.1.1",
"commander": "^11.0.0",
- "electron": "^29.4.3",
+ "electron": "^29.4.5",
"jsdom": "^21.1.0",
"make-fetch-happen": "^8.0.14",
"pacote": "^11.3.5",