diff --git a/package-lock.json b/package-lock.json index 177b5c2acbc..0152e204571 100644 --- a/package-lock.json +++ b/package-lock.json @@ -7871,6 +7871,10 @@ "resolved": "packages/compass-crud", "link": true }, + "node_modules/@mongodb-js/compass-data-modeling": { + "resolved": "packages/compass-data-modeling", + "link": true + }, "node_modules/@mongodb-js/compass-databases-collections": { "resolved": "packages/databases-collections", "link": true @@ -43352,6 +43356,7 @@ "@mongodb-js/compass-connection-import-export": "^0.46.8", "@mongodb-js/compass-connections": "^1.50.8", "@mongodb-js/compass-crud": "^13.50.8", + "@mongodb-js/compass-data-modeling": "^1.0.0", "@mongodb-js/compass-databases-collections": "^1.49.8", "@mongodb-js/compass-explain-plan": "^6.50.8", "@mongodb-js/compass-export-to-language": "^9.26.8", @@ -44167,6 +44172,133 @@ "node": "*" } }, + "packages/compass-data-modeling": { + "name": "@mongodb-js/compass-data-modeling", + "version": "1.0.0", + "license": "SSPL", + "dependencies": { + "@mongodb-js/compass-connections": "^1.50.8", + "@mongodb-js/compass-logging": "^1.6.8", + "@mongodb-js/compass-telemetry": "^1.4.8", + "@mongodb-js/compass-workspaces": "^0.31.8", + "compass-preferences-model": "^2.33.8", + "hadron-app-registry": "^9.4.8", + "react": "^17.0.2", + "react-redux": "^8.1.3", + "redux": "^4.2.1", + "redux-thunk": "^2.4.2" + }, + "devDependencies": { + "@mongodb-js/eslint-config-compass": "^1.3.8", + "@mongodb-js/mocha-config-compass": "^1.6.8", + "@mongodb-js/prettier-config-compass": "^1.2.8", + "@mongodb-js/testing-library-compass": "^1.2.8", + "@mongodb-js/tsconfig-compass": "^1.2.8", + "@types/chai": "^4.2.21", + "@types/chai-dom": "^0.0.10", + "@types/mocha": "^9.0.0", + "@types/react": "^17.0.5", + "@types/react-dom": "^17.0.10", + "@types/sinon-chai": "^3.2.5", + "chai": "^4.3.6", + "depcheck": "^1.4.1", + "mocha": "^10.2.0", + "nyc": "^15.1.0", + "react-dom": "^17.0.2", + "sinon": "^17.0.1", + "typescript": "^5.0.4", + "xvfb-maybe": "^0.2.1" + } + }, + "packages/compass-data-modeling/node_modules/@sinonjs/commons": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.1.tgz", + "integrity": "sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "type-detect": "4.0.8" + } + }, + "packages/compass-data-modeling/node_modules/@sinonjs/fake-timers": { + "version": "11.3.1", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-11.3.1.tgz", + "integrity": "sha512-EVJO7nW5M/F5Tur0Rf2z/QoMo+1Ia963RiMtapiQrEWvY0iBUvADo8Beegwjpnle5BHkyHuoxSTW3jF43H1XRA==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@sinonjs/commons": "^3.0.1" + } + }, + "packages/compass-data-modeling/node_modules/@sinonjs/samsam": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-8.0.2.tgz", + "integrity": "sha512-v46t/fwnhejRSFTGqbpn9u+LQ9xJDse10gNnPgAcxgdoCDMXj/G2asWAC/8Qs+BAZDicX+MNZouXT1A7c83kVw==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@sinonjs/commons": "^3.0.1", + "lodash.get": "^4.4.2", + "type-detect": "^4.1.0" + } + }, + "packages/compass-data-modeling/node_modules/@sinonjs/samsam/node_modules/type-detect": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.1.0.tgz", + "integrity": "sha512-Acylog8/luQ8L7il+geoSxhEkazvkslg7PSNKOX59mbB9cOveP5aq9h74Y7YU8yDpJwetzQQrfIwtf4Wp4LKcw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "packages/compass-data-modeling/node_modules/just-extend": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/just-extend/-/just-extend-6.2.0.tgz", + "integrity": "sha512-cYofQu2Xpom82S6qD778jBDpwvvy39s1l/hrYij2u9AMdQcGRpaBu6kY4mVhuno5kJVi1DAz4aiphA2WI1/OAw==", + "dev": true, + "license": "MIT" + }, + "packages/compass-data-modeling/node_modules/nise": { + "version": "5.1.9", + "resolved": "https://registry.npmjs.org/nise/-/nise-5.1.9.tgz", + "integrity": "sha512-qOnoujW4SV6e40dYxJOb3uvuoPHtmLzIk4TFo+j0jPJoC+5Z9xja5qH5JZobEPsa8+YYphMrOSwnrshEhG2qww==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@sinonjs/commons": "^3.0.0", + "@sinonjs/fake-timers": "^11.2.2", + "@sinonjs/text-encoding": "^0.7.2", + "just-extend": "^6.2.0", + "path-to-regexp": "^6.2.1" + } + }, + "packages/compass-data-modeling/node_modules/path-to-regexp": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-6.3.0.tgz", + "integrity": "sha512-Yhpw4T9C6hPpgPeA28us07OJeqZ5EzQTkbfwuhsUg0c237RomFoETJgmp2sa3F/41gfLE6G5cqcYwznmeEeOlQ==", + "dev": true, + "license": "MIT" + }, + "packages/compass-data-modeling/node_modules/sinon": { + "version": "17.0.1", + "resolved": "https://registry.npmjs.org/sinon/-/sinon-17.0.1.tgz", + "integrity": "sha512-wmwE19Lie0MLT+ZYNpDymasPHUKTaZHUH/pKEubRXIzySv9Atnlw+BUMGCzWgV7b7wO+Hw6f1TEOr0IUnmU8/g==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@sinonjs/commons": "^3.0.0", + "@sinonjs/fake-timers": "^11.2.2", + "@sinonjs/samsam": "^8.0.0", + "diff": "^5.1.0", + "nise": "^5.1.5", + "supports-color": "^7.2.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/sinon" + } + }, "packages/compass-database": { "name": "@mongodb-js/compass-database", "version": "3.19.1", @@ -46860,6 +46992,7 @@ "@mongodb-js/compass-components": "^1.34.8", "@mongodb-js/compass-connections": "^1.50.8", "@mongodb-js/compass-crud": "^13.50.8", + "@mongodb-js/compass-data-modeling": "^1.0.0", "@mongodb-js/compass-databases-collections": "^1.49.8", "@mongodb-js/compass-explain-plan": "^6.50.8", "@mongodb-js/compass-export-to-language": "^9.26.8", @@ -56444,6 +56577,118 @@ } } }, + "@mongodb-js/compass-data-modeling": { + "version": "file:packages/compass-data-modeling", + "requires": { + "@mongodb-js/compass-connections": "^1.50.8", + "@mongodb-js/compass-logging": "^1.6.8", + "@mongodb-js/compass-telemetry": "^1.4.8", + "@mongodb-js/compass-workspaces": "^0.31.8", + "@mongodb-js/eslint-config-compass": "^1.3.8", + "@mongodb-js/mocha-config-compass": "^1.6.8", + "@mongodb-js/prettier-config-compass": "^1.2.8", + "@mongodb-js/testing-library-compass": "^1.2.8", + "@mongodb-js/tsconfig-compass": "^1.2.8", + "@types/chai": "^4.2.21", + "@types/chai-dom": "^0.0.10", + "@types/mocha": "^9.0.0", + "@types/react": "^17.0.5", + "@types/react-dom": "^17.0.10", + "@types/sinon-chai": "^3.2.5", + "chai": "^4.3.6", + "compass-preferences-model": "^2.33.8", + "depcheck": "^1.4.1", + "hadron-app-registry": "^9.4.8", + "mocha": "^10.2.0", + "nyc": "^15.1.0", + "react": "^17.0.2", + "react-dom": "^17.0.2", + "react-redux": "^8.1.3", + "redux": "^4.2.1", + "redux-thunk": "^2.4.2", + "sinon": "^17.0.1", + "typescript": "^5.0.4", + "xvfb-maybe": "^0.2.1" + }, + "dependencies": { + "@sinonjs/commons": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.1.tgz", + "integrity": "sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==", + "dev": true, + "requires": { + "type-detect": "4.0.8" + } + }, + "@sinonjs/fake-timers": { + "version": "11.3.1", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-11.3.1.tgz", + "integrity": "sha512-EVJO7nW5M/F5Tur0Rf2z/QoMo+1Ia963RiMtapiQrEWvY0iBUvADo8Beegwjpnle5BHkyHuoxSTW3jF43H1XRA==", + "dev": true, + "requires": { + "@sinonjs/commons": "^3.0.1" + } + }, + "@sinonjs/samsam": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-8.0.2.tgz", + "integrity": "sha512-v46t/fwnhejRSFTGqbpn9u+LQ9xJDse10gNnPgAcxgdoCDMXj/G2asWAC/8Qs+BAZDicX+MNZouXT1A7c83kVw==", + "dev": true, + "requires": { + "@sinonjs/commons": "^3.0.1", + "lodash.get": "^4.4.2", + "type-detect": "^4.1.0" + }, + "dependencies": { + "type-detect": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.1.0.tgz", + "integrity": "sha512-Acylog8/luQ8L7il+geoSxhEkazvkslg7PSNKOX59mbB9cOveP5aq9h74Y7YU8yDpJwetzQQrfIwtf4Wp4LKcw==", + "dev": true + } + } + }, + "just-extend": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/just-extend/-/just-extend-6.2.0.tgz", + "integrity": "sha512-cYofQu2Xpom82S6qD778jBDpwvvy39s1l/hrYij2u9AMdQcGRpaBu6kY4mVhuno5kJVi1DAz4aiphA2WI1/OAw==", + "dev": true + }, + "nise": { + "version": "5.1.9", + "resolved": "https://registry.npmjs.org/nise/-/nise-5.1.9.tgz", + "integrity": "sha512-qOnoujW4SV6e40dYxJOb3uvuoPHtmLzIk4TFo+j0jPJoC+5Z9xja5qH5JZobEPsa8+YYphMrOSwnrshEhG2qww==", + "dev": true, + "requires": { + "@sinonjs/commons": "^3.0.0", + "@sinonjs/fake-timers": "^11.2.2", + "@sinonjs/text-encoding": "^0.7.2", + "just-extend": "^6.2.0", + "path-to-regexp": "^6.2.1" + } + }, + "path-to-regexp": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-6.3.0.tgz", + "integrity": "sha512-Yhpw4T9C6hPpgPeA28us07OJeqZ5EzQTkbfwuhsUg0c237RomFoETJgmp2sa3F/41gfLE6G5cqcYwznmeEeOlQ==", + "dev": true + }, + "sinon": { + "version": "17.0.1", + "resolved": "https://registry.npmjs.org/sinon/-/sinon-17.0.1.tgz", + "integrity": "sha512-wmwE19Lie0MLT+ZYNpDymasPHUKTaZHUH/pKEubRXIzySv9Atnlw+BUMGCzWgV7b7wO+Hw6f1TEOr0IUnmU8/g==", + "dev": true, + "requires": { + "@sinonjs/commons": "^3.0.0", + "@sinonjs/fake-timers": "^11.2.2", + "@sinonjs/samsam": "^8.0.0", + "diff": "^5.1.0", + "nise": "^5.1.5", + "supports-color": "^7.2.0" + } + } + } + }, "@mongodb-js/compass-databases-collections": { "version": "file:packages/databases-collections", "requires": { @@ -58463,6 +58708,7 @@ "@mongodb-js/compass-components": "^1.34.8", "@mongodb-js/compass-connections": "^1.50.8", "@mongodb-js/compass-crud": "^13.50.8", + "@mongodb-js/compass-data-modeling": "^1.0.0", "@mongodb-js/compass-databases-collections": "^1.49.8", "@mongodb-js/compass-explain-plan": "^6.50.8", "@mongodb-js/compass-export-to-language": "^9.26.8", @@ -79192,6 +79438,7 @@ "@mongodb-js/compass-connection-import-export": "^0.46.8", "@mongodb-js/compass-connections": "^1.50.8", "@mongodb-js/compass-crud": "^13.50.8", + "@mongodb-js/compass-data-modeling": "^1.0.0", "@mongodb-js/compass-databases-collections": "^1.49.8", "@mongodb-js/compass-explain-plan": "^6.50.8", "@mongodb-js/compass-export-to-language": "^9.26.8", diff --git a/packages/compass-data-modeling/.depcheckrc b/packages/compass-data-modeling/.depcheckrc new file mode 100644 index 00000000000..ae7c8273e41 --- /dev/null +++ b/packages/compass-data-modeling/.depcheckrc @@ -0,0 +1,11 @@ +ignores: + - '@mongodb-js/prettier-config-compass' + - '@mongodb-js/tsconfig-compass' + - '@types/chai' + - '@types/sinon-chai' + - 'sinon' + - '@types/chai-dom' + - '@types/react' + - '@types/react-dom' +ignore-patterns: + - 'dist' diff --git a/packages/compass-data-modeling/.eslintignore b/packages/compass-data-modeling/.eslintignore new file mode 100644 index 00000000000..85a8a75e68c --- /dev/null +++ b/packages/compass-data-modeling/.eslintignore @@ -0,0 +1,2 @@ +.nyc-output +dist diff --git a/packages/compass-data-modeling/.eslintrc.js b/packages/compass-data-modeling/.eslintrc.js new file mode 100644 index 00000000000..f06f8fc6013 --- /dev/null +++ b/packages/compass-data-modeling/.eslintrc.js @@ -0,0 +1,8 @@ +module.exports = { + root: true, + extends: ['@mongodb-js/eslint-config-compass/plugin'], + parserOptions: { + tsconfigRootDir: __dirname, + project: ['./tsconfig-lint.json'], + }, +}; diff --git a/packages/compass-data-modeling/.mocharc.js b/packages/compass-data-modeling/.mocharc.js new file mode 100644 index 00000000000..a7e53abc444 --- /dev/null +++ b/packages/compass-data-modeling/.mocharc.js @@ -0,0 +1 @@ +module.exports = require('@mongodb-js/mocha-config-compass/compass-plugin'); diff --git a/packages/compass-data-modeling/package.json b/packages/compass-data-modeling/package.json new file mode 100644 index 00000000000..6ea711d5dad --- /dev/null +++ b/packages/compass-data-modeling/package.json @@ -0,0 +1,90 @@ +{ + "name": "@mongodb-js/compass-data-modeling", + "description": "Data modeling diagram workspace and all related services", + "author": { + "name": "MongoDB Inc", + "email": "compass@mongodb.com" + }, + "private": true, + "bugs": { + "url": "https://jira.mongodb.org/projects/COMPASS/issues", + "email": "compass@mongodb.com" + }, + "homepage": "https://github.com/mongodb-js/compass", + "version": "1.0.0", + "repository": { + "type": "git", + "url": "https://github.com/mongodb-js/compass.git" + }, + "files": [ + "dist" + ], + "license": "SSPL", + "main": "dist/index.js", + "compass:main": "src/index.ts", + "exports": { + ".": "./dist/index.js", + "./provider": "./dist/provider/index.js", + "./renderer": "./dist/services/data-model-storage-electron.js", + "./web": "./dist/services/data-model-storage-web.js" + }, + "compass:exports": { + ".": "./src/index.ts", + "./provider": "./src/provider/index.ts", + "./renderer": "./src/services/data-model-storage-electron.ts", + "./web": "./src/services/data-model-storage-web.ts" + }, + "types": "./dist/index.d.ts", + "scripts": { + "bootstrap": "npm run compile", + "compile": "tsc -p tsconfig.json", + "typecheck": "tsc -p tsconfig-lint.json --noEmit", + "eslint": "eslint-compass", + "prettier": "prettier-compass", + "lint": "npm run eslint . && npm run prettier -- --check .", + "depcheck": "compass-scripts check-peer-deps && depcheck", + "check": "npm run typecheck && npm run lint && npm run depcheck", + "check-ci": "npm run check", + "test": "mocha", + "test-electron": "xvfb-maybe electron-mocha --no-sandbox", + "test-cov": "nyc --compact=false --produce-source-map=false -x \"**/*.spec.*\" --reporter=lcov --reporter=text --reporter=html npm run test", + "test-watch": "npm run test -- --watch", + "test-ci": "npm run test-cov", + "test-ci-electron": "npm run test-electron", + "reformat": "npm run eslint . -- --fix && npm run prettier -- --write ." + }, + "dependencies": { + "@mongodb-js/compass-connections": "^1.50.8", + "@mongodb-js/compass-logging": "^1.6.8", + "@mongodb-js/compass-telemetry": "^1.4.8", + "@mongodb-js/compass-workspaces": "^0.31.8", + "compass-preferences-model": "^2.33.8", + "hadron-app-registry": "^9.4.8", + "react": "^17.0.2", + "react-redux": "^8.1.3", + "redux": "^4.2.1", + "redux-thunk": "^2.4.2" + }, + "devDependencies": { + "@mongodb-js/eslint-config-compass": "^1.3.8", + "@mongodb-js/mocha-config-compass": "^1.6.8", + "@mongodb-js/prettier-config-compass": "^1.2.8", + "@mongodb-js/testing-library-compass": "^1.2.8", + "@mongodb-js/tsconfig-compass": "^1.2.8", + "@types/chai": "^4.2.21", + "@types/chai-dom": "^0.0.10", + "@types/mocha": "^9.0.0", + "@types/react": "^17.0.5", + "@types/react-dom": "^17.0.10", + "@types/sinon-chai": "^3.2.5", + "chai": "^4.3.6", + "depcheck": "^1.4.1", + "mocha": "^10.2.0", + "nyc": "^15.1.0", + "react-dom": "^17.0.2", + "sinon": "^17.0.1", + "typescript": "^5.0.4", + "xvfb-maybe": "^0.2.1" + }, + "is_compass_plugin": true +} diff --git a/packages/compass-data-modeling/src/components/data-modeling.tsx b/packages/compass-data-modeling/src/components/data-modeling.tsx new file mode 100644 index 00000000000..76331712164 --- /dev/null +++ b/packages/compass-data-modeling/src/components/data-modeling.tsx @@ -0,0 +1,12 @@ +import React from 'react'; +import { connect } from 'react-redux'; + +type DataModelingPluginInitialProps = Record; + +const DataModeling: React.FunctionComponent< + DataModelingPluginInitialProps +> = () => { + return <>Hello from Data Modeling plugin; +}; + +export default connect()(DataModeling); diff --git a/packages/compass-data-modeling/src/index.spec.tsx b/packages/compass-data-modeling/src/index.spec.tsx new file mode 100644 index 00000000000..3c3cf401c05 --- /dev/null +++ b/packages/compass-data-modeling/src/index.spec.tsx @@ -0,0 +1,12 @@ +import React from 'react'; +import { expect } from 'chai'; +import { render } from '@mongodb-js/testing-library-compass'; +import CompassPlugin from './index'; + +describe('Compass Plugin', function () { + const Plugin = CompassPlugin.withMockServices({}); + + it('renders a Plugin', function () { + expect(() => render()).to.not.throw(); + }); +}); diff --git a/packages/compass-data-modeling/src/index.ts b/packages/compass-data-modeling/src/index.ts new file mode 100644 index 00000000000..1217c7e03f1 --- /dev/null +++ b/packages/compass-data-modeling/src/index.ts @@ -0,0 +1,37 @@ +import { applyMiddleware, createStore } from 'redux'; +import thunk from 'redux-thunk'; +import { registerHadronPlugin } from 'hadron-app-registry'; +import { preferencesLocator } from 'compass-preferences-model/provider'; +import { connectionsLocator } from '@mongodb-js/compass-connections/provider'; +import { telemetryLocator } from '@mongodb-js/compass-telemetry/provider'; +import { createLoggerLocator } from '@mongodb-js/compass-logging/provider'; +import type { WorkspaceComponent } from '@mongodb-js/compass-workspaces'; +import DataModelingComponent from './components/data-modeling'; +import reducer from './store/reducer'; + +const DataModelingPlugin = registerHadronPlugin( + { + name: 'DataModeling', + component: DataModelingComponent, + activate(initialProps, services, { cleanup }) { + const store = createStore( + reducer, + applyMiddleware(thunk.withExtraArgument(services)) + ); + return { store, deactivate: cleanup }; + }, + }, + { + preferences: preferencesLocator, + connections: connectionsLocator, + telemetry: telemetryLocator, + logger: createLoggerLocator('COMPASS-DATA-MODELING'), + } +); + +export const WorkspaceTab: WorkspaceComponent<'Data Modeling'> = { + name: 'Data Modeling', + component: DataModelingPlugin, +}; + +export default DataModelingPlugin; diff --git a/packages/compass-data-modeling/src/provider/index.ts b/packages/compass-data-modeling/src/provider/index.ts new file mode 100644 index 00000000000..e69de29bb2d diff --git a/packages/compass-data-modeling/src/services/data-model-storage-electron.ts b/packages/compass-data-modeling/src/services/data-model-storage-electron.ts new file mode 100644 index 00000000000..ab422c6883a --- /dev/null +++ b/packages/compass-data-modeling/src/services/data-model-storage-electron.ts @@ -0,0 +1,11 @@ +import type { DataModelStorage } from './data-model-storage'; + +class DataModelStorageElectron implements DataModelStorage { + get() { + return {}; + } +} + +const storage = new DataModelStorageElectron(); + +export default storage; diff --git a/packages/compass-data-modeling/src/services/data-model-storage-web.ts b/packages/compass-data-modeling/src/services/data-model-storage-web.ts new file mode 100644 index 00000000000..a3de1ef7097 --- /dev/null +++ b/packages/compass-data-modeling/src/services/data-model-storage-web.ts @@ -0,0 +1,11 @@ +import type { DataModelStorage } from './data-model-storage'; + +class DataModelStorageWeb implements DataModelStorage { + get() { + return {}; + } +} + +const storage = new DataModelStorageWeb(); + +export default storage; diff --git a/packages/compass-data-modeling/src/services/data-model-storage.ts b/packages/compass-data-modeling/src/services/data-model-storage.ts new file mode 100644 index 00000000000..40be3e39bf2 --- /dev/null +++ b/packages/compass-data-modeling/src/services/data-model-storage.ts @@ -0,0 +1,5 @@ +type MongoDBDataModelDescription = unknown; + +export interface DataModelStorage { + get(): MongoDBDataModelDescription; +} diff --git a/packages/compass-data-modeling/src/store/reducer.ts b/packages/compass-data-modeling/src/store/reducer.ts new file mode 100644 index 00000000000..c22f75a6aeb --- /dev/null +++ b/packages/compass-data-modeling/src/store/reducer.ts @@ -0,0 +1,9 @@ +import type { Reducer } from 'redux'; + +type DataModelingState = unknown; + +const reducer: Reducer = (state) => { + return state; +}; + +export default reducer; diff --git a/packages/compass-data-modeling/tsconfig-lint.json b/packages/compass-data-modeling/tsconfig-lint.json new file mode 100644 index 00000000000..6bdef84f322 --- /dev/null +++ b/packages/compass-data-modeling/tsconfig-lint.json @@ -0,0 +1,5 @@ +{ + "extends": "./tsconfig.json", + "include": ["**/*"], + "exclude": ["node_modules", "dist"] +} diff --git a/packages/compass-data-modeling/tsconfig.json b/packages/compass-data-modeling/tsconfig.json new file mode 100644 index 00000000000..79bc84584ce --- /dev/null +++ b/packages/compass-data-modeling/tsconfig.json @@ -0,0 +1,8 @@ +{ + "extends": "@mongodb-js/tsconfig-compass/tsconfig.react.json", + "compilerOptions": { + "outDir": "dist" + }, + "include": ["src/**/*"], + "exclude": ["./src/**/*.spec.*"] +} diff --git a/packages/compass-preferences-model/src/feature-flags.ts b/packages/compass-preferences-model/src/feature-flags.ts index 07d88b7a978..99a438f6455 100644 --- a/packages/compass-preferences-model/src/feature-flags.ts +++ b/packages/compass-preferences-model/src/feature-flags.ts @@ -23,6 +23,7 @@ export type FeatureFlags = { enableProxySupport: boolean; enableRollingIndexes: boolean; enableGlobalWrites: boolean; + enableDataModeling: boolean; }; export const featureFlags: Required<{ @@ -111,4 +112,14 @@ export const featureFlags: Required<{ short: 'Enable schema export', }, }, + + /** + * https://jira.mongodb.org/browse/INIT-592 + */ + enableDataModeling: { + stage: 'development', + description: { + short: 'Design, Visualize, and Evolve your Data Model', + }, + }, }; diff --git a/packages/compass-sidebar/src/components/multiple-connections/navigation/navigation.tsx b/packages/compass-sidebar/src/components/multiple-connections/navigation/navigation.tsx index ae336f751b2..6d8ebcfa1bf 100644 --- a/packages/compass-sidebar/src/components/multiple-connections/navigation/navigation.tsx +++ b/packages/compass-sidebar/src/components/multiple-connections/navigation/navigation.tsx @@ -11,6 +11,7 @@ import { useOpenWorkspace, useWorkspacePlugins, } from '@mongodb-js/compass-workspaces/provider'; +import { usePreference } from 'compass-preferences-model/provider'; import React from 'react'; const navigationItem = css({ @@ -98,7 +99,9 @@ export function Navigation({ currentLocation: string | null; }): React.ReactElement { const { hasWorkspacePlugin } = useWorkspacePlugins(); - const { openMyQueriesWorkspace } = useOpenWorkspace(); + const { openMyQueriesWorkspace, openDataModelingWorkspace } = + useOpenWorkspace(); + const isDataModelingEnabled = usePreference('enableDataModeling'); return (
{hasWorkspacePlugin('My Queries') && ( @@ -109,6 +112,14 @@ export function Navigation({ isActive={currentLocation === 'My Queries'} /> )} + {isDataModelingEnabled && ( + + )}
); } diff --git a/packages/compass-web/package.json b/packages/compass-web/package.json index e8aaa014d16..dcc907a01a1 100644 --- a/packages/compass-web/package.json +++ b/packages/compass-web/package.json @@ -70,6 +70,7 @@ "@mongodb-js/compass-components": "^1.34.8", "@mongodb-js/compass-connections": "^1.50.8", "@mongodb-js/compass-crud": "^13.50.8", + "@mongodb-js/compass-data-modeling": "^1.0.0", "@mongodb-js/compass-databases-collections": "^1.49.8", "@mongodb-js/compass-explain-plan": "^6.50.8", "@mongodb-js/compass-export-to-language": "^9.26.8", diff --git a/packages/compass-web/sandbox/index.tsx b/packages/compass-web/sandbox/index.tsx index c488cd0e717..b2d6e900776 100644 --- a/packages/compass-web/sandbox/index.tsx +++ b/packages/compass-web/sandbox/index.tsx @@ -143,6 +143,7 @@ const App = () => { isAtlas && !!enableGenAIFeaturesAtlasOrg, optInDataExplorerGenAIFeatures: isAtlas && !!optInDataExplorerGenAIFeatures, + enableDataModeling: true, }} onTrack={sandboxTelemetry.track} onDebug={sandboxLogger.debug} diff --git a/packages/compass-web/src/entrypoint.tsx b/packages/compass-web/src/entrypoint.tsx index cdabbeb5ed8..9b1695b4024 100644 --- a/packages/compass-web/src/entrypoint.tsx +++ b/packages/compass-web/src/entrypoint.tsx @@ -60,6 +60,7 @@ import { useCompassWebLoggerAndTelemetry } from './logger-and-telemetry'; import { type TelemetryServiceOptions } from '@mongodb-js/compass-telemetry'; import { WebWorkspaceTab as WelcomeWorkspaceTab } from '@mongodb-js/compass-welcome'; import { useCompassWebPreferences } from './preferences'; +import { WorkspaceTab as DataModelingWorkspace } from '@mongodb-js/compass-data-modeling'; const WithAtlasProviders: React.FC = ({ children }) => { return ( @@ -174,6 +175,7 @@ function CompassWorkspace({ DatabasesWorkspaceTab, CollectionsWorkspaceTab, CollectionWorkspace, + DataModelingWorkspace, ]} > | WorkspaceComponent<'My Queries'> + | WorkspaceComponent<'Data Modeling'> | WorkspaceComponent<'Shell'> | WorkspaceComponent<'Performance'> | WorkspaceComponent<'Databases'> diff --git a/packages/compass-workspaces/src/components/workspaces.tsx b/packages/compass-workspaces/src/components/workspaces.tsx index ca54a2c04d4..b894b0fb6e0 100644 --- a/packages/compass-workspaces/src/components/workspaces.tsx +++ b/packages/compass-workspaces/src/components/workspaces.tsx @@ -182,6 +182,13 @@ const CompassWorkspaces: React.FunctionComponent = ({ title: tab.type, iconGlyph: 'CurlyBraces', } as const; + case 'Data Modeling': + return { + id: tab.id, + type: tab.type, + title: tab.type, + iconGlyph: 'Diagram' as const, + }; case 'Shell': { const connectionName = getConnectionById(tab.connectionId)?.title || ''; @@ -306,7 +313,8 @@ const CompassWorkspaces: React.FunctionComponent = ({ const activeWorkspaceElement = useMemo(() => { switch (activeTab?.type) { case 'Welcome': - case 'My Queries': { + case 'My Queries': + case 'Data Modeling': { const Component = getWorkspacePluginByName(activeTab.type); return ; } diff --git a/packages/compass-workspaces/src/index.ts b/packages/compass-workspaces/src/index.ts index 870991a0d85..f64d9732d09 100644 --- a/packages/compass-workspaces/src/index.ts +++ b/packages/compass-workspaces/src/index.ts @@ -236,6 +236,7 @@ export type { OpenWorkspaceOptions, WorkspaceTab, CollectionTabInfo }; export type { WelcomeWorkspace, MyQueriesWorkspace, + DataModelingWorkspace, ServerStatsWorkspace, ShellWorkspace, DatabasesWorkspace, diff --git a/packages/compass-workspaces/src/provider.tsx b/packages/compass-workspaces/src/provider.tsx index d9c6f5bae6a..c3a9316d0cc 100644 --- a/packages/compass-workspaces/src/provider.tsx +++ b/packages/compass-workspaces/src/provider.tsx @@ -42,6 +42,11 @@ export type WorkspacesService = { */ openMyQueriesWorkspace(this: void, tabOptions?: TabOptions): void; + /** + * Open "Data Modeling" workspace + */ + openDataModelingWorkspace(this: void): void; + /** * Open "Shell" workspace */ @@ -204,6 +209,7 @@ const noopWorkspacesService = { return null; }, openMyQueriesWorkspace: throwIfNotTestEnv, + openDataModelingWorkspace: throwIfNotTestEnv, openShellWorkspace: throwIfNotTestEnv, openDatabasesWorkspace: throwIfNotTestEnv, openPerformanceWorkspace: throwIfNotTestEnv, @@ -241,6 +247,11 @@ export const WorkspacesServiceProvider: React.FunctionComponent<{ openWorkspaceAction({ type: 'My Queries' }, tabOptions) ); }, + openDataModelingWorkspace: () => { + return void store.dispatch( + openWorkspaceAction({ type: 'Data Modeling' }) + ); + }, openShellWorkspace(connectionId, options = {}) { const { newTab, ...workspaceOptions } = options; return void store.dispatch( @@ -331,6 +342,7 @@ export function useOpenWorkspace() { openCollectionsWorkspace, openDatabasesWorkspace, openMyQueriesWorkspace, + openDataModelingWorkspace, openPerformanceWorkspace, openEditViewWorkspace, } = useWorkspacesService(); @@ -341,6 +353,7 @@ export function useOpenWorkspace() { openCollectionsWorkspace, openDatabasesWorkspace, openMyQueriesWorkspace, + openDataModelingWorkspace, openPerformanceWorkspace, openEditViewWorkspace, }); diff --git a/packages/compass-workspaces/src/stores/workspaces.ts b/packages/compass-workspaces/src/stores/workspaces.ts index 570636da802..214165c51ae 100644 --- a/packages/compass-workspaces/src/stores/workspaces.ts +++ b/packages/compass-workspaces/src/stores/workspaces.ts @@ -8,6 +8,7 @@ import type { CollectionsWorkspace, DatabasesWorkspace, MyQueriesWorkspace, + DataModelingWorkspace, ShellWorkspace, ServerStatsWorkspace, WelcomeWorkspace, @@ -85,6 +86,7 @@ function isAction( type WorkspaceTabProps = | Omit | Omit + | Omit | Omit | Omit | Omit @@ -334,10 +336,8 @@ const reducer: Reducer = ( // if both the new workspace and the existing one are connection scoped, // make sure we do not replace tabs between different connections if ( - action.workspace.type !== 'Welcome' && - action.workspace.type !== 'My Queries' && - currentActiveTab.type !== 'Welcome' && - currentActiveTab.type !== 'My Queries' + 'connectionId' in action.workspace && + 'connectionId' in currentActiveTab ) { forceNewTab = action.workspace.connectionId !== currentActiveTab.connectionId; @@ -345,8 +345,9 @@ const reducer: Reducer = ( // ... check if we can replace the current tab based on its // replace handlers and force new tab opening if we can't - if (!forceNewTab) + if (!forceNewTab) { forceNewTab = canReplaceTab(currentActiveTab) === false; + } } } @@ -526,10 +527,9 @@ const reducer: Reducer = ( WorkspacesActions.ConnectionDisconnected ) ) { - const isToBeClosed = (tab: WorkspaceTab) => - tab.type !== 'My Queries' && - tab.type !== 'Welcome' && - tab.connectionId === action.connectionId; + const isToBeClosed = (tab: WorkspaceTab) => { + return 'connectionId' in tab && tab.connectionId === action.connectionId; + }; return _bulkTabsClose({ state, @@ -639,6 +639,7 @@ export const getActiveTab = (state: WorkspacesState): WorkspaceTab | null => { export type OpenWorkspaceOptions = | Pick, 'type'> | Pick, 'type'> + | Pick, 'type'> | Pick< Workspace<'Shell'>, 'type' | 'connectionId' | 'initialEvaluate' | 'initialInput' diff --git a/packages/compass-workspaces/src/types.ts b/packages/compass-workspaces/src/types.ts index 9a2fca9f88b..a744c060e61 100644 --- a/packages/compass-workspaces/src/types.ts +++ b/packages/compass-workspaces/src/types.ts @@ -14,6 +14,10 @@ export type MyQueriesWorkspace = { type: 'My Queries'; }; +export type DataModelingWorkspace = { + type: 'Data Modeling'; +}; + export type ShellWorkspace = { type: 'Shell'; connectionId: string; @@ -57,6 +61,7 @@ export type CollectionWorkspace = { export type AnyWorkspace = | WelcomeWorkspace | MyQueriesWorkspace + | DataModelingWorkspace | ShellWorkspace | ServerStatsWorkspace | DatabasesWorkspace diff --git a/packages/compass/package.json b/packages/compass/package.json index 6f2c082b3f9..a433072999f 100644 --- a/packages/compass/package.json +++ b/packages/compass/package.json @@ -191,7 +191,6 @@ "devDependencies": { "@electron/rebuild": "^3.7.2", "@electron/remote": "^2.1.2", - "@types/minimatch": "^5.1.2", "@mongodb-js/atlas-service": "^0.35.8", "@mongodb-js/compass-aggregations": "^9.52.8", "@mongodb-js/compass-app-stores": "^7.36.8", @@ -200,6 +199,7 @@ "@mongodb-js/compass-connection-import-export": "^0.46.8", "@mongodb-js/compass-connections": "^1.50.8", "@mongodb-js/compass-crud": "^13.50.8", + "@mongodb-js/compass-data-modeling": "^1.0.0", "@mongodb-js/compass-databases-collections": "^1.49.8", "@mongodb-js/compass-explain-plan": "^6.50.8", "@mongodb-js/compass-export-to-language": "^9.26.8", @@ -238,6 +238,7 @@ "@mongodb-js/tsconfig-compass": "^1.2.8", "@mongodb-js/webpack-config-compass": "^1.6.8", "@segment/analytics-node": "^1.1.4", + "@types/minimatch": "^5.1.2", "ampersand-view": "^9.0.0", "bson": "^6.10.3", "chai": "^4.3.4", @@ -253,12 +254,12 @@ "electron-mocha": "^12.2.0", "ensure-error": "^3.0.1", "glob": "^10.2.5", - "local-links": "^1.4.0", - "make-fetch-happen": "^10.2.1", - "marky": "^1.2.1", "hadron-app-registry": "^9.4.8", "hadron-build": "^25.7.9", "hadron-ipc": "^3.4.8", + "local-links": "^1.4.0", + "make-fetch-happen": "^10.2.1", + "marky": "^1.2.1", "minimatch": "^10.0.1", "mongodb": "^6.14.1", "mongodb-build-info": "^1.7.2", diff --git a/packages/compass/src/app/components/workspace.tsx b/packages/compass/src/app/components/workspace.tsx index f01ee297238..cbef0332fce 100644 --- a/packages/compass/src/app/components/workspace.tsx +++ b/packages/compass/src/app/components/workspace.tsx @@ -39,6 +39,7 @@ import ExportToLanguageCollectionTabModal from '@mongodb-js/compass-export-to-la import updateTitle from '../utils/update-title'; import { getConnectionTitle } from '@mongodb-js/connection-info'; import { useConnectionsListRef } from '@mongodb-js/compass-connections/provider'; +import { WorkspaceTab as DataModelingWorkspace } from '@mongodb-js/compass-data-modeling'; export default function Workspace({ appName, @@ -55,12 +56,9 @@ export default function Workspace({ (ws: WorkspaceTab | null, collectionInfo: CollectionTabInfo | null) => { onActiveWorkspaceTabChange(ws, collectionInfo); - const namespace = - ws && (ws.type === 'Collection' || ws.type === 'Collections') - ? ws.namespace - : undefined; + const namespace = ws && 'namespace' in ws ? ws.namespace : undefined; const connectionInfo = - ws && ws.type !== 'My Queries' && ws.type !== 'Welcome' + ws && 'connectionId' in ws ? getConnectionById(ws.connectionId)?.info : undefined; updateTitle( @@ -83,6 +81,7 @@ export default function Workspace({ DatabasesWorkspaceTab, CollectionsWorkspaceTab, CollectionWorkspace, + DataModelingWorkspace, ]} >