diff --git a/packages/collection-model/lib/model.js b/packages/collection-model/lib/model.js index bb3bc56ed49..c1e76e6b83c 100644 --- a/packages/collection-model/lib/model.js +++ b/packages/collection-model/lib/model.js @@ -417,18 +417,13 @@ const CollectionCollection = AmpersandCollection.extend( } ); + const showHiddenNamespaces = instanceModel.shouldShowHiddenNamespaces(); + this.set( collections - .filter((coll) => { - // TODO: This is not the best place to do this kind of - // filtering, but for now this preserves the current behavior - // and changing it right away will expand the scope of the - // refactor significantly. We can address this in COMPASS-5211 - return ( - getNamespaceInfo(coll._id).system === false || - getNamespaceInfo(coll._id).collection === 'system.profile' - ); - }) + .filter( + (coll) => showHiddenNamespaces || !getNamespaceInfo(coll._id).system + ) .map(({ _id, ...rest }) => { return { _id, diff --git a/packages/collection-model/test/index.test.js b/packages/collection-model/test/index.test.js index 240e66b53aa..f75e76c5042 100644 --- a/packages/collection-model/test/index.test.js +++ b/packages/collection-model/test/index.test.js @@ -12,7 +12,7 @@ describe('mongodb-collection-model', function () { }); describe('CollectionCollection#fetch', function () { - function createFakeDatabase() { + function createFakeDatabase({ showHiddenNamespaces }) { var instance = { modelType: 'Instance', shouldFetchNamespacesFromPrivileges() { @@ -21,6 +21,9 @@ describe('mongodb-collection-model', function () { shouldFetchDbAndCollStats() { return false; }, + shouldShowHiddenNamespaces() { + return showHiddenNamespaces; + }, auth: { privileges: null, roles: null }, emit: function () {}, }; @@ -34,12 +37,8 @@ describe('mongodb-collection-model', function () { }; } - it('hides system collections but keeps system.profile', async function () { - var collections = new CollectionCollection([], { - parent: createFakeDatabase(), - }); - - var dataService = { + function createDataService() { + return { listCollections: async function () { return [ { _id: 'test.foo' }, @@ -49,8 +48,14 @@ describe('mongodb-collection-model', function () { ]; }, }; + } - await collections.fetch({ dataService: dataService }); + it('hides system collections by default, but keeps system.profile', async function () { + var collections = new CollectionCollection([], { + parent: createFakeDatabase({ showHiddenNamespaces: false }), + }); + + await collections.fetch({ dataService: createDataService() }); assert.deepStrictEqual( collections.map(function (coll) { @@ -59,5 +64,20 @@ describe('mongodb-collection-model', function () { ['test.bar', 'test.foo', 'test.system.profile'] ); }); + + it('keeps system collections when showHiddenNamespaces is enabled', async function () { + var collections = new CollectionCollection([], { + parent: createFakeDatabase({ showHiddenNamespaces: true }), + }); + + await collections.fetch({ dataService: createDataService() }); + + assert.deepStrictEqual( + collections.map(function (coll) { + return coll._id; + }), + ['test.bar', 'test.foo', 'test.system.profile', 'test.system.views'] + ); + }); }); }); diff --git a/packages/compass-app-stores/src/stores/instance-store.ts b/packages/compass-app-stores/src/stores/instance-store.ts index 7cc6913fd6a..be8b9e66922 100644 --- a/packages/compass-app-stores/src/stores/instance-store.ts +++ b/packages/compass-app-stores/src/stores/instance-store.ts @@ -286,14 +286,13 @@ export function createInstancesStore( } ); - preferences.onPreferenceValueChanged('inferNamespacesFromPrivileges', () => { - const connectedConnectionIds = Array.from( - instancesManager.listMongoDBInstances().keys() - ); - for (const connectionId of connectedConnectionIds) { + function reload() { + for (const [connectionId] of instancesManager.listMongoDBInstances()) void refreshDatabases({ connectionId }); - } - }); + } + + preferences.onPreferenceValueChanged('inferNamespacesFromPrivileges', reload); + preferences.onPreferenceValueChanged('showHiddenNamespaces', reload); on(connections, 'disconnected', function (connectionInfoId: string) { try { diff --git a/packages/compass-preferences-model/src/preferences-schema.tsx b/packages/compass-preferences-model/src/preferences-schema.tsx index 7cb04084746..6ed85b8886c 100644 --- a/packages/compass-preferences-model/src/preferences-schema.tsx +++ b/packages/compass-preferences-model/src/preferences-schema.tsx @@ -108,6 +108,7 @@ export type UserConfigurablePreferences = PermanentFeatureFlags & enableCreatingNewConnections: boolean; proxy: string; inferNamespacesFromPrivileges?: boolean; + showHiddenNamespaces: boolean; // Features that are enabled by default in Date Explorer, but are disabled in Compass maxTimeMSEnvLimit?: number; }; @@ -1130,6 +1131,17 @@ export const storedUserPreferencesProps: Required<{ validator: z.boolean().default(true), type: 'boolean', }, + showHiddenNamespaces: { + ui: true, + cli: true, + global: true, + description: { + short: 'Show Hidden Namespaces', + long: 'Show internal (__mdb_internal_) databases and system collections in the sidebar.', + }, + validator: z.boolean().default(false), + type: 'boolean', + }, maxTimeMSEnvLimit: { ui: true, cli: true, diff --git a/packages/compass-settings/src/components/settings/general.tsx b/packages/compass-settings/src/components/settings/general.tsx index c09595e308a..58f18a3c041 100644 --- a/packages/compass-settings/src/components/settings/general.tsx +++ b/packages/compass-settings/src/components/settings/general.tsx @@ -15,6 +15,7 @@ const generalFields = [ 'enableShowDialogOnQuit', 'enableDbAndCollStats', 'inferNamespacesFromPrivileges', + 'showHiddenNamespaces', 'legacyUUIDDisplayEncoding', ] as const; diff --git a/packages/database-model/lib/model.js b/packages/database-model/lib/model.js index e44f8a4963a..7deea757d9f 100644 --- a/packages/database-model/lib/model.js +++ b/packages/database-model/lib/model.js @@ -262,15 +262,11 @@ const DatabaseCollection = AmpersandCollection.extend( roles: instanceModel.auth.roles, }); + const showHiddenNamespaces = instanceModel.shouldShowHiddenNamespaces(); + this.set( dbs - .filter((db) => { - const ns = toNS(db._id); - // TODO(COMPASS-10954): This is indisputably the wrong way and place to handle namespace filtering. - // There is a namespace that now _must_ be revealed again to users so they can repair it in unfortunate circumstances. - // We will instead reveal all internal namespaces under a setting removing this filter altogether in COMPASS-10954. - return !ns.internal || ns.database === '__mdb_internal_search'; - }) + .filter((db) => showHiddenNamespaces || !toNS(db._id).internal) .map(({ _id, name, inferred_from_privileges }) => ({ _id, name, diff --git a/packages/database-model/test/index.test.js b/packages/database-model/test/index.test.js index 344b28e4350..501046e147b 100644 --- a/packages/database-model/test/index.test.js +++ b/packages/database-model/test/index.test.js @@ -8,39 +8,65 @@ describe('mongodb-database-model', function () { }); describe('DatabaseCollection#fetch', function () { - function createFakeInstance() { + function createFakeInstance({ showHiddenNamespaces }) { return { modelType: 'Instance', shouldFetchNamespacesFromPrivileges() { return false; }, + shouldShowHiddenNamespaces() { + return showHiddenNamespaces; + }, auth: { privileges: null, roles: null }, emit: function () {}, }; } - it('filters out internal (__mdb_internal_) databases from the list except search', async function () { - var databases = new Database.Collection([], { - parent: createFakeInstance(), - }); - - var dataService = { + function createDataService() { + return { listDatabases: async function () { return [ { _id: 'admin' }, { _id: 'test' }, - { _id: '__mdb_internal_atlas' }, - { _id: '__mdb_internal_search' }, + { _id: 'config' }, { _id: 'local' }, + { _id: '__mdb_internal_search' }, + { _id: '__mdb_internal_atlas' }, ]; }, }; + } + + it('hides internal (__mdb_internal_) databases by default', async function () { + var databases = new Database.Collection([], { + parent: createFakeInstance({ showHiddenNamespaces: false }), + }); + + await databases.fetch({ dataService: createDataService() }); + + assert.deepStrictEqual( + databases.map(({ _id }) => _id), + ['admin', 'config', 'local', 'test'] + ); + }); + + it('keeps internal (__mdb_internal_) databases when showHiddenNamespaces is enabled', async function () { + var databases = new Database.Collection([], { + parent: createFakeInstance({ showHiddenNamespaces: true }), + }); - await databases.fetch({ dataService: dataService }); + await databases.fetch({ dataService: createDataService() }); assert.deepStrictEqual( databases.map(({ _id }) => _id), - ['__mdb_internal_search', 'admin', 'local', 'test'] + [ + '__mdb_internal_atlas', + '__mdb_internal_search', + 'admin', + 'config', + 'local', + 'test', + ] ); }); }); diff --git a/packages/instance-model/lib/model.js b/packages/instance-model/lib/model.js index 0d2238ebcf6..79fdd5dc45f 100644 --- a/packages/instance-model/lib/model.js +++ b/packages/instance-model/lib/model.js @@ -404,6 +404,10 @@ const InstanceModel = AmpersandModel.extend( return this.preferences.getPreferences().inferNamespacesFromPrivileges; }, + shouldShowHiddenNamespaces() { + return this.preferences.getPreferences().showHiddenNamespaces; + }, + removeAllListeners() { InstanceModel.removeAllListeners(this); },