From a7496ffd273425ddeb1fdbf6336cb73e743ccc1c Mon Sep 17 00:00:00 2001 From: Le Roux Bodenstein Date: Tue, 3 Sep 2024 13:31:20 +0100 Subject: [PATCH] feat(compass-connections): useConnectionSupports(connectionId, connectionFeature) hook COMPASS-8213 (#6185) * useConnectionSupports hook * tests * use a selector --- .../src/hooks/use-connection-supports.spec.ts | 161 ++++++++++++++++++ .../src/hooks/use-connection-supports.ts | 45 +++++ .../src/stores/store-context.tsx | 2 +- 3 files changed, 207 insertions(+), 1 deletion(-) create mode 100644 packages/compass-connections/src/hooks/use-connection-supports.spec.ts create mode 100644 packages/compass-connections/src/hooks/use-connection-supports.ts diff --git a/packages/compass-connections/src/hooks/use-connection-supports.spec.ts b/packages/compass-connections/src/hooks/use-connection-supports.spec.ts new file mode 100644 index 00000000000..37e25288135 --- /dev/null +++ b/packages/compass-connections/src/hooks/use-connection-supports.spec.ts @@ -0,0 +1,161 @@ +import { useConnectionSupports } from './use-connection-supports'; +import { type ConnectionInfo } from '@mongodb-js/connection-storage/provider'; +import { expect } from 'chai'; +import { renderHookWithConnections } from '../test'; + +const mockConnections: ConnectionInfo[] = [ + { + id: 'no-atlasMetadata', + connectionOptions: { + connectionString: 'mongodb://foo', + }, + }, + { + id: 'host-cluster', + connectionOptions: { + connectionString: 'mongodb://foo', + }, + atlasMetadata: { + orgId: 'orgId', + projectId: 'projectId', + clusterName: 'clusterName', + regionalBaseUrl: 'https://example.com', + clusterId: 'clusterId', + clusterType: 'host', + instanceSize: 'M10', + }, + }, + { + id: 'free-cluster', + connectionOptions: { + connectionString: 'mongodb://foo', + }, + atlasMetadata: { + orgId: 'orgId', + projectId: 'projectId', + clusterName: 'clusterName', + regionalBaseUrl: 'https://example.com', + clusterId: 'clusterId', + clusterType: 'replicaSet', + instanceSize: 'M0', + }, + }, + { + id: 'serverless-cluster', + connectionOptions: { + connectionString: 'mongodb://foo', + }, + atlasMetadata: { + orgId: 'orgId', + projectId: 'projectId', + clusterName: 'clusterName', + regionalBaseUrl: 'https://example.com', + clusterId: 'clusterId', + clusterType: 'serverless', + instanceSize: 'SERVERLESS_V2', + }, + }, + { + id: 'dedicated-replicaSet', + connectionOptions: { + connectionString: 'mongodb://foo', + }, + atlasMetadata: { + orgId: 'orgId', + projectId: 'projectId', + clusterName: 'clusterName', + regionalBaseUrl: 'https://example.com', + clusterId: 'clusterId', + clusterType: 'replicaSet', + instanceSize: 'M10', + }, + }, + { + id: 'dedicated-sharded', + connectionOptions: { + connectionString: 'mongodb://foo', + }, + atlasMetadata: { + orgId: 'orgId', + projectId: 'projectId', + clusterName: 'clusterName', + regionalBaseUrl: 'https://example.com', + clusterId: 'clusterId', + clusterType: 'cluster', + instanceSize: 'M10', + }, + }, +]; + +describe('useConnectionSupports', function () { + it('should return false if the connection does not exist', function () { + const { result } = renderHookWithConnections( + () => useConnectionSupports('does-not-exist', 'rollingIndexCreation'), + { + connections: mockConnections, + } + ); + expect(result.current).to.equal(false); + }); + + it('should return false if the connection has no atlasMetadata', function () { + const { result } = renderHookWithConnections( + () => useConnectionSupports('no-atlasMetadata', 'rollingIndexCreation'), + { + connections: mockConnections, + } + ); + expect(result.current).to.equal(false); + }); + + it('should return false for host cluster type', function () { + const { result } = renderHookWithConnections( + () => useConnectionSupports('host-cluster', 'rollingIndexCreation'), + { + connections: mockConnections, + } + ); + expect(result.current).to.equal(false); + }); + + it('should return false for serverless cluster type', function () { + const { result } = renderHookWithConnections( + () => useConnectionSupports('serverless-cluster', 'rollingIndexCreation'), + { + connections: mockConnections, + } + ); + expect(result.current).to.equal(false); + }); + + it('should return false for free/shared tier clusters', function () { + const { result } = renderHookWithConnections( + () => useConnectionSupports('free-cluster', 'rollingIndexCreation'), + { + connections: mockConnections, + } + ); + expect(result.current).to.equal(false); + }); + + it('should return true for dedicated replicaSet clusters', function () { + const { result } = renderHookWithConnections( + () => + useConnectionSupports('dedicated-replicaSet', 'rollingIndexCreation'), + { + connections: mockConnections, + } + ); + expect(result.current).to.equal(true); + }); + + it('should return true for dedicated sharded clusters', function () { + const { result } = renderHookWithConnections( + () => useConnectionSupports('dedicated-sharded', 'rollingIndexCreation'), + { + connections: mockConnections, + } + ); + expect(result.current).to.equal(true); + }); +}); diff --git a/packages/compass-connections/src/hooks/use-connection-supports.ts b/packages/compass-connections/src/hooks/use-connection-supports.ts new file mode 100644 index 00000000000..83fa92a2f5a --- /dev/null +++ b/packages/compass-connections/src/hooks/use-connection-supports.ts @@ -0,0 +1,45 @@ +import { useSelector } from '../stores/store-context'; +import type { ConnectionState } from '../stores/connections-store-redux'; + +// only one for now +type ConnectionFeature = 'rollingIndexCreation'; + +function isFreeOrSharedTierCluster(instanceSize: string | undefined): boolean { + if (!instanceSize) { + return false; + } + + return ['M0', 'M2', 'M5'].includes(instanceSize); +} + +function supportsRollingIndexCreation(connection: ConnectionState) { + const atlasMetadata = connection.info?.atlasMetadata; + + if (!atlasMetadata) { + return false; + } + + const { clusterType, instanceSize } = atlasMetadata; + return ( + !isFreeOrSharedTierCluster(instanceSize) && + (clusterType === 'cluster' || clusterType === 'replicaSet') + ); +} +export function useConnectionSupports( + connectionId: string, + connectionFeature: ConnectionFeature +): boolean { + return useSelector((state) => { + const connection = state.connections.byId[connectionId]; + + if (!connection) { + return false; + } + + if (connectionFeature === 'rollingIndexCreation') { + return supportsRollingIndexCreation(connection); + } + + return false; + }); +} diff --git a/packages/compass-connections/src/stores/store-context.tsx b/packages/compass-connections/src/stores/store-context.tsx index adce1a0a941..39c6cc778dd 100644 --- a/packages/compass-connections/src/stores/store-context.tsx +++ b/packages/compass-connections/src/stores/store-context.tsx @@ -69,7 +69,7 @@ export const useDispatch = createDispatchHook( /** * @internal should not be directly exported from this package */ -const useSelector: TypedUseSelectorHook = +export const useSelector: TypedUseSelectorHook = createSelectorHook(ConnectionsStoreContext); export const connect = ((