diff --git a/package-lock.json b/package-lock.json index 32a0b384fe7..c484a5a22fb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -49501,6 +49501,7 @@ "version": "1.32.0", "license": "SSPL", "dependencies": { + "@mongodb-js/atlas-service": "^0.65.0", "@mongodb-js/compass-app-registry": "^9.4.27", "@mongodb-js/compass-app-stores": "^7.67.0", "@mongodb-js/compass-components": "^1.55.0", @@ -63556,6 +63557,7 @@ "@mongodb-js/compass-data-modeling": { "version": "file:packages/compass-data-modeling", "requires": { + "@mongodb-js/atlas-service": "^0.65.0", "@mongodb-js/compass-app-registry": "^9.4.27", "@mongodb-js/compass-app-stores": "^7.67.0", "@mongodb-js/compass-components": "^1.55.0", diff --git a/packages/atlas-service/src/atlas-service.ts b/packages/atlas-service/src/atlas-service.ts index 183a42012cb..4ffe27627d6 100644 --- a/packages/atlas-service/src/atlas-service.ts +++ b/packages/atlas-service/src/atlas-service.ts @@ -81,7 +81,11 @@ export class AtlasService { userDataEndpoint( orgId: string, groupId: string, - type: 'favoriteQueries' | 'recentQueries' | 'favoriteAggregations', + type: + | 'favoriteQueries' + | 'recentQueries' + | 'favoriteAggregations' + | 'dataModelDescriptions', id?: string ): string { const encodedOrgId = encodeURIComponent(orgId); diff --git a/packages/compass-components/src/components/file-selector.tsx b/packages/compass-components/src/components/file-selector.tsx index 373c08e2982..b113928fe89 100644 --- a/packages/compass-components/src/components/file-selector.tsx +++ b/packages/compass-components/src/components/file-selector.tsx @@ -2,7 +2,9 @@ import React, { type InputHTMLAttributes, useRef } from 'react'; import { css } from '@leafygreen-ui/emotion'; const displayNoneStyles = css({ - display: 'none', + // make sure actual input is always hidden (mms is doing something weird + // forcing these to be visible) + display: 'none !important', }); type FileSelectorTriggerProps = { diff --git a/packages/compass-data-modeling/package.json b/packages/compass-data-modeling/package.json index 63308c5be91..d03291c6947 100644 --- a/packages/compass-data-modeling/package.json +++ b/packages/compass-data-modeling/package.json @@ -26,13 +26,13 @@ ".": "./dist/index.js", "./provider": "./dist/provider/index.js", "./renderer": "./dist/services/data-model-storage-electron.js", - "./web": "./dist/services/data-model-storage-in-memory.js" + "./web": "./dist/services/data-model-storage-web.js" }, "compass:exports": { ".": "./src/index.ts", "./provider": "./src/provider/index.tsx", "./renderer": "./src/services/data-model-storage-electron.tsx", - "./web": "./src/services/data-model-storage-in-memory.tsx" + "./web": "./src/services/data-model-storage-web.tsx" }, "types": "./dist/index.d.ts", "scripts": { @@ -54,6 +54,7 @@ "reformat": "npm run eslint . -- --fix && npm run prettier -- --write ." }, "dependencies": { + "@mongodb-js/atlas-service": "^0.65.0", "@mongodb-js/compass-app-registry": "^9.4.27", "@mongodb-js/compass-app-stores": "^7.67.0", "@mongodb-js/compass-components": "^1.55.0", diff --git a/packages/compass-data-modeling/src/services/data-model-storage-web.tsx b/packages/compass-data-modeling/src/services/data-model-storage-web.tsx new file mode 100644 index 00000000000..04638a75868 --- /dev/null +++ b/packages/compass-data-modeling/src/services/data-model-storage-web.tsx @@ -0,0 +1,129 @@ +import { AtlasUserData } from '@mongodb-js/compass-user-data'; +import type { + DataModelStorage, + MongoDBDataModelDescription, +} from './data-model-storage'; +import { MongoDBDataModelDescriptionSchema } from './data-model-storage'; +import dataModelStorageInMemory from './data-model-storage-in-memory'; +import { + atlasServiceLocator, + type AtlasService, +} from '@mongodb-js/atlas-service/provider'; +import { createServiceProvider } from '@mongodb-js/compass-app-registry'; +import { DataModelStorageServiceProvider } from '../provider'; +import React, { useRef } from 'react'; +import { mongoLogId, useLogger } from '@mongodb-js/compass-logging/provider'; + +class DataModelStorageAtlas implements DataModelStorage { + private readonly userData: AtlasUserData< + typeof MongoDBDataModelDescriptionSchema + >; + constructor(orgId: string, projectId: string, atlasService: AtlasService) { + this.userData = new AtlasUserData( + MongoDBDataModelDescriptionSchema, + 'dataModelDescriptions', + { + orgId, + projectId, + getResourceUrl(path) { + // TODO(COMPASS-9960): this is copied from compass-web entrypoint for + // brevity, but shouldn't be defined outside of AtlasUserData, this + // logic is literally the same between all user data instances and can + // be encapsulated inside of the AtlasUserData class implementation + const [type, pathOrgId, pathProjectId, id] = + path?.split('/').filter(Boolean) || []; + + if ( + !type || + !pathOrgId || + !pathProjectId || + type !== 'dataModelDescriptions' + ) { + throw new Error( + 'DataModelStorageAtlas is used outside of Atlas Cloud context' + ); + } + + return atlasService.userDataEndpoint( + pathOrgId, + pathProjectId, + type, + id + ); + }, + authenticatedFetch: atlasService.authenticatedFetch.bind(atlasService), + } + ); + } + save(description: MongoDBDataModelDescription) { + return this.userData.write(description.id, description); + } + delete(id: MongoDBDataModelDescription['id']) { + return this.userData.delete(id); + } + async loadAll(): Promise { + try { + const res = await this.userData.readAll(); + return res.data; + } catch { + return []; + } + } + async load(id: string): Promise { + return ( + (await this.loadAll()).find((item) => { + return item.id === id; + }) ?? null + ); + } +} + +export const DataModelStorageServiceProviderWeb = createServiceProvider( + function DataModelStorageServiceProviderWeb({ + children, + orgId, + projectId, + }: { + /** + * Atlas organization id. Optional. If provided, data model storage will + * save the user data in Atlas Cloud, otherwise will fall back to in-memory + * storage + */ + orgId?: string; + /** + * Atlas project id. Optional. If provided, data model storage will + * save the user data in Atlas Cloud, otherwise will fall back to in-memory + * storage + */ + projectId?: string; + children?: React.ReactNode; + }) { + const storageRef = useRef(); + const atlasService = atlasServiceLocator(); + const logger = useLogger('DATA-MODEL-STORAGE'); + + if (!storageRef.current) { + if (orgId && projectId) { + storageRef.current = new DataModelStorageAtlas( + orgId, + projectId, + atlasService + ); + } else { + logger.log.warn( + mongoLogId(1_001_000_379), + 'DataModelStorageServiceProviderWeb', + 'Falling back to in memory storage because orgId or projectId is missing' + ); + // Fallback to in-memory if we're outside of Atlas Cloud + storageRef.current = dataModelStorageInMemory; + } + } + + return ( + + {children} + + ); + } +); diff --git a/packages/compass-data-modeling/web.d.ts b/packages/compass-data-modeling/web.d.ts index ed685938a24..af1d4190f57 100644 --- a/packages/compass-data-modeling/web.d.ts +++ b/packages/compass-data-modeling/web.d.ts @@ -1 +1 @@ -export * from './dist/services/data-model-storage-in-memory.d'; +export * from './dist/services/data-model-storage-web.d'; diff --git a/packages/compass-data-modeling/web.js b/packages/compass-data-modeling/web.js index 904ae04d64d..9fa8b57b899 100644 --- a/packages/compass-data-modeling/web.js +++ b/packages/compass-data-modeling/web.js @@ -1,2 +1,2 @@ 'use strict'; -module.exports = require('./dist/services/data-model-storage-in-memory'); +module.exports = require('./dist/services/data-model-storage-web'); diff --git a/packages/compass-web/sandbox/index.tsx b/packages/compass-web/sandbox/index.tsx index 25e46e7e29e..cb9c6e4b0e7 100644 --- a/packages/compass-web/sandbox/index.tsx +++ b/packages/compass-web/sandbox/index.tsx @@ -38,6 +38,7 @@ const App = () => { const [currentTab, updateCurrentTab] = useWorkspaceTabRouter(); const { status, projectParams } = useAtlasProxySignIn(); const { + orgId, projectId, csrfToken, csrfTime, @@ -99,7 +100,7 @@ const App = () => { - + - +