Skip to content

Commit 203ee82

Browse files
committed
manage request state in redux store
1 parent 0de12bc commit 203ee82

File tree

3 files changed

+169
-3
lines changed

3 files changed

+169
-3
lines changed

packages/compass-collection/src/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import { workspacesServiceLocator } from '@mongodb-js/compass-workspaces/provide
1414
import { experimentationServiceLocator } from '@mongodb-js/compass-telemetry/provider';
1515
import { createLoggerLocator } from '@mongodb-js/compass-logging/provider';
1616
import { preferencesLocator } from 'compass-preferences-model/provider';
17+
import { atlasAiServiceLocator } from '@mongodb-js/compass-generative-ai/provider';
1718
import {
1819
CollectionWorkspaceTitle,
1920
CollectionPluginTitleComponent,
@@ -32,6 +33,7 @@ export const WorkspaceTab: WorkspacePlugin<typeof CollectionWorkspaceTitle> = {
3233
{
3334
dataService: dataServiceLocator as DataServiceLocator<keyof DataService>,
3435
collection: collectionModelLocator,
36+
atlasAiService: atlasAiServiceLocator,
3537
workspaces: workspacesServiceLocator,
3638
experimentationServices: experimentationServiceLocator,
3739
connectionInfoRef: connectionInfoRefLocator,

packages/compass-collection/src/modules/collection-tab.ts

Lines changed: 159 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,18 @@ import { analyzeDocuments } from 'mongodb-schema';
44
import type { CollectionMetadata } from 'mongodb-collection-model';
55
import type { ThunkAction } from 'redux-thunk';
66
import type AppRegistry from '@mongodb-js/compass-app-registry';
7+
import type { ConnectionInfo } from '@mongodb-js/connection-info';
78
import type { workspacesServiceLocator } from '@mongodb-js/compass-workspaces/provider';
8-
import type { CollectionSubtab } from '@mongodb-js/compass-workspaces';
99
import type { DataService } from '@mongodb-js/compass-connections/provider';
10+
import type { CollectionSubtab } from '@mongodb-js/compass-workspaces';
11+
import type { AtlasAiService } from '@mongodb-js/compass-generative-ai/provider';
1012
import type { experimentationServiceLocator } from '@mongodb-js/compass-telemetry/provider';
1113
import { type Logger, mongoLogId } from '@mongodb-js/compass-logging/provider';
1214
import { type PreferencesAccess } from 'compass-preferences-model/provider';
15+
import {
16+
MockDataSchemaRequestShape,
17+
type MockDataSchemaResponse,
18+
} from '@mongodb-js/compass-generative-ai';
1319
import { isInternalFieldPath } from 'hadron-document';
1420
import toNS from 'mongodb-ns';
1521
import {
@@ -24,11 +30,18 @@ import {
2430
import { calculateSchemaDepth } from '../calculate-schema-depth';
2531
import { processSchema } from '../transform-schema-to-field-info';
2632
import type { Document, MongoError } from 'mongodb';
33+
import {
34+
MockDataGeneratorStep,
35+
MOCK_DATA_GENERATOR_STATE_IDLE,
36+
MOCK_DATA_GENERATOR_STATE_GENERATING,
37+
MOCK_DATA_GENERATOR_STATE_COMPLETED,
38+
MOCK_DATA_GENERATOR_STATE_ERROR,
39+
} from '../components/mock-data-generator-modal/types';
40+
import type { MockDataGeneratorState } from '../components/mock-data-generator-modal/types';
2741

2842
const DEFAULT_SAMPLE_SIZE = 100;
2943

3044
const NO_DOCUMENTS_ERROR = 'No documents found in the collection to analyze.';
31-
import { MockDataGeneratorStep } from '../components/mock-data-generator-modal/types';
3245

3346
function isAction<A extends AnyAction>(
3447
action: AnyAction,
@@ -61,6 +74,7 @@ type CollectionThunkAction<R, A extends AnyAction = AnyAction> = ThunkAction<
6174
{
6275
localAppRegistry: AppRegistry;
6376
dataService: DataService;
77+
atlasAiService: AtlasAiService;
6478
workspaces: ReturnType<typeof workspacesServiceLocator>;
6579
experimentationServices: ReturnType<typeof experimentationServiceLocator>;
6680
logger: Logger;
@@ -79,9 +93,10 @@ export type CollectionState = {
7993
isModalOpen: boolean;
8094
currentStep: MockDataGeneratorStep;
8195
};
96+
fakerSchemaGeneration: MockDataGeneratorState;
8297
};
8398

84-
enum CollectionActions {
99+
export enum CollectionActions {
85100
CollectionMetadataFetched = 'compass-collection/CollectionMetadataFetched',
86101
SchemaAnalysisStarted = 'compass-collection/SchemaAnalysisStarted',
87102
SchemaAnalysisFinished = 'compass-collection/SchemaAnalysisFinished',
@@ -91,6 +106,9 @@ enum CollectionActions {
91106
MockDataGeneratorModalClosed = 'compass-collection/MockDataGeneratorModalClosed',
92107
MockDataGeneratorNextButtonClicked = 'compass-collection/MockDataGeneratorNextButtonClicked',
93108
MockDataGeneratorPreviousButtonClicked = 'compass-collection/MockDataGeneratorPreviousButtonClicked',
109+
FakerMappingGenerationStarted = 'compass-collection/FakerMappingGenerationStarted',
110+
FakerMappingGenerationCompleted = 'compass-collection/FakerMappingGenerationCompleted',
111+
FakerMappingGenerationFailed = 'compass-collection/FakerMappingGenerationFailed',
94112
}
95113

96114
interface CollectionMetadataFetchedAction {
@@ -137,6 +155,23 @@ interface MockDataGeneratorPreviousButtonClickedAction {
137155
type: CollectionActions.MockDataGeneratorPreviousButtonClicked;
138156
}
139157

158+
interface FakerMappingGenerationStartedAction {
159+
type: CollectionActions.FakerMappingGenerationStarted;
160+
requestId: string;
161+
}
162+
163+
interface FakerMappingGenerationCompletedAction {
164+
type: CollectionActions.FakerMappingGenerationCompleted;
165+
fakerSchema: MockDataSchemaResponse;
166+
requestId: string;
167+
}
168+
169+
interface FakerMappingGenerationFailedAction {
170+
type: CollectionActions.FakerMappingGenerationFailed;
171+
error: string;
172+
requestId: string;
173+
}
174+
140175
const reducer: Reducer<CollectionState, Action> = (
141176
state = {
142177
// TODO(COMPASS-7782): use hook to get the workspace tab id instead
@@ -150,6 +185,9 @@ const reducer: Reducer<CollectionState, Action> = (
150185
isModalOpen: false,
151186
currentStep: MockDataGeneratorStep.AI_DISCLAIMER,
152187
},
188+
fakerSchemaGeneration: {
189+
status: MOCK_DATA_GENERATOR_STATE_IDLE,
190+
},
153191
},
154192
action
155193
) => {
@@ -332,6 +370,53 @@ const reducer: Reducer<CollectionState, Action> = (
332370
};
333371
}
334372

373+
if (
374+
isAction<FakerMappingGenerationStartedAction>(
375+
action,
376+
CollectionActions.FakerMappingGenerationStarted
377+
)
378+
) {
379+
return {
380+
...state,
381+
fakerSchemaGeneration: {
382+
status: MOCK_DATA_GENERATOR_STATE_GENERATING,
383+
requestId: action.requestId,
384+
},
385+
};
386+
}
387+
388+
if (
389+
isAction<FakerMappingGenerationCompletedAction>(
390+
action,
391+
CollectionActions.FakerMappingGenerationCompleted
392+
)
393+
) {
394+
return {
395+
...state,
396+
fakerSchemaGeneration: {
397+
status: MOCK_DATA_GENERATOR_STATE_COMPLETED,
398+
fakerSchema: action.fakerSchema,
399+
requestId: action.requestId,
400+
},
401+
};
402+
}
403+
404+
if (
405+
isAction<FakerMappingGenerationFailedAction>(
406+
action,
407+
CollectionActions.FakerMappingGenerationFailed
408+
)
409+
) {
410+
return {
411+
...state,
412+
fakerSchemaGeneration: {
413+
status: MOCK_DATA_GENERATOR_STATE_ERROR,
414+
error: action.error,
415+
requestId: action.requestId,
416+
},
417+
};
418+
}
419+
335420
return state;
336421
};
337422

@@ -458,6 +543,77 @@ export const analyzeCollectionSchema = (): CollectionThunkAction<
458543
};
459544
};
460545

546+
export const generateFakerMappings = (
547+
connectionInfo: ConnectionInfo
548+
): CollectionThunkAction<Promise<void>> => {
549+
return async (dispatch, getState, { logger, atlasAiService }) => {
550+
const { schemaAnalysis, fakerSchemaGeneration, namespace } = getState();
551+
if (schemaAnalysis.status !== SCHEMA_ANALYSIS_STATE_COMPLETE) {
552+
logger.log.error(
553+
mongoLogId(1_001_000_305),
554+
'Collection',
555+
'Cannot call `generateFakeMappings` unless schema analysis is complete'
556+
);
557+
return;
558+
}
559+
560+
if (fakerSchemaGeneration.status === MOCK_DATA_GENERATOR_STATE_GENERATING) {
561+
logger.debug(
562+
'Faker mapping generation is already in progress, skipping new generation.'
563+
);
564+
return;
565+
}
566+
567+
// todo: dedup/abort around requestId
568+
const requestId = 'some-request-id';
569+
570+
try {
571+
logger.debug('Generating faker mappings');
572+
573+
const { database, collection } = toNS(namespace);
574+
575+
dispatch({
576+
type: CollectionActions.FakerMappingGenerationStarted,
577+
requestId: requestId,
578+
});
579+
580+
const mockDataSchemaRequest = MockDataSchemaRequestShape.parse({
581+
databaseName: database,
582+
collectionName: collection,
583+
schema: schemaAnalysis.processedSchema,
584+
validationRules: schemaAnalysis.schemaMetadata.validationRules,
585+
});
586+
587+
const response = await atlasAiService.getMockDataSchema(
588+
mockDataSchemaRequest,
589+
connectionInfo
590+
);
591+
dispatch({
592+
type: CollectionActions.FakerMappingGenerationCompleted,
593+
fakerSchema: response,
594+
requestId: requestId,
595+
});
596+
} catch (e) {
597+
const errorMessage = e instanceof Error ? e.message : String(e);
598+
599+
logger.log.error(
600+
mongoLogId(1_001_000_312),
601+
'Collection',
602+
'Failed to generate faker.js mappings',
603+
{
604+
error: errorMessage,
605+
namespace,
606+
}
607+
);
608+
dispatch({
609+
type: CollectionActions.FakerMappingGenerationFailed,
610+
error: 'Experienced an issue generating faker.js mappings',
611+
requestId,
612+
});
613+
}
614+
};
615+
};
616+
461617
export type CollectionTabPluginMetadata = CollectionMetadata & {
462618
/**
463619
* Initial query for the query bar

packages/compass-collection/src/stores/collection-tab.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,15 @@ import reducer, {
99
analyzeCollectionSchema,
1010
} from '../modules/collection-tab';
1111
import { MockDataGeneratorStep } from '../components/mock-data-generator-modal/types';
12+
import { MOCK_DATA_GENERATOR_STATE_IDLE } from '../components/mock-data-generator-modal/types';
1213

1314
import type { Collection } from '@mongodb-js/compass-app-stores/provider';
1415
import type { ActivateHelpers } from '@mongodb-js/compass-app-registry';
1516
import type { workspacesServiceLocator } from '@mongodb-js/compass-workspaces/provider';
1617
import type { experimentationServiceLocator } from '@mongodb-js/compass-telemetry/provider';
1718
import type { connectionInfoRefLocator } from '@mongodb-js/compass-connections/provider';
1819
import type { Logger } from '@mongodb-js/compass-logging/provider';
20+
import type { AtlasAiService } from '@mongodb-js/compass-generative-ai/provider';
1921
import {
2022
isAIFeatureEnabled,
2123
type PreferencesAccess,
@@ -43,6 +45,7 @@ export type CollectionTabServices = {
4345
dataService: DataService;
4446
collection: Collection;
4547
localAppRegistry: AppRegistry;
48+
atlasAiService: AtlasAiService;
4649
workspaces: ReturnType<typeof workspacesServiceLocator>;
4750
experimentationServices: ReturnType<typeof experimentationServiceLocator>;
4851
connectionInfoRef: ReturnType<typeof connectionInfoRefLocator>;
@@ -62,6 +65,7 @@ export function activatePlugin(
6265
dataService,
6366
collection: collectionModel,
6467
localAppRegistry,
68+
atlasAiService,
6569
workspaces,
6670
experimentationServices,
6771
connectionInfoRef,
@@ -89,10 +93,14 @@ export function activatePlugin(
8993
isModalOpen: false,
9094
currentStep: MockDataGeneratorStep.AI_DISCLAIMER,
9195
},
96+
fakerSchemaGeneration: {
97+
status: MOCK_DATA_GENERATOR_STATE_IDLE,
98+
},
9299
},
93100
applyMiddleware(
94101
thunk.withExtraArgument({
95102
dataService,
103+
atlasAiService,
96104
workspaces,
97105
localAppRegistry,
98106
experimentationServices,

0 commit comments

Comments
 (0)