├── .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 |
--------------------------------------------------------------------------------
/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