Skip to content

Commit

Permalink
chore(atlas-service): convert to plugin (#5512)
Browse files Browse the repository at this point in the history
* Revert "breadcrumbs ui"

This reverts commit 8b0b3d9.

* setup provider

* convert atlas-sign-in to a plugin

* rename

* bootstrap

* logger component

* clean up

* use refs

* bootstrap
  • Loading branch information
mabaasit committed Feb 29, 2024
1 parent f5f5104 commit 2cb2be7
Show file tree
Hide file tree
Showing 15 changed files with 320 additions and 302 deletions.
3 changes: 1 addition & 2 deletions configs/eslint-config-compass/plugin.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,7 @@ module.exports = {
restrictedProviderImport('@mongodb-js/compass-logging'),
restrictedProviderImport('@mongodb-js/compass-app-stores'),
restrictedProviderImport('@mongodb-js/my-queries-storage'),
// TODO(COMPASS-7412): enable when possible
// restrictedProviderImport('@mongodb-js/atlas-service'),
restrictedProviderImport('@mongodb-js/atlas-service'),
restrictedProviderImport('compass-preferences-model'),
{
paths: require('module').builtinModules,
Expand Down
2 changes: 2 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion packages/atlas-service/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
"compass:exports": {
"./main": "./src/main.ts",
"./renderer": "./src/renderer.ts",
"./provider": "./src/provider.ts"
"./provider": "./src/provider.tsx"
},
"scripts": {
"bootstrap": "npm run compile",
Expand Down Expand Up @@ -79,6 +79,7 @@
"@mongodb-js/compass-utils": "^0.6.0",
"@mongodb-js/devtools-connect": "^2.4.2",
"@mongodb-js/oidc-plugin": "^0.3.1",
"hadron-app-registry": "^9.1.6",
"compass-preferences-model": "^2.18.0",
"electron": "^28.2.5",
"hadron-ipc": "^3.2.11",
Expand Down
78 changes: 0 additions & 78 deletions packages/atlas-service/src/components/atlas-signin.spec.tsx

This file was deleted.

32 changes: 0 additions & 32 deletions packages/atlas-service/src/components/atlas-signin.tsx

This file was deleted.

11 changes: 11 additions & 0 deletions packages/atlas-service/src/components/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import React from 'react';
import AISignInModal from './ai-signin-modal';
import { ConfirmationModalArea } from '@mongodb-js/compass-components';

export const AtlasSignIn = () => {
return (
<ConfirmationModalArea>
<AISignInModal></AISignInModal>
</ConfirmationModalArea>
);
};
17 changes: 0 additions & 17 deletions packages/atlas-service/src/provider.ts

This file was deleted.

46 changes: 46 additions & 0 deletions packages/atlas-service/src/provider.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import React, { createContext, useContext, useMemo } from 'react';
import type { AtlasAuthService } from './atlas-auth-service';
import { AtlasService, type AtlasServiceOptions } from './atlas-service';
import { preferencesLocator } from 'compass-preferences-model/provider';
import { useLoggerAndTelemetry } from '@mongodb-js/compass-logging/provider';

const AtlasAuthServiceContext = createContext<AtlasAuthService | null>(null);
export const AtlasAuthServiceProvider = AtlasAuthServiceContext.Provider;
function useAtlasAuthServiceLocator(): AtlasAuthService {
const service = useContext(AtlasAuthServiceContext);
if (!service) {
throw new Error('No AtlasAuthService available in this context');
}
return service;
}
export const atlasAuthServiceLocator = useAtlasAuthServiceLocator;

const AtlasServiceContext = createContext<AtlasService | null>(null);
export const AtlasServiceProvider: React.FC<{
options?: AtlasServiceOptions;
}> = ({ options, children }) => {
const logger = useLoggerAndTelemetry('ATLAS-SERVICE');
const preferences = preferencesLocator();
const authService = atlasAuthServiceLocator();

const atlasService = useMemo(() => {
return new AtlasService(authService, preferences, logger, options);
}, [authService, preferences, logger, options]);

return (
<AtlasServiceContext.Provider value={atlasService}>
{children}
</AtlasServiceContext.Provider>
);
};
function useAtlasServiceLocator(): AtlasService {
const service = useContext(AtlasServiceContext);
if (!service) {
throw new Error('No AtlasService available in this context');
}
return service;
}
export const atlasServiceLocator = useAtlasServiceLocator;

export { AtlasAuthService } from './atlas-auth-service';
export type { AtlasService } from './atlas-service';
16 changes: 15 additions & 1 deletion packages/atlas-service/src/renderer.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,19 @@
export { AtlasSignIn } from './components/atlas-signin';
import { registerHadronPlugin } from 'hadron-app-registry';
import { activatePlugin } from './store/atlas-signin-store';
import { atlasAuthServiceLocator } from './provider';
import { AtlasSignIn } from './components';

export const AtlasAuthPlugin = registerHadronPlugin(
{
name: 'AtlasAuth',
component: AtlasSignIn,
activate: activatePlugin,
},
{
atlasAuthService: atlasAuthServiceLocator,
}
);
export default AtlasAuthPlugin;
export { AtlasServiceError } from './util';
export type { AtlasUserConfig } from './user-config-store';
export type { AtlasUserInfo } from './util';
Expand Down
43 changes: 43 additions & 0 deletions packages/atlas-service/src/store/atlas-signin-store.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { expect } from 'chai';
import type { AtlasAuthPluginServices } from './atlas-signin-store';
import { activatePlugin } from './atlas-signin-store';
import type { ActivateHelpers } from 'hadron-app-registry';
import { waitFor } from '@testing-library/react';

const activateHelpers = {
on: () => {},
addCleanup: () => {},
cleanup: () => {},
} as unknown as ActivateHelpers;

describe('Atlas Signin Store', () => {
context('when plugin is activated', function () {
it('should restore the sign-in state - when signed in', async function () {
const services = {
atlasAuthService: {
isAuthenticated: () => Promise.resolve(true),
getUserInfo: () => Promise.resolve({ sub: '1234' }),
},
} as unknown as AtlasAuthPluginServices;
const { store } = activatePlugin({}, services, activateHelpers);
expect(store.getState()).to.have.property('state', 'restoring');
await waitFor(() => {
expect(store.getState()).to.have.property('state', 'success');
});
expect(store.getState()).to.have.nested.property('userInfo.sub', '1234');
});
it('should restore the sign-in state - when signed out', async function () {
const services = {
atlasAuthService: {
isAuthenticated: () => Promise.resolve(false),
},
} as unknown as AtlasAuthPluginServices;
const { store } = activatePlugin({}, services, activateHelpers);
expect(store.getState()).to.have.property('state', 'restoring');
await waitFor(() => {
expect(store.getState()).to.have.property('state', 'unauthenticated');
});
expect(store.getState()).to.have.property('userInfo', null);
});
});
});
80 changes: 48 additions & 32 deletions packages/atlas-service/src/store/atlas-signin-store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,51 +2,67 @@ import { createStore, applyMiddleware } from 'redux';
import thunk from 'redux-thunk';
import type { AtlasUserConfig } from '../renderer';
import reducer, {
restoreSignInState,
signedOut,
tokenRefreshFailed,
userConfigChanged,
} from './atlas-signin-reducer';
import { atlasAuthServiceLocator, type AtlasAuthService } from '../provider';
import { type AtlasAuthService } from '../provider';
import { ipcRenderer } from 'hadron-ipc';
import type { ActivateHelpers } from 'hadron-app-registry';

export function configureStore({
atlasAuthService,
}: {
let store: AtlasServiceStore;
export function getStore() {
if (!store) {
throw new Error('AtlasAuthPlugin not activated');
}
return store;
}

export type AtlasAuthPluginServices = {
atlasAuthService: AtlasAuthService;
}) {
const store = createStore(
reducer,
applyMiddleware(thunk.withExtraArgument({ atlasAuthService }))
);
};
export function activatePlugin(
_: Record<string, never>,
services: AtlasAuthPluginServices,
{ on, addCleanup, cleanup }: ActivateHelpers
) {
store = configureStore(services);

const onSignedOut = () => store.dispatch(signedOut);
const onTokenRefreshFailed = () => store.dispatch(tokenRefreshFailed);
const onUserConfigChanged = (_evt: unknown, newConfig: AtlasUserConfig) =>
store.dispatch(userConfigChanged(newConfig));

// We might not be in electorn environment
if (ipcRenderer) {
ipcRenderer.on('atlas-service-token-refresh-failed', () => {
getStore().dispatch(tokenRefreshFailed());
});

ipcRenderer.on('atlas-service-signed-out', () => {
getStore().dispatch(signedOut());
});

ipcRenderer.on(
'atlas-service-user-config-changed',
(_evt, newConfig: AtlasUserConfig) => {
getStore().dispatch(userConfigChanged(newConfig));
}
);
on(ipcRenderer, 'atlas-service-token-refresh-failed', onSignedOut);
on(ipcRenderer, 'atlas-service-signed-out', onTokenRefreshFailed);
on(ipcRenderer, 'atlas-service-user-config-changed', onUserConfigChanged);
}

return store;
}
addCleanup(() => {
if (ipcRenderer) {
ipcRenderer.off(
'atlas-service-token-refresh-failed',
onTokenRefreshFailed
);
ipcRenderer.off('atlas-service-signed-out', onSignedOut);
ipcRenderer.off('atlas-service-user-config-changed', onUserConfigChanged);
}
});

export type AtlasServiceStore = ReturnType<typeof configureStore>;
// Restore the sign-in state when plugin is activated
void store.dispatch(restoreSignInState());

let store: AtlasServiceStore;
return { store, deactivate: cleanup };
}

export function getStore() {
store ??= configureStore({
atlasAuthService: atlasAuthServiceLocator(),
});
export function configureStore({ atlasAuthService }: AtlasAuthPluginServices) {
const store = createStore(
reducer,
applyMiddleware(thunk.withExtraArgument({ atlasAuthService }))
);
return store;
}

export type AtlasServiceStore = ReturnType<typeof configureStore>;
Loading

0 comments on commit 2cb2be7

Please sign in to comment.