├── .eslintrc.cjs ├── .github └── workflows │ ├── ci.yml │ └── publish-app.yml ├── .gitignore ├── .husky └── pre-commit ├── .prettierignore ├── .prettierrc.json ├── LICENSE ├── README.md ├── db-examples ├── version-0-0 │ ├── 00-user-applications-role.mml │ ├── 01-restaurant-menu.mml │ ├── 02-book-store.mml │ ├── 03-social-network.mml │ ├── 04-feed.mml │ ├── 05-m-flix.mml │ └── 06-analytics.mml └── version-0-1 │ └── 05-m-flix.mml ├── e2e ├── add-new-collection.spec.ts └── launch-mongodb-designer-link.spec.ts ├── editor.html ├── index.html ├── landing ├── favicon.png ├── favicon.svg └── index.html ├── media └── mongo-modeler.jpg ├── package-lock.json ├── package.json ├── playwright.config.ts ├── public ├── android-chrome-128x128.png ├── android-chrome-144x144.png ├── android-chrome-192x192.png ├── android-chrome-512x512.png ├── android-chrome-72x72.png ├── apple-touch-icon.png ├── assets │ ├── abel-de-tena.jpeg │ ├── alberto-santiago.png │ ├── aridane-martin.jpg │ ├── cristina-gonzalez.jpg │ ├── fran-lopez.jpg │ ├── leticia-de-la-osa.jpeg │ ├── logo_mongo_modeler_dark_mode.svg │ ├── logo_mongo_modeler_light_mode.svg │ ├── manuel-gallego-barra.jpeg │ ├── marcos-apocada.jpeg │ ├── miguel-galvez.jpg │ ├── mobile-development.svg │ ├── team-work-cuate.svg │ ├── teresa-milanes.jpeg │ ├── tony-torres.jpeg │ └── veronica-camarzana.jpeg ├── browserconfig.xml ├── favicon-16x16.png ├── favicon-32x32.png ├── favicon.ico ├── favicon.png ├── favicon.svg ├── manifest.json ├── mongo-modeler-app.jpg ├── mstile-150x150.png └── safari-pinned-tab.svg ├── src ├── App.css ├── App.tsx ├── common │ ├── a11y │ │ ├── click-outside.hook.ts │ │ ├── common.model.ts │ │ ├── focus.common-helpers.ts │ │ ├── index.ts │ │ ├── list │ │ │ ├── focus.helpers.ts │ │ │ ├── index.ts │ │ │ ├── list.hooks.ts │ │ │ └── list.model.ts │ │ ├── nested-list │ │ │ ├── index.ts │ │ │ ├── nested-list.hooks.ts │ │ │ ├── nested-list.mappers.ts │ │ │ └── nested-list.model.ts │ │ ├── nested-select │ │ │ ├── index.ts │ │ │ ├── nested-select.hooks.ts │ │ │ ├── nested-select.mappers.ts │ │ │ └── nested-select.model.ts │ │ ├── nested.hooks.ts │ │ ├── on-key.hook.ts │ │ ├── on-two-Keys.hook.ts │ │ └── select │ │ │ ├── focus.helpers.ts │ │ │ ├── index.ts │ │ │ ├── select.hooks.ts │ │ │ ├── select.mappers.ts │ │ │ └── select.model.ts │ ├── components │ │ ├── checkbox │ │ │ ├── checkbox.component.module.css │ │ │ ├── checkbox.component.tsx │ │ │ └── index.ts │ │ ├── dropdown │ │ │ ├── dropdown.component.module.css │ │ │ ├── dropdown.component.tsx │ │ │ ├── dropdown.const.ts │ │ │ ├── dropdown.model.ts │ │ │ └── index.ts │ │ ├── forms │ │ │ ├── checkbox-formik │ │ │ │ ├── checkbox-formik.component.module.css │ │ │ │ ├── checkbox-formik.component.tsx │ │ │ │ └── index.ts │ │ │ ├── dropdown-formik │ │ │ │ ├── dropdown-formik.component.tsx │ │ │ │ ├── dropdown.component.module.css │ │ │ │ └── index.ts │ │ │ ├── index.ts │ │ │ ├── input-formik │ │ │ │ ├── index.ts │ │ │ │ ├── input-formik.component.module.css │ │ │ │ └── input-formik.component.tsx │ │ │ └── table-pk-picker-formik │ │ │ │ ├── index.ts │ │ │ │ ├── table-pk-picker-formik.component.tsx │ │ │ │ └── table-pk-picker.component.module.css │ │ ├── icons │ │ │ ├── about-icon.component.tsx │ │ │ ├── add-folder.component.tsx │ │ │ ├── add-icon.component.tsx │ │ │ ├── canvas-setting-icon.component.tsx │ │ │ ├── collection-icon.component.tsx │ │ │ ├── copy-icon.component.tsx │ │ │ ├── dark-icon.component.tsx │ │ │ ├── down-icon.tsx │ │ │ ├── drag-drop-icon.component.tsx │ │ │ ├── edit-icon.component.tsx │ │ │ ├── expand-down-icon.component.tsx │ │ │ ├── export-icon.component.tsx │ │ │ ├── import-icon.component.tsx │ │ │ ├── index.ts │ │ │ ├── light-icon.component.tsx │ │ │ ├── linkedin-icon.component.tsx │ │ │ ├── new-icon.component.tsx │ │ │ ├── open-icon.component.tsx │ │ │ ├── paste-icon.component.tsx │ │ │ ├── redo-icon.component.tsx │ │ │ ├── relation-icon.component.tsx │ │ │ ├── remove-icon.component.tsx │ │ │ ├── right-arrow.component.tsx │ │ │ ├── save-icon.component.tsx │ │ │ ├── tick-icon.component.tsx │ │ │ ├── trash-icon.component.tsx │ │ │ ├── undo-icon.component.tsx │ │ │ ├── up-icon.component.tsx │ │ │ ├── zoom-in-icon.component.tsx │ │ │ └── zoom-out-icon.component.tsx │ │ ├── index.ts │ │ ├── modal-dialog │ │ │ ├── index.ts │ │ │ ├── modal-dialog.component.tsx │ │ │ ├── modal-dialog.const.ts │ │ │ ├── modal-dialog.styles.module.css │ │ │ └── modal.dialog.bussines.ts │ │ └── table-pk-picker │ │ │ ├── components │ │ │ ├── field-tree.component.tsx │ │ │ ├── generate-options.component.tsx │ │ │ └── nested-options.component.tsx │ │ │ ├── index.ts │ │ │ ├── table-pk-picker.business.spec.ts │ │ │ ├── table-pk-picker.business.ts │ │ │ ├── table-pk-picker.component.module.css │ │ │ ├── table-pk-picker.component.tsx │ │ │ ├── table-pk-picker.const.ts │ │ │ └── table-pk-picker.model.ts │ ├── export │ │ ├── classic-download.ts │ │ ├── download-svg.business.ts │ │ ├── index.ts │ │ └── save-file-modern.ts │ ├── file-input │ │ ├── index.ts │ │ └── open-file.ts │ ├── helpers │ │ ├── platform.helpers.spec.ts │ │ ├── platform.helpers.ts │ │ ├── set-off-set-zoom-to-coords.helper.spec.tsx │ │ └── set-off-set-zoom-to-coords.helper.tsx │ ├── local-storage │ │ ├── index.ts │ │ └── local-storage.helpers.ts │ └── undo-redo │ │ ├── history-manager.business.spec.ts │ │ ├── history-manager.business.ts │ │ ├── history-manager.hook.ts │ │ └── index.ts ├── core │ ├── autosave │ │ ├── autosave.business.spec.ts │ │ ├── autosave.business.ts │ │ ├── autosave.hook.ts │ │ └── index.ts │ ├── model │ │ └── index.ts │ └── providers │ │ ├── canvas-schema │ │ ├── business-specs │ │ │ ├── canvas-calculaterelationx.business.spec.ts │ │ │ ├── canvas-delete-item.business.spec.ts │ │ │ ├── canvas-findfield.business.spec.ts │ │ │ ├── canvas-put-table-on-top.business.spec.ts │ │ │ ├── canvas-relationycoordinate.bussiness.spec.ts │ │ │ ├── canvas-schema.business.spec.ts │ │ │ ├── canvas-updateposition.business.spec.ts │ │ │ └── canvas.business-toggle-collapse.spec.ts │ │ ├── canvas-schema-v0.model.ts │ │ ├── canvas-schema-vlatest.model.ts │ │ ├── canvas-schema.business.ts │ │ ├── canvas-schema.context.ts │ │ ├── canvas-schema.hook.spec.tsx │ │ ├── canvas-schema.hook.tsx │ │ ├── canvas-schema.mapper.spec.ts │ │ ├── canvas-schema.mapper.ts │ │ ├── canvas-schema.provider.tsx │ │ ├── canvas.business.spec.ts │ │ ├── canvas.business.ts │ │ ├── canvas.const.ts │ │ └── index.ts │ │ ├── canvas-view-settings │ │ ├── canvas-view-settings.consts.ts │ │ ├── canvas-view-settings.context.tsx │ │ ├── canvas-view-settings.model.ts │ │ ├── canvas-view-settings.provider.tsx │ │ └── index.ts │ │ ├── device-provider │ │ ├── device.context.tsx │ │ ├── device.model.ts │ │ ├── device.provider.tsx │ │ └── index.ts │ │ ├── index.ts │ │ ├── modal-dialog-provider │ │ ├── index.ts │ │ ├── modal-dialog.context.tsx │ │ ├── modal-dialog.model.ts │ │ └── modal-dialog.provider.tsx │ │ └── theme-provider │ │ ├── index.ts │ │ ├── theme-context.tsx │ │ ├── theme-provider.tsx │ │ ├── theme.business.ts │ │ └── theme.model.ts ├── dummy.spec.ts ├── main.tsx ├── pods │ ├── about │ │ ├── about.pod.module.css │ │ ├── about.pod.tsx │ │ ├── components │ │ │ ├── members.component.module.css │ │ │ └── members.component.tsx │ │ ├── index.ts │ │ └── members.ts │ ├── canvas-settings │ │ ├── canvas-settings.pod.module.css │ │ ├── canvas-settings.pod.tsx │ │ ├── canvas-settings.validation.ts │ │ └── index.ts │ ├── canvas │ │ ├── canvas-svg.component.tsx │ │ ├── canvas.mock.data.ts │ │ ├── canvas.pod.module.css │ │ ├── canvas.pod.tsx │ │ ├── components │ │ │ ├── canvas-accessible │ │ │ │ ├── canvas-accessible.component.tsx │ │ │ │ ├── canvas-accessible.pod.module.css │ │ │ │ ├── canvas-accessible.pod.tsx │ │ │ │ ├── components │ │ │ │ │ ├── collection-accessible.component.tsx │ │ │ │ │ ├── collection-list-accessible.component.tsx │ │ │ │ │ ├── empty-canvas-accessible.component.tsx │ │ │ │ │ ├── empty-relations-accessible.component.tsx │ │ │ │ │ ├── field-accessible.component.tsx │ │ │ │ │ ├── field-list-accessible.component.tsx │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── relation-accesible.bussines.spec.ts │ │ │ │ │ ├── relation-accesible.bussines.ts │ │ │ │ │ ├── relation-accessible.component.tsx │ │ │ │ │ ├── relation-list-accessible.component.tsx │ │ │ │ │ ├── table-relations-accessible-element-destination.component.tsx │ │ │ │ │ ├── table-relations-accessible-element-origin.component.tsx │ │ │ │ │ ├── table-relations-accessible.business-find-field-name-and-parent.spec.ts │ │ │ │ │ ├── table-relations-accessible.business-get-type-of-relation-for-table.spec.ts │ │ │ │ │ ├── table-relations-accessible.business.ts │ │ │ │ │ └── table-relations-accessible.component.tsx │ │ │ │ └── index.ts │ │ │ ├── relation │ │ │ │ ├── components │ │ │ │ │ ├── clickable-line.component.tsx │ │ │ │ │ ├── clickable-path.component.module.css │ │ │ │ │ ├── clickable-path.component.tsx │ │ │ │ │ ├── clickeable-self.component.tsx │ │ │ │ │ ├── fork.component.module.css │ │ │ │ │ ├── fork.component.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── database-relation-collection.business.spec.ts │ │ │ │ ├── database-relation-collection.business.ts │ │ │ │ ├── database-relation-collection.component.tsx │ │ │ │ ├── database-relation-self.business.ts │ │ │ │ ├── database-relation-self.component.tsx │ │ │ │ ├── database-relation-two-tables-path.business.spec.ts │ │ │ │ ├── database-relation-two-tables-path.business.ts │ │ │ │ ├── database-relation-two-tables-path.component.tsx │ │ │ │ ├── database-relation-two-tables-straight.component.tsx │ │ │ │ ├── database-relation.component.module.css │ │ │ │ ├── index.ts │ │ │ │ ├── relation.business.ts │ │ │ │ └── relation.vm.ts │ │ │ └── table │ │ │ │ ├── components │ │ │ │ ├── database-table-body.tsx │ │ │ │ ├── database-table-border.component.tsx │ │ │ │ ├── database-table-header.component.tsx │ │ │ │ ├── database-table-row.component.tsx │ │ │ │ ├── index.ts │ │ │ │ ├── selected-table-filter-highlight.component.tsx │ │ │ │ └── truncated-text.component.tsx │ │ │ │ ├── database-table-render-rows.helper.tsx │ │ │ │ ├── database-table.buiness.spec.ts │ │ │ │ ├── database-table.business.ts │ │ │ │ ├── database-table.component.tsx │ │ │ │ ├── database-table.const.ts │ │ │ │ ├── database-table.module.css │ │ │ │ └── table-drag.hook.tsx │ │ ├── index.ts │ │ └── m-flix.mock.data.ts │ ├── edit-relation │ │ ├── edit-relation.business.ts │ │ ├── edit-relation.component.tsx │ │ ├── edit-relation.pod.module.css │ │ ├── edit-relation.pod.tsx │ │ ├── edit-relation.validation.ts │ │ ├── edit-relation.vm.ts │ │ ├── find-field-recursively.business.spec.ts │ │ ├── index.ts │ │ └── map-relation-form.vm.spec.ts │ ├── edit-table │ │ ├── components │ │ │ ├── commands │ │ │ │ ├── command-icon-button.tsx │ │ │ │ ├── commands.business-first-item.spec.ts │ │ │ │ ├── commands.business-last-item.spec.ts │ │ │ │ ├── commands.business.ts │ │ │ │ └── commands.component.tsx │ │ │ ├── field.tsx │ │ │ └── nested-field-grid.tsx │ │ ├── edit-table.business-add-field-logic.spec.ts │ │ ├── edit-table.business-move-down-field.spec.ts │ │ ├── edit-table.business-move-up-field.spec.ts │ │ ├── edit-table.business.spec.ts │ │ ├── edit-table.business.ts │ │ ├── edit-table.component.tsx │ │ ├── edit-table.mapper.spec.ts │ │ ├── edit-table.mapper.ts │ │ ├── edit-table.module.css │ │ ├── edit-table.pod.tsx │ │ ├── edit-table.vm.ts │ │ ├── index.ts │ │ └── use-input-focus.hook.ts │ ├── export │ │ ├── canvas-export-svg.component.tsx │ │ ├── components │ │ │ ├── relation │ │ │ │ ├── components │ │ │ │ │ ├── database-relation-self-export.component.tsx │ │ │ │ │ ├── database-relation-two-tables-path-export.component.tsx │ │ │ │ │ ├── database-relation-two-tables-straight-export.component.tsx │ │ │ │ │ ├── fork-export.component.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── database-relation-collection.component.tsx │ │ │ │ └── index.ts │ │ │ └── table │ │ │ │ ├── database-table-row.component.tsx │ │ │ │ └── database-table.component.tsx │ │ ├── export-table.module.css │ │ ├── export-table.pod.tsx │ │ ├── export-variables.const.ts │ │ └── index.ts │ ├── footer │ │ ├── footer.business.ts │ │ ├── footer.component.tsx │ │ ├── footer.pod.module.css │ │ ├── footer.pod.tsx │ │ └── index.ts │ ├── import-collection │ │ ├── import-panel.business.spec.ts │ │ ├── import-panel.business.ts │ │ ├── import-panel.model.ts │ │ ├── import-panel.pod.module.css │ │ └── import-panel.pod.tsx │ └── toolbar │ │ ├── components │ │ ├── about-button │ │ │ ├── about-button.tsx │ │ │ └── index.ts │ │ ├── add-collection │ │ │ ├── add-collection.component.tsx │ │ │ └── index.ts │ │ ├── canvas-setting-button │ │ │ ├── canvas-setting-button.component.tsx │ │ │ └── index.ts │ │ ├── copy-button │ │ │ ├── copy-button.component.tsx │ │ │ └── index.ts │ │ ├── delete-button │ │ │ ├── delete-button.component.tsx │ │ │ └── index.ts │ │ ├── duplicate-button │ │ │ ├── duplicate-button.component.tsx │ │ │ └── index.ts │ │ ├── export-button │ │ │ ├── export-button.business.spec.ts │ │ │ ├── export-button.business.ts │ │ │ ├── export-button.component.tsx │ │ │ ├── export-coordinate.helpers.ts │ │ │ └── index.ts │ │ ├── import-button │ │ │ ├── import-button.component.tsx │ │ │ └── index.ts │ │ ├── index.ts │ │ ├── new-button │ │ │ ├── index.ts │ │ │ └── new-button.component.tsx │ │ ├── open-button │ │ │ ├── index.ts │ │ │ └── open-button.component.tsx │ │ ├── paste-button │ │ │ ├── index.ts │ │ │ └── paste-button.component.tsx │ │ ├── redo-button │ │ │ ├── index.ts │ │ │ └── redo-button.component.tsx │ │ ├── relation-button │ │ │ ├── index.ts │ │ │ └── relation-button.component.tsx │ │ ├── save-button │ │ │ ├── index.ts │ │ │ └── save-button.component.tsx │ │ ├── theme-toggle-button │ │ │ ├── index.ts │ │ │ └── themeToggleButton.component.tsx │ │ ├── toolbar-button │ │ │ ├── index.ts │ │ │ ├── toolbarButton.component.spec.tsx │ │ │ └── toolbarButton.component.tsx │ │ ├── undo-button │ │ │ ├── index.ts │ │ │ └── undo-button.component.tsx │ │ └── zoom-button │ │ │ ├── index.ts │ │ │ ├── zoom-in-button.component.tsx │ │ │ └── zoom-out-button.component.tsx │ │ ├── shortcut │ │ ├── shortcut.const.ts │ │ ├── shortcut.hook.spec.tsx │ │ ├── shortcut.hook.tsx │ │ └── shortcut.model.ts │ │ ├── toolbar.pod.module.css │ │ └── toolbar.pod.tsx ├── scenes │ ├── index.ts │ ├── main.scene.module.css │ └── main.scene.tsx └── vite-env.d.ts ├── tsconfig.json ├── tsconfig.node.json ├── vite.config.ts └── vitest.setup.ts /.eslintrc.cjs: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | env: { browser: true, es2020: true }, 4 | extends: [ 5 | 'eslint:recommended', 6 | 'plugin:@typescript-eslint/recommended', 7 | 'plugin:react-hooks/recommended', 8 | ], 9 | ignorePatterns: ['dist', '.eslintrc.cjs'], 10 | parser: '@typescript-eslint/parser', 11 | plugins: ['react-refresh'], 12 | rules: { 13 | 'react-refresh/only-export-components': [ 14 | 'warn', 15 | { allowConstantExport: true }, 16 | ], 17 | }, 18 | }; 19 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI workflow 2 | 3 | on: pull_request 4 | 5 | jobs: 6 | ci: 7 | runs-on: ubuntu-latest 8 | steps: 9 | - name: Checkout repository 10 | uses: actions/checkout@v2 11 | # Temporary workaround 12 | # See this bug on Vite + Rollup node v 20 13 | # https://github.com/vitejs/vite/issues/15492 14 | - name: Use Node.js 18.13.0 15 | uses: actions/setup-node@v2 16 | with: 17 | node-version: '18.13.0' 18 | cache: 'npm' 19 | - name: Install front 20 | run: npm install 21 | - name: Build 22 | run: npm run tsc-check 23 | - name: Tests front 24 | run: npm test 25 | 26 | e2e-tests: 27 | runs-on: ubuntu-latest 28 | steps: 29 | - name: Checkout repository 30 | uses: actions/checkout@v2 31 | 32 | - name: Use Node.js 18.13.0 33 | uses: actions/setup-node@v2 34 | with: 35 | node-version: '18.13.0' 36 | cache: 'npm' 37 | 38 | - name: Install dependencies 39 | run: npm ci 40 | 41 | - name: Build 42 | run: npm run build 43 | 44 | - name: Check TypeScript Types 45 | run: npm run tsc-check 46 | 47 | - name: Run E2E tests 48 | run: npm run ci:e2e 49 | -------------------------------------------------------------------------------- /.github/workflows/publish-app.yml: -------------------------------------------------------------------------------- 1 | name: Publish app 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | 8 | jobs: 9 | deploy-react-app: 10 | environment: 11 | name: 'Website' 12 | url: https://www.mongo-modeler.com 13 | runs-on: ubuntu-latest 14 | steps: 15 | - uses: actions/checkout@v3 16 | - name: Install 17 | run: npm ci 18 | - name: Build 19 | run: npm run build 20 | - name: Deploy 21 | uses: Azure/static-web-apps-deploy@v1 22 | with: 23 | azure_static_web_apps_api_token: ${{ secrets.AZURE_STATIC_WEB_APPS_API_TOKEN_MANGO_GLACIER_093E76303 }} 24 | repo_token: ${{ secrets.GITHUB_TOKEN }} 25 | action: 'upload' 26 | app_location: 'dist' 27 | output_location: 'dist' 28 | skip_app_build: true 29 | skip_api_build: true 30 | env: 31 | NODE_VERSION: 18.16.0 32 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | /test-results/ 26 | /playwright-report/ 27 | /blob-report/ 28 | /playwright/.cache/ 29 | -------------------------------------------------------------------------------- /.husky/pre-commit: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | . "$(dirname -- "$0")/_/husky.sh" 3 | 4 | 5 | npx lint-staged 6 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist -------------------------------------------------------------------------------- /.prettierrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "printWidth": 80, 3 | "singleQuote": true, 4 | "useTabs": false, 5 | "tabWidth": 2, 6 | "semi": true, 7 | "bracketSpacing": true, 8 | "trailingComma": "es5", 9 | "arrowParens": "avoid", 10 | "endOfLine": "lf" 11 | } 12 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Lemoncode 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /db-examples/version-0-0/00-user-applications-role.mml: -------------------------------------------------------------------------------- 1 | {"tables":[{"id":"a1f11df4-9469-4f4b-aa6d-86a22a7ac9de","tableName":"User","fields":[{"id":"bad20722-6054-40df-9de1-d50191314883","PK":true,"name":"_id","type":"objectId","children":[]},{"id":"d3d9cf6c-4de3-4b61-9b52-1b8e47b5a441","PK":false,"name":"name","type":"string","children":[]},{"id":"cb063bff-7a1d-476e-a6cb-121193acb038","PK":false,"name":"application_roles","type":"object","isArray":true,"children":[{"id":"e10d158f-2b3b-4676-b929-ef71164927e3","PK":false,"name":"role","type":"string","children":[]},{"id":"13afc87b-28b5-47bc-bdc9-6648672483b9","PK":false,"name":"read","type":"bool","children":[]},{"id":"00c3f941-6355-4745-969e-e57d8102488d","PK":false,"name":"expired","type":"bool","children":[]}],"isCollapsed":false}],"x":1015,"y":228}],"relations":[],"selectedElementId":"a1f11df4-9469-4f4b-aa6d-86a22a7ac9de"} -------------------------------------------------------------------------------- /e2e/add-new-collection.spec.ts: -------------------------------------------------------------------------------- 1 | import { test, expect } from '@playwright/test'; 2 | 3 | test('opens MongoDB Designer, adds collection, and checks "New Collection" visibility', async ({ 4 | page, 5 | }) => { 6 | await page.goto(''); 7 | 8 | await page.getByRole('link', { name: 'Launch MongoDB Designer' }).click(); 9 | await expect(page).toHaveURL('http://localhost:5173/editor.html'); 10 | 11 | const newButton = page.getByRole('button', { name: 'New' }); 12 | await expect(newButton).toBeVisible(); 13 | await newButton.click(); 14 | 15 | const addCollectionButton = page 16 | .getByRole('button', { name: 'Add Collection' }) 17 | .first(); 18 | await expect(addCollectionButton).toBeVisible(); 19 | await addCollectionButton.click(); 20 | 21 | const applyButton = page.getByRole('button', { name: 'Apply' }); 22 | await expect(applyButton).toBeVisible(); 23 | await expect(applyButton).toBeEnabled(); 24 | await applyButton.click(); 25 | 26 | const newCollectionText = page.locator('svg g text', { 27 | hasText: 'New Collection', 28 | }); 29 | await expect(newCollectionText).toBeVisible(); 30 | }); 31 | -------------------------------------------------------------------------------- /e2e/launch-mongodb-designer-link.spec.ts: -------------------------------------------------------------------------------- 1 | import { test, expect } from '@playwright/test'; 2 | 3 | test('navigates to and verifies MongoDB Designer URL', async ({ page }) => { 4 | await page.goto(''); 5 | 6 | await page.getByRole('link', { name: 'Launch MongoDB Designer' }).click(); 7 | await expect(page).toHaveURL('http://localhost:5173/editor.html'); 8 | }); 9 | -------------------------------------------------------------------------------- /editor.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 9 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | Mongo Modeler - Community Preview 29 | 30 | 31 |
32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /landing/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lemoncode/mongo-modeler/93a6a4441c89d87f6178b66a42c349eb29373627/landing/favicon.png -------------------------------------------------------------------------------- /landing/favicon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /media/mongo-modeler.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lemoncode/mongo-modeler/93a6a4441c89d87f6178b66a42c349eb29373627/media/mongo-modeler.jpg -------------------------------------------------------------------------------- /playwright.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig, devices } from '@playwright/test'; 2 | 3 | const BASE_URL = 'http://localhost:5173/'; 4 | 5 | export default defineConfig({ 6 | testDir: './e2e', 7 | fullyParallel: true, 8 | forbidOnly: !!process.env.CI, 9 | retries: process.env.CI ? 2 : 0, 10 | workers: process.env.CI ? 1 : undefined, 11 | reporter: 'html', 12 | use: { 13 | baseURL: BASE_URL, 14 | trace: 'on-first-retry', 15 | }, 16 | 17 | /* Configure projects for major browsers */ 18 | projects: [ 19 | { 20 | name: 'chromium', 21 | use: { ...devices['Desktop Chrome'] }, 22 | }, 23 | 24 | { 25 | name: 'firefox', 26 | use: { ...devices['Desktop Firefox'] }, 27 | }, 28 | 29 | /* Test against mobile viewports. */ 30 | // { 31 | // name: 'Mobile Chrome', 32 | // use: { ...devices['Pixel 5'] }, 33 | // }, 34 | // { 35 | // name: 'Mobile Safari', 36 | // use: { ...devices['iPhone 12'] }, 37 | // }, 38 | 39 | /* Test against branded browsers. */ 40 | // { 41 | // name: 'Microsoft Edge', 42 | // use: { ...devices['Desktop Edge'], channel: 'msedge' }, 43 | // }, 44 | // { 45 | // name: 'Google Chrome', 46 | // use: { ...devices['Desktop Chrome'], channel: 'chrome' }, 47 | // }, 48 | ], 49 | /* Run your local dev server before starting the tests */ 50 | webServer: { 51 | command: 'npm run dev', 52 | url: BASE_URL, 53 | reuseExistingServer: !process.env.CI, 54 | }, 55 | }); 56 | -------------------------------------------------------------------------------- /public/android-chrome-128x128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lemoncode/mongo-modeler/93a6a4441c89d87f6178b66a42c349eb29373627/public/android-chrome-128x128.png -------------------------------------------------------------------------------- /public/android-chrome-144x144.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lemoncode/mongo-modeler/93a6a4441c89d87f6178b66a42c349eb29373627/public/android-chrome-144x144.png -------------------------------------------------------------------------------- /public/android-chrome-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lemoncode/mongo-modeler/93a6a4441c89d87f6178b66a42c349eb29373627/public/android-chrome-192x192.png -------------------------------------------------------------------------------- /public/android-chrome-512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lemoncode/mongo-modeler/93a6a4441c89d87f6178b66a42c349eb29373627/public/android-chrome-512x512.png -------------------------------------------------------------------------------- /public/android-chrome-72x72.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lemoncode/mongo-modeler/93a6a4441c89d87f6178b66a42c349eb29373627/public/android-chrome-72x72.png -------------------------------------------------------------------------------- /public/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lemoncode/mongo-modeler/93a6a4441c89d87f6178b66a42c349eb29373627/public/apple-touch-icon.png -------------------------------------------------------------------------------- /public/assets/abel-de-tena.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lemoncode/mongo-modeler/93a6a4441c89d87f6178b66a42c349eb29373627/public/assets/abel-de-tena.jpeg -------------------------------------------------------------------------------- /public/assets/alberto-santiago.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lemoncode/mongo-modeler/93a6a4441c89d87f6178b66a42c349eb29373627/public/assets/alberto-santiago.png -------------------------------------------------------------------------------- /public/assets/aridane-martin.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lemoncode/mongo-modeler/93a6a4441c89d87f6178b66a42c349eb29373627/public/assets/aridane-martin.jpg -------------------------------------------------------------------------------- /public/assets/cristina-gonzalez.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lemoncode/mongo-modeler/93a6a4441c89d87f6178b66a42c349eb29373627/public/assets/cristina-gonzalez.jpg -------------------------------------------------------------------------------- /public/assets/fran-lopez.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lemoncode/mongo-modeler/93a6a4441c89d87f6178b66a42c349eb29373627/public/assets/fran-lopez.jpg -------------------------------------------------------------------------------- /public/assets/leticia-de-la-osa.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lemoncode/mongo-modeler/93a6a4441c89d87f6178b66a42c349eb29373627/public/assets/leticia-de-la-osa.jpeg -------------------------------------------------------------------------------- /public/assets/manuel-gallego-barra.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lemoncode/mongo-modeler/93a6a4441c89d87f6178b66a42c349eb29373627/public/assets/manuel-gallego-barra.jpeg -------------------------------------------------------------------------------- /public/assets/marcos-apocada.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lemoncode/mongo-modeler/93a6a4441c89d87f6178b66a42c349eb29373627/public/assets/marcos-apocada.jpeg -------------------------------------------------------------------------------- /public/assets/miguel-galvez.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lemoncode/mongo-modeler/93a6a4441c89d87f6178b66a42c349eb29373627/public/assets/miguel-galvez.jpg -------------------------------------------------------------------------------- /public/assets/teresa-milanes.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lemoncode/mongo-modeler/93a6a4441c89d87f6178b66a42c349eb29373627/public/assets/teresa-milanes.jpeg -------------------------------------------------------------------------------- /public/assets/tony-torres.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lemoncode/mongo-modeler/93a6a4441c89d87f6178b66a42c349eb29373627/public/assets/tony-torres.jpeg -------------------------------------------------------------------------------- /public/assets/veronica-camarzana.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lemoncode/mongo-modeler/93a6a4441c89d87f6178b66a42c349eb29373627/public/assets/veronica-camarzana.jpeg -------------------------------------------------------------------------------- /public/browserconfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | #da532c 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /public/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lemoncode/mongo-modeler/93a6a4441c89d87f6178b66a42c349eb29373627/public/favicon-16x16.png -------------------------------------------------------------------------------- /public/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lemoncode/mongo-modeler/93a6a4441c89d87f6178b66a42c349eb29373627/public/favicon-32x32.png -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lemoncode/mongo-modeler/93a6a4441c89d87f6178b66a42c349eb29373627/public/favicon.ico -------------------------------------------------------------------------------- /public/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lemoncode/mongo-modeler/93a6a4441c89d87f6178b66a42c349eb29373627/public/favicon.png -------------------------------------------------------------------------------- /public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "lang": "en", 3 | "dir": "ltr", 4 | "name": "Mongo Modeler", 5 | "description": "A free, online Data Modeling tool for MongoDB", 6 | "start_url": "./editor.html", 7 | "display_override": ["minimal-ui", "fullscreen"], 8 | "display": "standalone", 9 | "icons": [ 10 | { 11 | "src": "/android-chrome-512x512.png", 12 | "sizes": "512x512", 13 | "type": "image/png", 14 | "purpose": "maskable" 15 | }, 16 | { 17 | "src": "/android-chrome-192x192.png", 18 | "sizes": "192x192", 19 | "type": "image/png" 20 | }, 21 | { 22 | "src": "/android-chrome-144x144.png", 23 | "sizes": "144x144", 24 | "type": "image/png" 25 | }, 26 | { 27 | "src": "/android-chrome-128x128.png", 28 | "sizes": "128x128", 29 | "type": "image/png" 30 | }, 31 | { 32 | "src": "/android-chrome-72x72.png", 33 | "sizes": "72x72", 34 | "type": "image/png" 35 | } 36 | ], 37 | "background_color": "#455a6c", 38 | "theme_color": "#455a6c" 39 | } 40 | -------------------------------------------------------------------------------- /public/mongo-modeler-app.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lemoncode/mongo-modeler/93a6a4441c89d87f6178b66a42c349eb29373627/public/mongo-modeler-app.jpg -------------------------------------------------------------------------------- /public/mstile-150x150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lemoncode/mongo-modeler/93a6a4441c89d87f6178b66a42c349eb29373627/public/mstile-150x150.png -------------------------------------------------------------------------------- /src/App.tsx: -------------------------------------------------------------------------------- 1 | import { MainScene } from '@/scenes'; 2 | import { 3 | CanvasSchemaProvider, 4 | CanvasViewSettingsProvider, 5 | ModalDialogProvider, 6 | useThemeContext, 7 | } from './core/providers'; 8 | 9 | function App() { 10 | const { theme } = useThemeContext(); 11 | 12 | return ( 13 | 14 | 15 | 16 |
17 | 18 |
19 |
20 |
21 |
22 | ); 23 | } 24 | 25 | export default App; 26 | -------------------------------------------------------------------------------- /src/common/a11y/click-outside.hook.ts: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | export const useClickOutside = ( 4 | isOpen: boolean, 5 | ref: React.RefObject, 6 | callback: (e: MouseEvent) => void 7 | ) => { 8 | const handleClickOutside = (e: MouseEvent) => { 9 | callback(e); 10 | }; 11 | 12 | React.useEffect(() => { 13 | ref.current?.addEventListener('click', handleClickOutside); 14 | 15 | return () => { 16 | ref.current?.removeEventListener('click', handleClickOutside); 17 | }; 18 | }, [isOpen]); 19 | }; 20 | -------------------------------------------------------------------------------- /src/common/a11y/common.model.ts: -------------------------------------------------------------------------------- 1 | export type BaseA11yOption