Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore(generative-ai): move ai sign in modal to gen ai package from atlas-service COMPASS-8459 #6448

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 9 additions & 3 deletions package-lock.json

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

1 change: 0 additions & 1 deletion packages/atlas-service/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,6 @@
"hadron-ipc": "^3.2.25",
"lodash": "^4.17.21",
"react": "^17.0.2",
"react-redux": "^8.1.3",
"redux": "^4.2.1",
"redux-thunk": "^2.4.2"
}
Expand Down
2 changes: 1 addition & 1 deletion packages/atlas-service/src/atlas-auth-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import type { AtlasUserInfo } from './util';
export type ArgsWithSignal<T = Record<string, unknown>> = T & {
signal?: AbortSignal;
};
export type SignInPrompt = 'none' | 'ai-promo-modal';
export type SignInPrompt = 'none';
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We probably should consider how we can remote this type altogether now, I know that it's right now here so that the reducer can trigger the ipc without recursively calling itself, but this is probably more of a a flaw than a feature now that we don't have the second option

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good callout, it could use an intentional function for each I feel. It's a bit overloaded without benefit at the moment. I'll see what we can do here.


type AtlasAuthServiceEvents = {
'signed-in': [];
Expand Down
7 changes: 1 addition & 6 deletions packages/atlas-service/src/compass-atlas-auth-service.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
import { ipcRenderer } from 'hadron-ipc';
import type { CompassAuthService as AtlasServiceMain } from './main';
import {
signInWithModalPrompt,
signInWithoutPrompt,
} from './store/atlas-signin-reducer';
import { signInWithoutPrompt } from './store/atlas-signin-reducer';
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Similar to above, this naming should probably be adjusted, no point in calling out that there is no prompt if there is no other option in this service

import { getStore } from './store/atlas-signin-store';
import { AtlasAuthService } from './atlas-auth-service';
import type { ArgsWithSignal, SignInPrompt } from './atlas-auth-service';
Expand Down Expand Up @@ -46,8 +43,6 @@ export class CompassAtlasAuthService extends AtlasAuthService {
switch (promptType) {
case 'none':
return getStore().dispatch(signInWithoutPrompt({ signal }));
case 'ai-promo-modal':
return getStore().dispatch(signInWithModalPrompt({ signal }));
default:
return this.ipc.signIn({ signal });
}
Expand Down
3 changes: 1 addition & 2 deletions packages/atlas-service/src/renderer.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
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,
component: () => null,
activate: activatePlugin,
},
{
Expand Down
99 changes: 1 addition & 98 deletions packages/atlas-service/src/store/atlas-signin-reducer.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@ import {
cancelSignIn,
attemptId,
AttemptStateMap,
signInWithModalPrompt,
closeSignInModal,
signInWithoutPrompt,
} from './atlas-signin-reducer';
import { expect } from 'chai';
Expand Down Expand Up @@ -176,7 +174,7 @@ describe('atlasSignInReducer', function () {
atlasAuthService: mockAtlasService as any,
});

void store.dispatch(signInWithModalPrompt()).catch(() => {});
void store.dispatch(signInWithoutPrompt()).catch(() => {});

await Promise.all([
store.dispatch(signIn()),
Expand All @@ -186,101 +184,6 @@ describe('atlasSignInReducer', function () {
});
});

describe('signInWithModalPrompt', function () {
it('should resolve when user finishes sign in with prompt flow', async function () {
const mockAtlasService = {
isAuthenticated: sandbox.stub().resolves(false),
signIn: sandbox.stub().resolves({ sub: '1234' }),
getUserInfo: sandbox.stub().resolves({ sub: '1234' }),
emit: sandbox.stub(),
};
const store = configureStore({
atlasAuthService: mockAtlasService as any,
});

const signInPromise = store.dispatch(signInWithModalPrompt());
await store.dispatch(signIn());
await signInPromise;

expect(store.getState()).to.have.property('state', 'success');
});

it('should reject if sign in flow fails', async function () {
const mockAtlasService = {
isAuthenticated: sandbox.stub().resolves(false),
signIn: sandbox.stub().rejects(new Error('Whoops!')),
getUserInfo: sandbox.stub().resolves({ sub: '1234' }),
emit: sandbox.stub(),
};
const store = configureStore({
atlasAuthService: mockAtlasService as any,
});

const signInPromise = store.dispatch(signInWithModalPrompt());
await store.dispatch(signIn());

try {
await signInPromise;
throw new Error('Expected signInPromise to throw');
} catch (err) {
expect(err).to.have.property('message', 'Whoops!');
}

expect(store.getState()).to.have.property('state', 'error');
});

it('should reject if user dismissed the modal', async function () {
const mockAtlasService = {
isAuthenticated: sandbox.stub().resolves(false),
signIn: sandbox.stub().resolves({ sub: '1234' }),
getUserInfo: sandbox.stub().resolves({ sub: '1234' }),
emit: sandbox.stub(),
};
const store = configureStore({
atlasAuthService: mockAtlasService as any,
});

const signInPromise = store.dispatch(signInWithModalPrompt());
store.dispatch(closeSignInModal());

try {
await signInPromise;
throw new Error('Expected signInPromise to throw');
} catch (err) {
expect(err).to.have.property('message', 'This operation was aborted');
}

expect(store.getState()).to.have.property('state', 'canceled');
});

it('should reject if provided signal was aborted', async function () {
const mockAtlasService = {
isAuthenticated: sandbox.stub().resolves(false),
signIn: sandbox.stub().resolves({ sub: '1234' }),
getUserInfo: sandbox.stub().resolves({ sub: '1234' }),
emit: sandbox.stub(),
};
const store = configureStore({
atlasAuthService: mockAtlasService as any,
});

const c = new AbortController();
const signInPromise = store.dispatch(
signInWithModalPrompt({ signal: c.signal })
);
c.abort(new Error('Aborted from outside'));

try {
await signInPromise;
throw new Error('Expected signInPromise to throw');
} catch (err) {
expect(err).to.have.property('message', 'Aborted from outside');
}

expect(store.getState()).to.have.property('state', 'canceled');
});
});

describe('signInWithoutPrompt', function () {
it('should resolve when sign in flow finishes', async function () {
const mockAtlasService = {
Expand Down
67 changes: 1 addition & 66 deletions packages/atlas-service/src/store/atlas-signin-reducer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ export function isAction<A extends AnyAction>(

export type AtlasSignInState = {
error: string | null;
isModalOpen: boolean;
// For managing attempt state that doesn't belong in the store
currentAttemptId: number | null;
} & (
Expand All @@ -37,8 +36,6 @@ export type AtlasSignInThunkAction<
> = ThunkAction<R, AtlasSignInState, { atlasAuthService: AtlasAuthService }, A>;

export const enum AtlasSignInActions {
OpenSignInModal = 'atlas-service/atlas-signin/OpenSignInModal',
CloseSignInModal = 'atlas-service/atlas-signin/CloseSignInModal',
RestoringStart = 'atlas-service/atlas-signin/StartRestoring',
RestoringFailed = 'atlas-service/atlas-signin/RestoringFailed',
RestoringSuccess = 'atlas-service/atlas-signin/RestoringSuccess',
Expand All @@ -52,14 +49,6 @@ export const enum AtlasSignInActions {
SignedOut = 'atlas-service/atlas-signin/SignedOut',
}

export type AtlasSignInOpenModalAction = {
type: AtlasSignInActions.OpenSignInModal;
};

export type AtlasSignInCloseModalAction = {
type: AtlasSignInActions.CloseSignInModal;
};

export type AtlasSignInRestoringStartAction = {
type: AtlasSignInActions.RestoringStart;
};
Expand Down Expand Up @@ -250,24 +239,6 @@ const reducer: Reducer<AtlasSignInState, Action> = (
return { ...INITIAL_STATE, state: 'canceled' };
}

if (
isAction<AtlasSignInOpenModalAction>(
action,
AtlasSignInActions.OpenSignInModal
)
) {
return { ...state, isModalOpen: true };
}

if (
isAction<AtlasSignInCloseModalAction>(
action,
AtlasSignInActions.CloseSignInModal
)
) {
return { ...state, isModalOpen: false };
}

if (
isAction<AtlasSignInTokenRefreshFailedAction>(
action,
Expand Down Expand Up @@ -337,29 +308,6 @@ const startAttempt = (fn: () => void): AtlasSignInThunkAction<AttemptState> => {
};
};

export const signInWithModalPrompt = ({
signal,
}: { signal?: AbortSignal } = {}): AtlasSignInThunkAction<
Promise<AtlasUserInfo>
> => {
return async (dispatch, getState) => {
// Nothing to do if we already signed in
const { state, userInfo } = getState();
if (state === 'success') {
return userInfo;
}
const attempt = dispatch(
startAttempt(() => {
dispatch(openSignInModal());
})
);
signal?.addEventListener('abort', () => {
dispatch(closeSignInModal(signal.reason));
});
return attempt.promise;
};
};

export const signInWithoutPrompt = ({
signal,
}: { signal?: AbortSignal } = {}): AtlasSignInThunkAction<
Expand All @@ -383,12 +331,8 @@ export const signInWithoutPrompt = ({
};
};

export const openSignInModal = () => {
return { type: AtlasSignInActions.OpenSignInModal };
};

/**
* Sign in from the opt in window
* Sign into Atlas. To be called when the user isn't signed in yet.
*/
export const signIn = (): AtlasSignInThunkAction<Promise<void>> => {
return async (dispatch, getState, { atlasAuthService }) => {
Expand Down Expand Up @@ -434,15 +378,6 @@ export const signIn = (): AtlasSignInThunkAction<Promise<void>> => {
};
};

export const closeSignInModal = (
reason?: any
): AtlasSignInThunkAction<void> => {
return (dispatch) => {
dispatch(cancelSignIn(reason));
dispatch({ type: AtlasSignInActions.CloseSignInModal });
};
};

export const cancelSignIn = (reason?: any): AtlasSignInThunkAction<void> => {
return (dispatch, getState) => {
// Can't cancel sign in after the flow was finished indicated by current
Expand Down
2 changes: 0 additions & 2 deletions packages/compass-aggregations/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ import {
} from '@mongodb-js/compass-app-stores/provider';
import { workspacesServiceLocator } from '@mongodb-js/compass-workspaces/provider';
import { preferencesLocator } from 'compass-preferences-model/provider';
import { atlasAuthServiceLocator } from '@mongodb-js/atlas-service/provider';
import { atlasAiServiceLocator } from '@mongodb-js/compass-generative-ai/provider';
import { pipelineStorageLocator } from '@mongodb-js/my-queries-storage/provider';
import { connectionRepositoryAccessLocator } from '@mongodb-js/compass-connections/provider';
Expand All @@ -49,7 +48,6 @@ const CompassAggregationsHadronPlugin = registerHadronPlugin(
preferences: preferencesLocator,
logger: createLoggerLocator('COMPASS-AGGREGATIONS-UI'),
track: telemetryLocator,
atlasAuthService: atlasAuthServiceLocator,
atlasAiService: atlasAiServiceLocator,
pipelineStorage: pipelineStorageLocator,
connectionInfoRef: connectionInfoRefLocator,
Expand Down
2 changes: 0 additions & 2 deletions packages/compass-aggregations/src/modules/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@ import type { PreferencesAccess } from 'compass-preferences-model';
import type { Logger } from '@mongodb-js/compass-logging/provider';
import type AppRegistry from 'hadron-app-registry';
import type { AtlasAiService } from '@mongodb-js/compass-generative-ai/provider';
import type { AtlasAuthService } from '@mongodb-js/atlas-service/provider';
import type { MongoDBInstance } from 'mongodb-instance-model';
import type { DataService } from '../modules/data-service';
import type {
Expand Down Expand Up @@ -100,7 +99,6 @@ export type PipelineBuilderExtraArgs = {
localAppRegistry: AppRegistry;
pipelineBuilder: PipelineBuilder;
pipelineStorage: PipelineStorage;
atlasAuthService: AtlasAuthService;
workspaces: WorkspacesService;
preferences: PreferencesAccess;
logger: Logger;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -447,10 +447,10 @@ export const resetIsAggregationGeneratedFromQuery =
};

export const showInput = (): PipelineBuilderThunkAction<Promise<void>> => {
return async (dispatch, _getState, { atlasAuthService }) => {
return async (dispatch, _getState, { atlasAiService }) => {
try {
if (process.env.COMPASS_E2E_SKIP_ATLAS_SIGNIN !== 'true') {
await atlasAuthService.signIn({ promptType: 'ai-promo-modal' });
await atlasAiService.ensureAiFeatureAccess();
}
dispatch({
type: AIPipelineActionTypes.ShowInput,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,6 @@ function createStore({
thunk.withExtraArgument({
globalAppRegistry: new AppRegistry(),
localAppRegistry: new AppRegistry(),
atlasAuthService: {} as any,
atlasAiService: {} as any,
pipelineBuilder,
pipelineStorage: new CompassPipelineStorage(),
Expand Down
Loading
Loading