Skip to content

Commit 8aa2581

Browse files
committed
update store setup for new plugin, not sure it works
1 parent 552e4b7 commit 8aa2581

File tree

8 files changed

+248
-64
lines changed

8 files changed

+248
-64
lines changed

packages/compass-telemetry/src/telemetry-events.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2632,6 +2632,7 @@ type ScreenEvent = ConnectionScopedEvent<{
26322632
| 'my_queries'
26332633
| 'performance'
26342634
| 'schema'
2635+
| 'vector_visualizer'
26352636
| 'validation'
26362637
| 'confirm_new_pipeline_modal'
26372638
| 'create_collection_modal'

packages/compass-vector-embedding-visualizer/src/components/vector-visualizer.tsx

Lines changed: 41 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,21 @@
11
import React, { useEffect, useState } from 'react';
2+
import { connect } from 'react-redux';
23
import Plotly from 'plotly.js';
34
const PCA = require('ml-pca');
4-
import { Binary } from 'mongodb';
5+
import type { Binary } from 'mongodb';
6+
import type { Document } from 'bson';
7+
8+
import type { VectorEmbeddingVisualizerState } from '../stores/reducer';
9+
import { loadDocuments } from '../stores/visualization';
10+
import { ErrorSummary } from '@mongodb-js/compass-components';
511

612
type HoverInfo = { x: number; y: number; text: string } | null;
713

814
export interface VectorVisualizerProps {
9-
dataService: {
10-
find: (
11-
ns: string,
12-
filter: Record<string, unknown>,
13-
options?: { limit?: number }
14-
) => Promise<any[]>;
15-
};
15+
onFetchDocs: (namespace: string) => void;
16+
docs: Document[];
17+
loadingDocumentsState: 'initial' | 'loading' | 'loaded' | 'error';
18+
loadingDocumentsError: Error | null;
1619
collection: { namespace: string };
1720
}
1821

@@ -23,24 +26,33 @@ function normalizeTo2D(vectors: Binary[]): { x: number; y: number }[] {
2326
return reduced.map(([x, y]: [number, number]) => ({ x, y }));
2427
}
2528

26-
export const VectorVisualizer: React.FC<VectorVisualizerProps> = ({
27-
dataService,
29+
const VectorVisualizer: React.FC<VectorVisualizerProps> = ({
30+
onFetchDocs,
31+
docs,
32+
loadingDocumentsState,
33+
loadingDocumentsError,
2834
collection,
2935
}) => {
3036
const [hoverInfo, setHoverInfo] = useState<HoverInfo>(null);
3137

38+
useEffect(() => {
39+
if (loadingDocumentsState === 'initial') {
40+
// Fetch the documents when the component mounts when they aren't already loaded.
41+
onFetchDocs(collection.namespace);
42+
}
43+
}, [loadingDocumentsState, onFetchDocs, collection.namespace]);
44+
3245
useEffect(() => {
3346
const container = document.getElementById('vector-plot');
3447
if (!container) return;
3548

36-
let isMounted = true;
49+
const abortController = new AbortController();
3750

3851
const plot = async () => {
3952
try {
4053
const ns = collection?.namespace;
41-
if (!ns || !dataService) return;
54+
if (!ns) return;
4255

43-
const docs = await dataService.find(ns, {}, { limit: 1000 });
4456
const vectors = docs.map((doc) => doc.review_vec).filter(Boolean);
4557

4658
if (!vectors.length) return;
@@ -120,13 +132,16 @@ export const VectorVisualizer: React.FC<VectorVisualizerProps> = ({
120132
void plot();
121133

122134
return () => {
123-
isMounted = false;
135+
abortController.abort();
124136
};
125-
}, [collection?.namespace, dataService]);
137+
}, [docs, collection.namespace]);
126138

127139
return (
128140
<div style={{ position: 'relative', width: '100%', height: '100%' }}>
129141
<div id="vector-plot" style={{ width: '100%', height: '100%' }} />
142+
{loadingDocumentsError && (
143+
<ErrorSummary errors={loadingDocumentsError.message} />
144+
)}
130145
{hoverInfo && (
131146
<div
132147
style={{
@@ -148,3 +163,14 @@ export const VectorVisualizer: React.FC<VectorVisualizerProps> = ({
148163
</div>
149164
);
150165
};
166+
167+
export default connect(
168+
(state: VectorEmbeddingVisualizerState) => ({
169+
docs: state.visualization.docs,
170+
loadingDocumentsState: state.visualization.loadingDocumentsState,
171+
loadingDocumentsError: state.visualization.loadingDocumentsError,
172+
}),
173+
{
174+
onFetchDocs: loadDocuments,
175+
}
176+
)(VectorVisualizer);

packages/compass-vector-embedding-visualizer/src/index.ts

Lines changed: 20 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,17 @@ import React from 'react';
22
import { registerHadronPlugin } from 'hadron-app-registry';
33
import { createLoggerLocator } from '@mongodb-js/compass-logging/provider';
44
import { collectionModelLocator } from '@mongodb-js/compass-app-stores/provider';
5-
import { dataServiceLocator } from '@mongodb-js/compass-connections/provider';
6-
import { createStore } from 'redux';
5+
import {
6+
dataServiceLocator,
7+
type DataServiceLocator,
8+
} from '@mongodb-js/compass-connections/provider';
79

8-
import { VectorVisualizer } from './components/vector-visualizer';
9-
import { activateVectorPlugin } from './stores/store';
10-
11-
function reducer(state = {}, _action: any) {
12-
return state;
13-
}
10+
import VectorVisualizer from './components/vector-visualizer';
11+
import { VectorsTabTitle } from './plugin-tab-title';
12+
import {
13+
activateVectorPlugin,
14+
type VectorDataServiceProps,
15+
} from './stores/store';
1416

1517
export const CompassVectorPluginProvider = registerHadronPlugin(
1618
{
@@ -21,25 +23,25 @@ export const CompassVectorPluginProvider = registerHadronPlugin(
2123
activate: activateVectorPlugin,
2224
},
2325
{
24-
dataService: dataServiceLocator,
26+
dataService:
27+
dataServiceLocator as DataServiceLocator<VectorDataServiceProps>,
2528
collection: collectionModelLocator,
2629
logger: createLoggerLocator('COMPASS-VECTOR-VISUALIZER'),
2730
}
2831
);
2932

30-
const VectorVisualizerWrapper = (props: {
31-
dataService: any;
32-
collection: any;
33-
}) => {
34-
return React.createElement(VectorVisualizer, props);
35-
};
33+
// const VectorVisualizerWrapper = (props: {
34+
// dataService: any;
35+
// collection: any;
36+
// }) => {
37+
// return React.createElement(VectorVisualizer, props);
38+
// };
3639

3740
export const CompassVectorPlugin = {
3841
name: 'Vector Visualizer' as const,
39-
type: 'CollectionTab' as const,
4042
provider: CompassVectorPluginProvider,
41-
content: VectorVisualizerWrapper,
42-
header: () => React.createElement('div', null, 'Vector Embeddings'),
43+
content: VectorVisualizer, // VectorVisualizerWrapper,
44+
header: VectorsTabTitle,
4345
};
4446

4547
export default CompassVectorPluginProvider;
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import React from 'react';
2+
3+
export function VectorsTabTitle() {
4+
return <div>Vectors</div>;
5+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import type { AnyAction } from 'redux';
2+
import { combineReducers } from 'redux';
3+
import type {
4+
VisualizationActions,
5+
VisualizationActionTypes,
6+
} from './visualization';
7+
import type { ThunkAction } from 'redux-thunk';
8+
import { visualizationReducer } from './visualization';
9+
import type { VectorPluginServices } from './store';
10+
11+
const reducer = combineReducers({
12+
visualization: visualizationReducer,
13+
});
14+
15+
export type VectorEmbeddingVisualizerActions = VisualizationActions;
16+
17+
export type VectorEmbeddingVisualizerActionTypes = VisualizationActionTypes;
18+
19+
export type VectorEmbeddingVisualizerState = ReturnType<typeof reducer>;
20+
21+
export type VectorEmbeddingVisualizerExtraArgs = VectorPluginServices & {
22+
cancelControllerRef: { current: AbortController | null };
23+
};
24+
25+
export type VectorEmbeddingVisualizerThunkAction<
26+
R,
27+
A extends AnyAction
28+
> = ThunkAction<
29+
R,
30+
VectorEmbeddingVisualizerState,
31+
VectorEmbeddingVisualizerExtraArgs,
32+
A
33+
>;
34+
35+
export default reducer;
Lines changed: 35 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,19 @@
1-
import type { Store } from 'redux';
2-
import { createStore } from 'redux';
1+
import { applyMiddleware, createStore } from 'redux';
32
import type { DataService } from 'mongodb-data-service';
4-
import type { ConnectionInfoRef } from '@mongodb-js/compass-connections/provider';
3+
// import type { ConnectionInfoRef } from '@mongodb-js/compass-connections/provider';
54
import type {
65
Collection,
7-
MongoDBInstance,
6+
// MongoDBInstance,
87
} from '@mongodb-js/compass-app-stores/provider';
9-
import type AppRegistry from 'hadron-app-registry';
8+
// import type AppRegistry from 'hadron-app-registry';
109
import type { Logger } from '@mongodb-js/compass-logging';
11-
import type { TrackFunction } from '@mongodb-js/compass-telemetry';
12-
import type { AtlasService } from '@mongodb-js/atlas-service/provider';
13-
import type { PreferencesAccess } from 'compass-preferences-model';
10+
// import type { TrackFunction } from '@mongodb-js/compass-telemetry';
11+
// import type { AtlasService } from '@mongodb-js/atlas-service/provider';
12+
// import type { PreferencesAccess } from 'compass-preferences-model';
1413
import type { ActivateHelpers } from 'hadron-app-registry';
14+
import thunk from 'redux-thunk';
15+
16+
import reducer from './reducer';
1517

1618
export type VectorDataServiceProps =
1719
| 'find'
@@ -23,37 +25,39 @@ export type VectorDataService = Pick<DataService, VectorDataServiceProps>;
2325

2426
export type VectorPluginServices = {
2527
dataService: VectorDataService;
26-
connectionInfoRef: ConnectionInfoRef;
27-
instance: MongoDBInstance;
28-
localAppRegistry: Pick<AppRegistry, 'on' | 'emit' | 'removeListener'>;
29-
globalAppRegistry: Pick<AppRegistry, 'on' | 'emit' | 'removeListener'>;
3028
logger: Logger;
3129
collection: Collection;
32-
track: TrackFunction;
33-
atlasService: AtlasService;
34-
preferences: PreferencesAccess;
35-
};
3630

37-
export type VectorPluginOptions = {
38-
namespace: string;
39-
serverVersion: string;
40-
isReadonly: boolean;
41-
};
31+
// Note(Rhys): If we want more of these services, we can uncomment,
32+
// and then in ../index.ts, we add them as well.
4233

43-
export type VectorPluginStore = Store;
34+
// connectionInfoRef: ConnectionInfoRef;
35+
// instance: MongoDBInstance;
36+
// localAppRegistry: Pick<AppRegistry, 'on' | 'emit' | 'removeListener'>;
37+
// globalAppRegistry: Pick<AppRegistry, 'on' | 'emit' | 'removeListener'>;
38+
// track: TrackFunction;
39+
// atlasService: AtlasService;
40+
// preferences: PreferencesAccess;
41+
};
4442

45-
function reducer(state = {}, _action: any) {
46-
return state;
47-
}
43+
// export type VectorPluginOptions = {
44+
// namespace: string;
45+
// serverVersion: string;
46+
// isReadonly: boolean;
47+
// };
48+
export type VectorPluginOptions = Record<string, unknown>;
4849

4950
export function activateVectorPlugin(
5051
_options: VectorPluginOptions,
51-
_services: VectorPluginServices,
52+
services: VectorPluginServices,
5253
{ cleanup }: ActivateHelpers
5354
) {
54-
const store = createStore((state = {}) => state);
55-
return {
56-
store,
57-
deactivate: () => cleanup(),
58-
};
55+
const cancelControllerRef = { current: null };
56+
const store = createStore(
57+
reducer,
58+
applyMiddleware(
59+
thunk.withExtraArgument({ ...services, cancelControllerRef })
60+
)
61+
);
62+
return { store, deactivate: cleanup };
5963
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import type { AnyAction } from 'redux';
2+
import type {
3+
VectorEmbeddingVisualizerActions,
4+
VectorEmbeddingVisualizerActionTypes,
5+
} from './reducer';
6+
7+
export function isAction<T extends VectorEmbeddingVisualizerActionTypes>(
8+
action: AnyAction,
9+
type: T
10+
): action is Extract<VectorEmbeddingVisualizerActions, { type: T }> {
11+
return action.type === type;
12+
}

0 commit comments

Comments
 (0)