@team-codeme/crud-forge 0.0.0-stage → 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.cursor/agents/generator-engineer.md +31 -0
- package/.cursor/agents/keycloak-engineer.md +33 -0
- package/.cursor/agents/qa-engineer.md +32 -0
- package/.cursor/agents/security-reviewer.md +30 -0
- package/.cursor/mcp.json +13 -0
- package/.cursor/rules/crudforge-precautions.mdc +16 -0
- package/.cursor/rules/playwright-browser.mdc +30 -0
- package/.cursor/rules/readme-todo-sync.mdc +13 -0
- package/.env.qa.example +19 -0
- package/.github/workflows/qa-live.yml +32 -0
- package/.github/workflows/qa.yml +27 -0
- package/.vscode/settings.json +32 -0
- package/QA/IAM-PLAN.md +25 -0
- package/QA/IAM-RESULTS.md +39 -0
- package/QA/IAM-TESTCASES.md +36 -0
- package/QA/IAM-TODO.md +7 -0
- package/QA/KEYCLOAK-BOOTSTRAP.md +105 -0
- package/QA/PLAN.md +43 -0
- package/QA/RESULTS.md +59 -0
- package/QA/TESTCASES.md +65 -0
- package/QA/TODO.md +14 -0
- package/QA/pmb-dev/README.md +49 -0
- package/QA/pmb-dev/config/config.yml +152 -0
- package/QA/pmb-dev/gdl/i.gdl +17 -0
- package/README.md +851 -2
- package/Todo.md +207 -0
- package/assets/branding/crudforge-logo.png +0 -0
- package/assets/branding/crudforge-mark.png +0 -0
- package/branding/poster-crudforge.jpg +0 -0
- package/chat/last-chat/Investigating Mock Data Configuration.md +428 -0
- package/cli.js +167 -0
- package/config/default-config.yml +245 -0
- package/docs/performance/README.md +217 -0
- package/docs/performance/after.json +111 -0
- package/docs/performance/before.json +111 -0
- package/docs/quality/README.md +276 -0
- package/e2e/crudforge.e2e.yml +47 -0
- package/e2e/crudforge.field-profile.yml +33 -0
- package/e2e/crudforge.iam-live.yml +124 -0
- package/e2e/crudforge.iam.yml +62 -0
- package/e2e/tests/field-profile.spec.js +152 -0
- package/e2e/tests/generated-crud.spec.js +251 -0
- package/e2e/tests/iam-live.spec.js +149 -0
- package/e2e/tests/iam-pack.spec.js +151 -0
- package/e2e/tests/list-state.spec.js +73 -0
- package/features.csv +27 -0
- package/fuse-starter-pack/branding/crudforge-mark-source.jpg +0 -0
- package/fuse-starter-pack/branding/crudforge-mark-source.png +0 -0
- package/fuse-starter-pack/branding/crudforge-mark.png +0 -0
- package/fuse-starter-pack/branding/crudforge-wordmark-source.jpg +0 -0
- package/fuse-starter-pack/branding/crudforge-wordmark-source.png +0 -0
- package/fuse-starter-pack/branding/crudforge-wordmark.png +0 -0
- package/fuse-starter-pack/fuse-v21.1/Dockerfile +14 -0
- package/fuse-starter-pack/fuse-v21.1/LICENSE.md +6 -0
- package/fuse-starter-pack/fuse-v21.1/README.md +59 -0
- package/fuse-starter-pack/fuse-v21.1/angular.json +113 -0
- package/fuse-starter-pack/fuse-v21.1/eslint.config.ts +150 -0
- package/fuse-starter-pack/fuse-v21.1/nginx.conf +23 -0
- package/fuse-starter-pack/fuse-v21.1/nginx.dev.conf +18 -0
- package/fuse-starter-pack/fuse-v21.1/package-lock.json +11513 -0
- package/fuse-starter-pack/fuse-v21.1/package.json +69 -0
- package/fuse-starter-pack/fuse-v21.1/postcss.config.json +5 -0
- package/fuse-starter-pack/fuse-v21.1/prettier.config.ts +15 -0
- package/fuse-starter-pack/fuse-v21.1/proxy.conf.json +8 -0
- package/fuse-starter-pack/fuse-v21.1/proxy.dev.conf.json +8 -0
- package/fuse-starter-pack/fuse-v21.1/public/favicon.png +0 -0
- package/fuse-starter-pack/fuse-v21.1/public/fonts/geist/Geist-Italic.woff2 +0 -0
- package/fuse-starter-pack/fuse-v21.1/public/fonts/geist/Geist.woff2 +0 -0
- package/fuse-starter-pack/fuse-v21.1/public/fonts/geist/GeistMono-Italic.woff2 +0 -0
- package/fuse-starter-pack/fuse-v21.1/public/fonts/geist/GeistMono.woff2 +0 -0
- package/fuse-starter-pack/fuse-v21.1/public/i18n/en.json +8 -0
- package/fuse-starter-pack/fuse-v21.1/public/i18n/es.json +8 -0
- package/fuse-starter-pack/fuse-v21.1/public/images/flags/ES.svg +79 -0
- package/fuse-starter-pack/fuse-v21.1/public/images/flags/US.svg +14 -0
- package/fuse-starter-pack/fuse-v21.1/public/images/flags/where-to-find-other-flags.txt +5 -0
- package/fuse-starter-pack/fuse-v21.1/public/images/logo/logo-mark.png +0 -0
- package/fuse-starter-pack/fuse-v21.1/public/images/logo/logo.png +0 -0
- package/fuse-starter-pack/fuse-v21.1/push.sh +27 -0
- package/fuse-starter-pack/fuse-v21.1/src/app/app.config.server.ts +10 -0
- package/fuse-starter-pack/fuse-v21.1/src/app/app.config.ts +64 -0
- package/fuse-starter-pack/fuse-v21.1/src/app/app.routes.server.ts +8 -0
- package/fuse-starter-pack/fuse-v21.1/src/app/app.routes.ts +39 -0
- package/fuse-starter-pack/fuse-v21.1/src/app/app.ts +22 -0
- package/fuse-starter-pack/fuse-v21.1/src/app/core/icons/index.ts +1 -0
- package/fuse-starter-pack/fuse-v21.1/src/app/core/icons/lucide.ts +1 -0
- package/fuse-starter-pack/fuse-v21.1/src/app/core/icons/provider.ts +23 -0
- package/fuse-starter-pack/fuse-v21.1/src/app/core/local-storage/index.ts +2 -0
- package/fuse-starter-pack/fuse-v21.1/src/app/core/local-storage/local-storage.ts +109 -0
- package/fuse-starter-pack/fuse-v21.1/src/app/core/local-storage/provider.ts +15 -0
- package/fuse-starter-pack/fuse-v21.1/src/app/core/media/index.ts +2 -0
- package/fuse-starter-pack/fuse-v21.1/src/app/core/media/media.ts +64 -0
- package/fuse-starter-pack/fuse-v21.1/src/app/core/media/provider.ts +15 -0
- package/fuse-starter-pack/fuse-v21.1/src/app/core/theming/index.ts +3 -0
- package/fuse-starter-pack/fuse-v21.1/src/app/core/theming/models/theming.ts +13 -0
- package/fuse-starter-pack/fuse-v21.1/src/app/core/theming/palette.ts +209 -0
- package/fuse-starter-pack/fuse-v21.1/src/app/core/theming/provider.ts +24 -0
- package/fuse-starter-pack/fuse-v21.1/src/app/core/theming/theming.ts +129 -0
- package/fuse-starter-pack/fuse-v21.1/src/app/core/transloco/transloco-http-loader.ts +12 -0
- package/fuse-starter-pack/fuse-v21.1/src/app/domains/admin/layout/data/navigation.ts +176 -0
- package/fuse-starter-pack/fuse-v21.1/src/app/domains/admin/layout/layout.ts +77 -0
- package/fuse-starter-pack/fuse-v21.1/src/app/domains/admin/layout/ui/language-switcher.ts +91 -0
- package/fuse-starter-pack/fuse-v21.1/src/app/domains/admin/layout/ui/navigation.ts +238 -0
- package/fuse-starter-pack/fuse-v21.1/src/app/domains/admin/layout/ui/notifications.ts +252 -0
- package/fuse-starter-pack/fuse-v21.1/src/app/domains/admin/layout/ui/scheme-switcher.ts +58 -0
- package/fuse-starter-pack/fuse-v21.1/src/app/domains/admin/layout/ui/sidebar.ts +31 -0
- package/fuse-starter-pack/fuse-v21.1/src/app/domains/admin/layout/ui/user.ts +132 -0
- package/fuse-starter-pack/fuse-v21.1/src/app/domains/admin/modules/apps/academy/data/academy.ts +753 -0
- package/fuse-starter-pack/fuse-v21.1/src/app/domains/admin/modules/apps/academy/data/model.ts +27 -0
- package/fuse-starter-pack/fuse-v21.1/src/app/domains/admin/modules/apps/academy/features/course.ts +318 -0
- package/fuse-starter-pack/fuse-v21.1/src/app/domains/admin/modules/apps/academy/features/courses.ts +228 -0
- package/fuse-starter-pack/fuse-v21.1/src/app/domains/admin/modules/apps/academy/routes.ts +14 -0
- package/fuse-starter-pack/fuse-v21.1/src/app/domains/admin/modules/apps/contacts/data/contacts.ts +4372 -0
- package/fuse-starter-pack/fuse-v21.1/src/app/domains/admin/modules/apps/contacts/data/model.ts +34 -0
- package/fuse-starter-pack/fuse-v21.1/src/app/domains/admin/modules/apps/contacts/features/contact.ts +239 -0
- package/fuse-starter-pack/fuse-v21.1/src/app/domains/admin/modules/apps/contacts/features/contacts.ts +185 -0
- package/fuse-starter-pack/fuse-v21.1/src/app/domains/admin/modules/apps/contacts/routes.ts +16 -0
- package/fuse-starter-pack/fuse-v21.1/src/app/domains/admin/modules/apps/file-manager/data/file-manager.ts +261 -0
- package/fuse-starter-pack/fuse-v21.1/src/app/domains/admin/modules/apps/file-manager/data/model.ts +12 -0
- package/fuse-starter-pack/fuse-v21.1/src/app/domains/admin/modules/apps/file-manager/features/file-manager.ts +131 -0
- package/fuse-starter-pack/fuse-v21.1/src/app/domains/admin/modules/apps/file-manager/routes.ts +15 -0
- package/fuse-starter-pack/fuse-v21.1/src/app/domains/admin/modules/apps/file-manager/ui/list.ts +164 -0
- package/fuse-starter-pack/fuse-v21.1/src/app/domains/admin/modules/apps/help-center/features/faq.ts +288 -0
- package/fuse-starter-pack/fuse-v21.1/src/app/domains/admin/modules/apps/help-center/features/guide.ts +134 -0
- package/fuse-starter-pack/fuse-v21.1/src/app/domains/admin/modules/apps/help-center/features/home.ts +219 -0
- package/fuse-starter-pack/fuse-v21.1/src/app/domains/admin/modules/apps/help-center/features/support.ts +161 -0
- package/fuse-starter-pack/fuse-v21.1/src/app/domains/admin/modules/apps/help-center/routes.ts +33 -0
- package/fuse-starter-pack/fuse-v21.1/src/app/domains/admin/modules/apps/notes/data/model.ts +18 -0
- package/fuse-starter-pack/fuse-v21.1/src/app/domains/admin/modules/apps/notes/data/notes.ts +324 -0
- package/fuse-starter-pack/fuse-v21.1/src/app/domains/admin/modules/apps/notes/features/note.ts +152 -0
- package/fuse-starter-pack/fuse-v21.1/src/app/domains/admin/modules/apps/notes/features/notes.ts +118 -0
- package/fuse-starter-pack/fuse-v21.1/src/app/domains/admin/modules/apps/notes/routes.ts +16 -0
- package/fuse-starter-pack/fuse-v21.1/src/app/domains/admin/modules/apps/tasks/data/model.ts +17 -0
- package/fuse-starter-pack/fuse-v21.1/src/app/domains/admin/modules/apps/tasks/data/tasks.ts +562 -0
- package/fuse-starter-pack/fuse-v21.1/src/app/domains/admin/modules/apps/tasks/features/task.ts +195 -0
- package/fuse-starter-pack/fuse-v21.1/src/app/domains/admin/modules/apps/tasks/features/tasks.ts +271 -0
- package/fuse-starter-pack/fuse-v21.1/src/app/domains/admin/modules/apps/tasks/routes.ts +16 -0
- package/fuse-starter-pack/fuse-v21.1/src/app/domains/admin/modules/dashboards/data/analytics.ts +1620 -0
- package/fuse-starter-pack/fuse-v21.1/src/app/domains/admin/modules/dashboards/data/finance.ts +1065 -0
- package/fuse-starter-pack/fuse-v21.1/src/app/domains/admin/modules/dashboards/data/project.ts +376 -0
- package/fuse-starter-pack/fuse-v21.1/src/app/domains/admin/modules/dashboards/features/analytics/analytics.ts +1096 -0
- package/fuse-starter-pack/fuse-v21.1/src/app/domains/admin/modules/dashboards/features/finance/finance.ts +658 -0
- package/fuse-starter-pack/fuse-v21.1/src/app/domains/admin/modules/dashboards/features/project/budget-table.ts +188 -0
- package/fuse-starter-pack/fuse-v21.1/src/app/domains/admin/modules/dashboards/features/project/project.ts +565 -0
- package/fuse-starter-pack/fuse-v21.1/src/app/domains/admin/modules/dashboards/routes.ts +23 -0
- package/fuse-starter-pack/fuse-v21.1/src/app/domains/admin/modules/documentation/features/changelog/changelog.ts +932 -0
- package/fuse-starter-pack/fuse-v21.1/src/app/domains/admin/modules/documentation/features/getting-started/building.ts +33 -0
- package/fuse-starter-pack/fuse-v21.1/src/app/domains/admin/modules/documentation/features/getting-started/development.ts +42 -0
- package/fuse-starter-pack/fuse-v21.1/src/app/domains/admin/modules/documentation/features/getting-started/installation.ts +47 -0
- package/fuse-starter-pack/fuse-v21.1/src/app/domains/admin/modules/documentation/layout.ts +9 -0
- package/fuse-starter-pack/fuse-v21.1/src/app/domains/admin/modules/documentation/routes.ts +45 -0
- package/fuse-starter-pack/fuse-v21.1/src/app/domains/admin/modules/extras/error/features/error-page.ts +70 -0
- package/fuse-starter-pack/fuse-v21.1/src/app/domains/admin/modules/extras/error/routes.ts +21 -0
- package/fuse-starter-pack/fuse-v21.1/src/app/domains/admin/modules/extras/notifications/features/notifications.ts +262 -0
- package/fuse-starter-pack/fuse-v21.1/src/app/domains/admin/modules/extras/notifications/routes.ts +10 -0
- package/fuse-starter-pack/fuse-v21.1/src/app/domains/admin/modules/extras/settings/features/account.ts +238 -0
- package/fuse-starter-pack/fuse-v21.1/src/app/domains/admin/modules/extras/settings/features/notifications.ts +134 -0
- package/fuse-starter-pack/fuse-v21.1/src/app/domains/admin/modules/extras/settings/features/plan-and-billing.ts +238 -0
- package/fuse-starter-pack/fuse-v21.1/src/app/domains/admin/modules/extras/settings/features/security.ts +211 -0
- package/fuse-starter-pack/fuse-v21.1/src/app/domains/admin/modules/extras/settings/features/team.ts +188 -0
- package/fuse-starter-pack/fuse-v21.1/src/app/domains/admin/modules/extras/settings/layout.ts +109 -0
- package/fuse-starter-pack/fuse-v21.1/src/app/domains/admin/modules/extras/settings/routes.ts +37 -0
- package/fuse-starter-pack/fuse-v21.1/src/app/domains/admin/modules/extras/welcome/welcome.component.ts +22 -0
- package/fuse-starter-pack/fuse-v21.1/src/app/domains/admin/routes.ts +95 -0
- package/fuse-starter-pack/fuse-v21.1/src/app/domains/auth/features/forgot-password/forgot-password.html +54 -0
- package/fuse-starter-pack/fuse-v21.1/src/app/domains/auth/features/forgot-password/forgot-password.ts +51 -0
- package/fuse-starter-pack/fuse-v21.1/src/app/domains/auth/features/reset-password/reset-password.html +82 -0
- package/fuse-starter-pack/fuse-v21.1/src/app/domains/auth/features/reset-password/reset-password.ts +69 -0
- package/fuse-starter-pack/fuse-v21.1/src/app/domains/auth/features/sign-in/sign-in.html +132 -0
- package/fuse-starter-pack/fuse-v21.1/src/app/domains/auth/features/sign-in/sign-in.ts +54 -0
- package/fuse-starter-pack/fuse-v21.1/src/app/domains/auth/features/sign-up/sign-up.html +183 -0
- package/fuse-starter-pack/fuse-v21.1/src/app/domains/auth/features/sign-up/sign-up.ts +56 -0
- package/fuse-starter-pack/fuse-v21.1/src/app/domains/auth/layout.ts +9 -0
- package/fuse-starter-pack/fuse-v21.1/src/app/domains/auth/routes.ts +34 -0
- package/fuse-starter-pack/fuse-v21.1/src/app/domains/coming-soon/features/coming-soon.ts +156 -0
- package/fuse-starter-pack/fuse-v21.1/src/app/domains/coming-soon/layout.ts +9 -0
- package/fuse-starter-pack/fuse-v21.1/src/app/domains/coming-soon/routes.ts +16 -0
- package/fuse-starter-pack/fuse-v21.1/src/app/domains/website/layout/layout.ts +9 -0
- package/fuse-starter-pack/fuse-v21.1/src/app/domains/website/modules/home/features/home.ts +23 -0
- package/fuse-starter-pack/fuse-v21.1/src/app/domains/website/modules/home/routes.ts +10 -0
- package/fuse-starter-pack/fuse-v21.1/src/app/domains/website/routes.ts +30 -0
- package/fuse-starter-pack/fuse-v21.1/src/environments/environment.mock.ts +5 -0
- package/fuse-starter-pack/fuse-v21.1/src/environments/environment.prod.ts +5 -0
- package/fuse-starter-pack/fuse-v21.1/src/environments/environment.ts +5 -0
- package/fuse-starter-pack/fuse-v21.1/src/index.html +66 -0
- package/fuse-starter-pack/fuse-v21.1/src/main.server.ts +11 -0
- package/fuse-starter-pack/fuse-v21.1/src/main.ts +5 -0
- package/fuse-starter-pack/fuse-v21.1/src/server.ts +70 -0
- package/fuse-starter-pack/fuse-v21.1/src/styles/base/base.css +63 -0
- package/fuse-starter-pack/fuse-v21.1/src/styles/base/typography.css +54 -0
- package/fuse-starter-pack/fuse-v21.1/src/styles/components/a.css +18 -0
- package/fuse-starter-pack/fuse-v21.1/src/styles/components/input.css +22 -0
- package/fuse-starter-pack/fuse-v21.1/src/styles/components/kbd.css +55 -0
- package/fuse-starter-pack/fuse-v21.1/src/styles/components/material.css +1149 -0
- package/fuse-starter-pack/fuse-v21.1/src/styles/styles.css +31 -0
- package/fuse-starter-pack/fuse-v21.1/src/styles/tailwind/theme.css +147 -0
- package/fuse-starter-pack/fuse-v21.1/src/styles/tailwind/utilities.css +563 -0
- package/fuse-starter-pack/fuse-v21.1/src/styles/tailwind/variants.css +4 -0
- package/fuse-starter-pack/fuse-v21.1/src/styles/third-party/lucide-icons.css +12 -0
- package/fuse-starter-pack/fuse-v21.1/tsconfig.app.json +16 -0
- package/fuse-starter-pack/fuse-v21.1/tsconfig.json +37 -0
- package/fuse-starter-pack/fuse-v21.1/tsconfig.spec.json +10 -0
- package/generator/README.md +12 -0
- package/generator/issues/.gitkeep +0 -0
- package/package.json +56 -4
- package/playwright.config.js +29 -0
- package/playwright.field-profile.config.js +6 -0
- package/playwright.iam-live.config.js +31 -0
- package/playwright.iam.config.js +29 -0
- package/playwright.list-state.config.js +6 -0
- package/playwright.performance.config.js +1 -0
- package/run-config-tests.sh +5 -0
- package/scripts/e2e-paths.js +89 -0
- package/scripts/e2e-prepare-field-profile.js +17 -0
- package/scripts/e2e-prepare-iam-live.js +135 -0
- package/scripts/e2e-prepare-iam.js +65 -0
- package/scripts/e2e-prepare.js +72 -0
- package/scripts/e2e-serve-iam-live.js +28 -0
- package/scripts/e2e-serve-iam.js +28 -0
- package/scripts/e2e-serve.js +28 -0
- package/scripts/performance/generate.js +17 -0
- package/scripts/performance/measure.js +55 -0
- package/scripts/postinstall.js +9 -0
- package/scripts/prepare-quality-apps.js +34 -0
- package/scripts/run-config-tests.js +63 -0
- package/src/assets/logo-with-lable.jpeg +0 -0
- package/src/assets/logo.jpeg +0 -0
- package/src/commands/bootstrap.js +92 -0
- package/src/commands/doctor.js +403 -0
- package/src/commands/generate.js +301 -0
- package/src/commands/init-config.js +310 -0
- package/src/commands/keycloak-options.js +182 -0
- package/src/commands/validate.js +52 -0
- package/src/config/auth-config.js +183 -0
- package/src/config/default-values.js +235 -0
- package/src/config/env-refs.js +71 -0
- package/src/config/field-preferences.js +99 -0
- package/src/config/input-sources.js +104 -0
- package/src/config/load-config.js +166 -0
- package/src/config/proxy-routes.js +44 -0
- package/src/generator/access-control-tools.js +334 -0
- package/src/generator/ai-docs.js +691 -0
- package/src/generator/application-tests.js +252 -0
- package/src/generator/auth-pack.js +965 -0
- package/src/generator/embed-config.js +431 -0
- package/src/generator/entity-layout.js +30 -0
- package/src/generator/fuse-build.js +57 -0
- package/src/generator/fuse-runtime.js +344 -0
- package/src/generator/generated-banner.js +137 -0
- package/src/generator/index.js +874 -0
- package/src/generator/project-output.js +126 -0
- package/src/generator/team-pack.js +220 -0
- package/src/index.js +68 -0
- package/src/parser/gdl-parser.js +169 -0
- package/src/parser/jdl-parser.js +171 -0
- package/src/presets/pmb-test.js +139 -0
- package/src/presets/static-source.js +73 -0
- package/src/presets/store.js +96 -0
- package/src/provision/admin-service.js +148 -0
- package/src/provision/bootstrap.js +147 -0
- package/src/provision/http.js +123 -0
- package/src/provision/keycloak-admin-rest.js +335 -0
- package/src/provision/state.js +51 -0
- package/src/provision/token.js +52 -0
- package/src/templates/angular/auth/access-control.service.ts.ejs +179 -0
- package/src/templates/angular/auth/access-ctrl.pipe.ts.ejs +20 -0
- package/src/templates/angular/auth/auth.guard.ts.ejs +27 -0
- package/src/templates/angular/auth/auth.interceptor.ts.ejs +53 -0
- package/src/templates/angular/auth/auth.service.ts.ejs +594 -0
- package/src/templates/angular/auth/auth.utils.ts.ejs +28 -0
- package/src/templates/angular/auth/current-user.ts.ejs +24 -0
- package/src/templates/angular/auth/disabled-account-overlay.component.css.ejs +95 -0
- package/src/templates/angular/auth/disabled-account-overlay.component.html.ejs +33 -0
- package/src/templates/angular/auth/disabled-account-overlay.component.ts.ejs +23 -0
- package/src/templates/angular/auth/fuse-account.ts.ejs +234 -0
- package/src/templates/angular/auth/fuse-user.ts.ejs +264 -0
- package/src/templates/angular/auth/has-permission.directive.ts.ejs +51 -0
- package/src/templates/angular/auth/index.ts.ejs +24 -0
- package/src/templates/angular/auth/keycloak-admin.service.ts.ejs +670 -0
- package/src/templates/angular/auth/landing.guard.ts.ejs +61 -0
- package/src/templates/angular/auth/no-auth.guard.ts.ejs +19 -0
- package/src/templates/angular/auth/permission-attribute.util.ts.ejs +182 -0
- package/src/templates/angular/auth/sign-in.ts.ejs +60 -0
- package/src/templates/angular/entity/_entity_.model.ts.ejs +64 -0
- package/src/templates/angular/entity/_entity_.routes.ts.ejs +9 -0
- package/src/templates/angular/entity/components/forms/form/_entity_-form.component.html.ejs +168 -0
- package/src/templates/angular/entity/components/forms/form/_entity_-form.component.ts.ejs +175 -0
- package/src/templates/angular/entity/components/forms/form-page/_entity_-form-page.component.html.ejs +10 -0
- package/src/templates/angular/entity/components/forms/form-page/_entity_-form-page.component.ts.ejs +86 -0
- package/src/templates/angular/entity/components/forms/update/_entity_-form.service.ts.ejs +136 -0
- package/src/templates/angular/entity/components/interaction/actions/_entity_-actions.component.html.ejs +68 -0
- package/src/templates/angular/entity/components/interaction/actions/_entity_-actions.component.ts.ejs +69 -0
- package/src/templates/angular/entity/components/interaction/filter/_entity_-filter.component.html.ejs +111 -0
- package/src/templates/angular/entity/components/interaction/filter/_entity_-filter.component.ts.ejs +102 -0
- package/src/templates/angular/entity/components/presentation/card/_entity_-card.component.css.ejs +33 -0
- package/src/templates/angular/entity/components/presentation/card/_entity_-card.component.html.ejs +29 -0
- package/src/templates/angular/entity/components/presentation/card/_entity_-card.component.ts.ejs +93 -0
- package/src/templates/angular/entity/components/presentation/detail/_entity_-detail.component.css.ejs +54 -0
- package/src/templates/angular/entity/components/presentation/detail/_entity_-detail.component.html.ejs +58 -0
- package/src/templates/angular/entity/components/presentation/detail/_entity_-detail.component.ts.ejs +47 -0
- package/src/templates/angular/entity/components/presentation/list/_entity_-list.component.html.ejs +419 -0
- package/src/templates/angular/entity/components/presentation/list/_entity_-list.component.scss.ejs +48 -0
- package/src/templates/angular/entity/components/presentation/list/_entity_-list.component.ts.ejs +592 -0
- package/src/templates/angular/entity/service/_entity_.service.ts.ejs +153 -0
- package/src/templates/angular/entity/settings/_entity_.settings.ts.ejs +49 -0
- package/src/templates/angular/enums/_enum_.model.ts.ejs +11 -0
- package/src/templates/angular/iam/change-password.component.html.ejs +39 -0
- package/src/templates/angular/iam/change-password.component.ts.ejs +44 -0
- package/src/templates/angular/iam/no-access.component.ts.ejs +17 -0
- package/src/templates/angular/iam/role-list.component.html.ejs +331 -0
- package/src/templates/angular/iam/role-list.component.scss.ejs +107 -0
- package/src/templates/angular/iam/role-list.component.ts.ejs +597 -0
- package/src/templates/angular/iam/role-management/role-header.component.html.ejs +51 -0
- package/src/templates/angular/iam/role-management/role-header.component.ts.ejs +45 -0
- package/src/templates/angular/iam/role-management/role-inheritance.component.html.ejs +15 -0
- package/src/templates/angular/iam/role-management/role-inheritance.component.ts.ejs +19 -0
- package/src/templates/angular/iam/role-management/role-permissions-panel.component.css.ejs +24 -0
- package/src/templates/angular/iam/role-management/role-permissions-panel.component.html.ejs +108 -0
- package/src/templates/angular/iam/role-management/role-permissions-panel.component.ts.ejs +122 -0
- package/src/templates/angular/iam/role-management/role-users.component.html.ejs +104 -0
- package/src/templates/angular/iam/role-management/role-users.component.ts.ejs +53 -0
- package/src/templates/angular/iam/role-management/user-select-dialog.component.html.ejs +113 -0
- package/src/templates/angular/iam/role-management/user-select-dialog.component.ts.ejs +157 -0
- package/src/templates/angular/iam/role-permission-matrix.component.html.ejs +355 -0
- package/src/templates/angular/iam/role-permission-matrix.component.scss.ejs +217 -0
- package/src/templates/angular/iam/role-permission-matrix.component.ts.ejs +800 -0
- package/src/templates/angular/iam/screen-catalog.ts.ejs +147 -0
- package/src/templates/angular/iam/shared/confirm-dialog.component.ts.ejs +83 -0
- package/src/templates/angular/iam/shared/matrix-hierarchy.util.ts.ejs +196 -0
- package/src/templates/angular/iam/shared/permission-matrix-sound.ts.ejs +59 -0
- package/src/templates/angular/iam/shared/role-display.util.ts.ejs +43 -0
- package/src/templates/angular/iam/shared/role-permission-skeleton.component.ts.ejs +54 -0
- package/src/templates/angular/iam/shared/screen-matrix.util.ts.ejs +554 -0
- package/src/templates/angular/iam/shared/screen-navigation-map.ts.ejs +187 -0
- package/src/templates/angular/iam/shared/screen-navigation.registry.ts.ejs +64 -0
- package/src/templates/angular/iam/shared/text-highlight.pipe.ts.ejs +39 -0
- package/src/templates/angular/iam/user-access-matrix.component.html.ejs +212 -0
- package/src/templates/angular/iam/user-access-matrix.component.scss.ejs +34 -0
- package/src/templates/angular/iam/user-access-matrix.component.ts.ejs +239 -0
- package/src/templates/angular/iam/user-detail.component.html.ejs +143 -0
- package/src/templates/angular/iam/user-detail.component.ts.ejs +108 -0
- package/src/templates/angular/iam/user-form.component.html.ejs +63 -0
- package/src/templates/angular/iam/user-form.component.ts.ejs +100 -0
- package/src/templates/angular/iam/user-list.component.html.ejs +369 -0
- package/src/templates/angular/iam/user-list.component.scss.ejs +242 -0
- package/src/templates/angular/iam/user-list.component.ts.ejs +446 -0
- package/src/templates/angular/iam/user-management.routes.ts.ejs +47 -0
- package/src/templates/angular/iam/user-permission-matrix.component.html.ejs +231 -0
- package/src/templates/angular/iam/user-permission-matrix.component.scss.ejs +216 -0
- package/src/templates/angular/iam/user-permission-matrix.component.ts.ejs +516 -0
- package/src/templates/angular/shared/base/audit-user-name.pipe.ts.ejs +69 -0
- package/src/templates/angular/shared/base/base-filter.component.ts.ejs +245 -0
- package/src/templates/angular/shared/base/base-form.component.ts.ejs +109 -0
- package/src/templates/angular/shared/base/base-list.component.ts.ejs +507 -0
- package/src/templates/angular/shared/base/filter-types.ts.ejs +55 -0
- package/src/templates/angular/shared/base/input-format.directive.ts.ejs +47 -0
- package/src/templates/angular/shared/base/input-format.ts.ejs +15 -0
- package/src/templates/angular/shared/confirm-with-input-dialog.component.ts.ejs +91 -0
- package/src/templates/angular/shared/confirmation-dialog.component.ts.ejs +80 -0
- package/src/templates/angular/shared/list-styles.css.ejs +103 -0
- package/src/templates/angular/shared/loading-overlay.component.ts.ejs +24 -0
- package/src/templates/angular/shared/resizable.directive.ts.ejs +115 -0
- package/src/templates/angular/shared/snackbar-styles.css.ejs +11 -0
- package/src/templates/fuse-packs/access-control-tools/access-control-sync.js +819 -0
- package/src/templates/fuse-packs/access-control-tools/build-rename-map.js +67 -0
- package/src/templates/fuse-packs/access-control-tools/inject-qa-ids.js +14 -0
- package/src/templates/fuse-packs/access-control-tools/lib/hierarchy-scanner.js +628 -0
- package/src/templates/fuse-packs/access-control-tools/lib/hierarchy-scanner.test.js +323 -0
- package/src/templates/fuse-packs/access-control-tools/lib/html-scanner.js +362 -0
- package/src/templates/fuse-packs/access-control-tools/lib/id-rules.duplicate.test.js +136 -0
- package/src/templates/fuse-packs/access-control-tools/lib/id-rules.js +1095 -0
- package/src/templates/fuse-packs/access-control-tools/lib/ts-component-index.js +482 -0
- package/src/templates/fuse-packs/access-control-tools/output/.gitkeep +0 -0
- package/src/templates/fuse-packs/access-control-tools/run.sh +223 -0
- package/src/templates/fuse-packs/access-control-tools/scan-access-control.js +14 -0
- package/src/templates/fuse-packs/iam-assets/sound/apple-play.mp3 +0 -0
- package/src/templates/fuse-packs/iam-assets/sound/remove.mp3 +0 -0
- package/src/templates/generator/README.md +12 -0
- package/src/templates/testing/ci.cjs +45 -0
- package/src/templates/testing/mock.cjs +149 -0
- package/src/templates/testing/playwright.config.cjs +25 -0
- package/src/templates/testing/serve.cjs +22 -0
- package/src/templates/testing/smoke.spec.cjs +180 -0
- package/src/utils/branding.js +39 -0
- package/src/utils/colors.js +18 -0
- package/src/utils/diff.js +109 -0
- package/src/utils/merger.js +115 -0
- package/src/validator/backend-diagnostics.js +30 -0
- package/src/validator/blueprint-validator.js +276 -0
- package/src/validator/diagnostics.js +608 -0
- package/src/validator/pattern.js +28 -0
- package/test/auth-interceptor.js +84 -0
- package/test/auth-provision-checks.js +297 -0
- package/test/field-preferences.js +145 -0
- package/test/fixtures/field-profile.gdl +7 -0
- package/test/fixtures/mock.jdl +17 -0
- package/test/fixtures/mock.png +0 -0
- package/test/fixtures/performance/config.yml +33 -0
- package/test/fixtures/performance/large.gdl +199 -0
- package/test/fixtures/performance/small.gdl +7 -0
- package/test/fixtures/quality/custom.yml +22 -0
- package/test/fixtures/quality/go-duck.yml +22 -0
- package/test/fixtures/quality/jhipster.yml +30 -0
- package/test/fixtures/quality/representative.gdl +14 -0
- package/test/list-state.js +138 -0
- package/test/micro-functions-layout.js +95 -0
- package/test/performance-generation.js +32 -0
- package/test/pmb-preset.js +127 -0
- package/test/project-workflow.js +111 -0
- package/test/quality-features.js +250 -0
- package/test/verify-commands.js +83 -0
- package/test/verify.js +959 -0
- package/test-files/GDL/example.gdl +15 -0
- package/test-files/JDL/example.jdl +15 -0
- package/test-files/config/crudforge.config.yml +127 -0
- package/test-run.sh +272 -0
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
@Audited
|
|
2
|
+
entity Province {
|
|
3
|
+
string index
|
|
4
|
+
string provinceCode
|
|
5
|
+
string provinceName
|
|
6
|
+
bool isActive
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
@Audited
|
|
10
|
+
entity Catalog01 {
|
|
11
|
+
string code
|
|
12
|
+
string name
|
|
13
|
+
int quantity
|
|
14
|
+
bool isActive
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
@Audited
|
|
18
|
+
entity Catalog02 {
|
|
19
|
+
string code
|
|
20
|
+
string name
|
|
21
|
+
int quantity
|
|
22
|
+
bool isActive
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
@Audited
|
|
26
|
+
entity Catalog03 {
|
|
27
|
+
string code
|
|
28
|
+
string name
|
|
29
|
+
int quantity
|
|
30
|
+
bool isActive
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
@Audited
|
|
34
|
+
entity Catalog04 {
|
|
35
|
+
string code
|
|
36
|
+
string name
|
|
37
|
+
int quantity
|
|
38
|
+
bool isActive
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
@Audited
|
|
42
|
+
entity Catalog05 {
|
|
43
|
+
string code
|
|
44
|
+
string name
|
|
45
|
+
int quantity
|
|
46
|
+
bool isActive
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
@Audited
|
|
50
|
+
entity Catalog06 {
|
|
51
|
+
string code
|
|
52
|
+
string name
|
|
53
|
+
int quantity
|
|
54
|
+
bool isActive
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
@Audited
|
|
58
|
+
entity Catalog07 {
|
|
59
|
+
string code
|
|
60
|
+
string name
|
|
61
|
+
int quantity
|
|
62
|
+
bool isActive
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
@Audited
|
|
66
|
+
entity Catalog08 {
|
|
67
|
+
string code
|
|
68
|
+
string name
|
|
69
|
+
int quantity
|
|
70
|
+
bool isActive
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
@Audited
|
|
74
|
+
entity Catalog09 {
|
|
75
|
+
string code
|
|
76
|
+
string name
|
|
77
|
+
int quantity
|
|
78
|
+
bool isActive
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
@Audited
|
|
82
|
+
entity Catalog10 {
|
|
83
|
+
string code
|
|
84
|
+
string name
|
|
85
|
+
int quantity
|
|
86
|
+
bool isActive
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
@Audited
|
|
90
|
+
entity Catalog11 {
|
|
91
|
+
string code
|
|
92
|
+
string name
|
|
93
|
+
int quantity
|
|
94
|
+
bool isActive
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
@Audited
|
|
98
|
+
entity Catalog12 {
|
|
99
|
+
string code
|
|
100
|
+
string name
|
|
101
|
+
int quantity
|
|
102
|
+
bool isActive
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
@Audited
|
|
106
|
+
entity Catalog13 {
|
|
107
|
+
string code
|
|
108
|
+
string name
|
|
109
|
+
int quantity
|
|
110
|
+
bool isActive
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
@Audited
|
|
114
|
+
entity Catalog14 {
|
|
115
|
+
string code
|
|
116
|
+
string name
|
|
117
|
+
int quantity
|
|
118
|
+
bool isActive
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
@Audited
|
|
122
|
+
entity Catalog15 {
|
|
123
|
+
string code
|
|
124
|
+
string name
|
|
125
|
+
int quantity
|
|
126
|
+
bool isActive
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
@Audited
|
|
130
|
+
entity Catalog16 {
|
|
131
|
+
string code
|
|
132
|
+
string name
|
|
133
|
+
int quantity
|
|
134
|
+
bool isActive
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
@Audited
|
|
138
|
+
entity Catalog17 {
|
|
139
|
+
string code
|
|
140
|
+
string name
|
|
141
|
+
int quantity
|
|
142
|
+
bool isActive
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
@Audited
|
|
146
|
+
entity Catalog18 {
|
|
147
|
+
string code
|
|
148
|
+
string name
|
|
149
|
+
int quantity
|
|
150
|
+
bool isActive
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
@Audited
|
|
154
|
+
entity Catalog19 {
|
|
155
|
+
string code
|
|
156
|
+
string name
|
|
157
|
+
int quantity
|
|
158
|
+
bool isActive
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
@Audited
|
|
162
|
+
entity Catalog20 {
|
|
163
|
+
string code
|
|
164
|
+
string name
|
|
165
|
+
int quantity
|
|
166
|
+
bool isActive
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
@Audited
|
|
170
|
+
entity Catalog21 {
|
|
171
|
+
string code
|
|
172
|
+
string name
|
|
173
|
+
int quantity
|
|
174
|
+
bool isActive
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
@Audited
|
|
178
|
+
entity Catalog22 {
|
|
179
|
+
string code
|
|
180
|
+
string name
|
|
181
|
+
int quantity
|
|
182
|
+
bool isActive
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
@Audited
|
|
186
|
+
entity Catalog23 {
|
|
187
|
+
string code
|
|
188
|
+
string name
|
|
189
|
+
int quantity
|
|
190
|
+
bool isActive
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
@Audited
|
|
194
|
+
entity Catalog24 {
|
|
195
|
+
string code
|
|
196
|
+
string name
|
|
197
|
+
int quantity
|
|
198
|
+
bool isActive
|
|
199
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
backend:
|
|
2
|
+
kind: custom
|
|
3
|
+
input:
|
|
4
|
+
file: ./gdl/example.gdl
|
|
5
|
+
type: gdl
|
|
6
|
+
fuse:
|
|
7
|
+
enabled: true
|
|
8
|
+
cleanLayout: true
|
|
9
|
+
includePrebuilt: false
|
|
10
|
+
api:
|
|
11
|
+
microservice: catalog
|
|
12
|
+
baseUrl: /v1
|
|
13
|
+
generate:
|
|
14
|
+
globals:
|
|
15
|
+
tests: true
|
|
16
|
+
testing:
|
|
17
|
+
ci: true
|
|
18
|
+
fixtures:
|
|
19
|
+
Farmer:
|
|
20
|
+
referenceCode: AB12
|
|
21
|
+
auth:
|
|
22
|
+
provider: none
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
backend:
|
|
2
|
+
kind: go-duck
|
|
3
|
+
input:
|
|
4
|
+
file: ./gdl/example.gdl
|
|
5
|
+
type: gdl
|
|
6
|
+
fuse:
|
|
7
|
+
enabled: true
|
|
8
|
+
cleanLayout: true
|
|
9
|
+
includePrebuilt: false
|
|
10
|
+
api:
|
|
11
|
+
microservice: reference-service
|
|
12
|
+
baseUrl: /api
|
|
13
|
+
generate:
|
|
14
|
+
globals:
|
|
15
|
+
tests: true
|
|
16
|
+
testing:
|
|
17
|
+
ci: true
|
|
18
|
+
fixtures:
|
|
19
|
+
Farmer:
|
|
20
|
+
referenceCode: AB12
|
|
21
|
+
auth:
|
|
22
|
+
provider: none
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
backend:
|
|
2
|
+
kind: jhipster
|
|
3
|
+
input:
|
|
4
|
+
file: ./gdl/example.gdl
|
|
5
|
+
type: gdl
|
|
6
|
+
fuse:
|
|
7
|
+
enabled: true
|
|
8
|
+
cleanLayout: true
|
|
9
|
+
includePrebuilt: false
|
|
10
|
+
api:
|
|
11
|
+
microservice: registry
|
|
12
|
+
baseUrl: /api
|
|
13
|
+
generate:
|
|
14
|
+
globals:
|
|
15
|
+
tests: true
|
|
16
|
+
testing:
|
|
17
|
+
ci: true
|
|
18
|
+
fixtures:
|
|
19
|
+
Farmer:
|
|
20
|
+
referenceCode: AB12
|
|
21
|
+
auth:
|
|
22
|
+
provider: keycloak
|
|
23
|
+
realm: test
|
|
24
|
+
clientId: test-client
|
|
25
|
+
serverUrl: http://127.0.0.1:9999
|
|
26
|
+
useMockAuth: false
|
|
27
|
+
provision:
|
|
28
|
+
enabled: false
|
|
29
|
+
iam:
|
|
30
|
+
enabled: false
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
enum Status { ACTIVE, INACTIVE }
|
|
2
|
+
entity Province {
|
|
3
|
+
string name required minlength(2)
|
|
4
|
+
}
|
|
5
|
+
entity Farmer {
|
|
6
|
+
string name required maxlength(30)
|
|
7
|
+
Status status required
|
|
8
|
+
bool active
|
|
9
|
+
date birthDate required
|
|
10
|
+
string referenceCode required pattern(^[A-Z]{2}[0-9]{2}$)
|
|
11
|
+
}
|
|
12
|
+
relationship ManyToOne {
|
|
13
|
+
Farmer{province} to Province{farmer}
|
|
14
|
+
}
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
// Behavioral tests of shared generated UI logic. Requires Node 24+, like the Fuse app.
|
|
2
|
+
const assert = require('node:assert/strict');
|
|
3
|
+
const fs = require('node:fs');
|
|
4
|
+
const path = require('node:path');
|
|
5
|
+
const vm = require('node:vm');
|
|
6
|
+
const { stripTypeScriptTypes } = require('node:module');
|
|
7
|
+
const ejs = require('ejs');
|
|
8
|
+
const rx = require('rxjs');
|
|
9
|
+
|
|
10
|
+
function load(relative, exported, context = {}, preferences = {}, locals = {}) {
|
|
11
|
+
let source = ejs.render(fs.readFileSync(path.join(__dirname, '../src/templates/angular', relative), 'utf8'), { preferences, ...locals });
|
|
12
|
+
source = source.replace(/^import[\s\S]*?;\n/gm, '')
|
|
13
|
+
.replace(/@(Component|Injectable|Pipe)\([\s\S]*?\)\s*/g, '')
|
|
14
|
+
.replace(/@(ViewChild|Input|Output)\([^\n]*?\)\s*/g, '')
|
|
15
|
+
.replace(/^export /gm, '');
|
|
16
|
+
const module = { exports: {} };
|
|
17
|
+
vm.runInNewContext(stripTypeScriptTypes(source) + `\nmodule.exports = ${exported};`, { module, ...rx, ...context });
|
|
18
|
+
return module.exports;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
async function main() {
|
|
22
|
+
const id = '11111111-2222-3333-4444-555555555555';
|
|
23
|
+
let calls = 0;
|
|
24
|
+
let lookup = () => rx.of({ id, firstName: ' First ', lastName: 'Last' });
|
|
25
|
+
const NameService = load('shared/base/audit-user-name.pipe.ts.ejs', 'AuditUserNameService', {
|
|
26
|
+
KeycloakAdminService: {}, inject: () => ({ getUserById: () => { ++calls; return lookup(); } }),
|
|
27
|
+
}, { fuse: { enabled: true }, auth: { provider: 'keycloak' } });
|
|
28
|
+
const names = new NameService();
|
|
29
|
+
assert.equal(await rx.firstValueFrom(names.resolve('Already Named')), 'Already Named');
|
|
30
|
+
assert.equal(await rx.firstValueFrom(names.resolve(null)), '');
|
|
31
|
+
assert.equal(calls, 0);
|
|
32
|
+
assert.equal(await rx.firstValueFrom(names.resolve(id)), 'First Last');
|
|
33
|
+
assert.equal(await rx.firstValueFrom(names.resolve(id)), 'First Last');
|
|
34
|
+
assert.equal(calls, 1, 'Repeated actors reuse a single lookup');
|
|
35
|
+
lookup = () => rx.of({ data: { user: { id, attributes: { given_name: ['First'], family_name: ['Last'] } } } });
|
|
36
|
+
assert.equal(await rx.firstValueFrom(new NameService().resolve(id)), 'First Last');
|
|
37
|
+
lookup = () => rx.throwError(() => new Error('Forbidden'));
|
|
38
|
+
assert.equal(await rx.firstValueFrom(new NameService().resolve(id)), id);
|
|
39
|
+
lookup = () => rx.of({ id: 'different-user', firstName: 'Wrong' });
|
|
40
|
+
assert.equal(await rx.firstValueFrom(new NameService().resolve(id)), id);
|
|
41
|
+
const NoAuthNames = load('shared/base/audit-user-name.pipe.ts.ejs', 'AuditUserNameService');
|
|
42
|
+
assert.equal(await rx.firstValueFrom(new NoAuthNames().resolve(id)), id);
|
|
43
|
+
|
|
44
|
+
const storage = new Map();
|
|
45
|
+
let observer;
|
|
46
|
+
const cleanup = [];
|
|
47
|
+
const Base = load('shared/base/base-list.component.ts.ejs', 'BaseListComponent', {
|
|
48
|
+
localStorage: { getItem: k => storage.get(k) ?? null, setItem: (k, v) => storage.set(k, v) },
|
|
49
|
+
ResizeObserver: class { constructor(callback) { observer = callback; } observe() {} disconnect() { cleanup.push('disconnected'); } },
|
|
50
|
+
});
|
|
51
|
+
const list = Object.create(Base.prototype);
|
|
52
|
+
Object.assign(list, {
|
|
53
|
+
entityNameKebab: 'book', viewMode: 'table', cdr: { markForCheck() {} },
|
|
54
|
+
viewDestroyRef: { onDestroy(callback) { cleanup.push(callback); } },
|
|
55
|
+
listViewport: { nativeElement: { getBoundingClientRect: () => ({ width: 1000 }) } },
|
|
56
|
+
allColumnPreferences: [{key:'state',alwaysVisible:true},{key:'title'},{key:'createdBy',defaultHidden:true}],
|
|
57
|
+
});
|
|
58
|
+
list.restoreColumnPreferences();
|
|
59
|
+
assert.deepEqual(Array.from(list.displayedColumns), ['state', 'title']);
|
|
60
|
+
list.toggleColumn('createdBy');
|
|
61
|
+
list.restoreColumnPreferences();
|
|
62
|
+
assert.ok(list.displayedColumns.includes('createdBy'));
|
|
63
|
+
list.resetColumnPreferences();
|
|
64
|
+
assert.ok(!list.displayedColumns.includes('createdBy'));
|
|
65
|
+
storage.set(list.columnPreferenceStorageKey, '[]');
|
|
66
|
+
list.restoreColumnPreferences();
|
|
67
|
+
assert.deepEqual(Array.from(list.displayedColumns), ['state'], 'Empty saved selections are distinct from no saved preference');
|
|
68
|
+
storage.set(list.columnPreferenceStorageKey, '{broken');
|
|
69
|
+
list.restoreColumnPreferences();
|
|
70
|
+
assert.deepEqual(Array.from(list.displayedColumns), ['state', 'title']);
|
|
71
|
+
list.restoreViewMode();
|
|
72
|
+
list.observeListWidth();
|
|
73
|
+
observer([{ contentRect: { width: 500 } }]);
|
|
74
|
+
assert.equal(list.viewMode, 'card');
|
|
75
|
+
assert.equal(storage.has(list.storageKeyViewMode), false);
|
|
76
|
+
observer([{ contentRect: { width: 900 } }]);
|
|
77
|
+
assert.equal(list.viewMode, 'table');
|
|
78
|
+
list.onViewModeChange('card');
|
|
79
|
+
assert.equal(storage.get(list.storageKeyViewMode), 'card');
|
|
80
|
+
observer([{ contentRect: { width: 1000 } }]);
|
|
81
|
+
assert.equal(list.viewMode, 'card');
|
|
82
|
+
cleanup[0]();
|
|
83
|
+
assert.equal(cleanup[1], 'disconnected');
|
|
84
|
+
const locals = {
|
|
85
|
+
entity: { name: 'Book', fields: [], relationships: [] }, relationships: [], iamAcl: false,
|
|
86
|
+
toCamelCase: value => value[0].toLowerCase() + value.slice(1),
|
|
87
|
+
toKebabCase: value => value.toLowerCase(),
|
|
88
|
+
};
|
|
89
|
+
const FormBase = load('shared/base/base-form.component.ts.ejs', 'BaseFormComponent');
|
|
90
|
+
const Form = load('entity/components/forms/form/_entity_-form.component.ts.ejs', 'BookFormComponent',
|
|
91
|
+
{ BaseFormComponent: FormBase }, {}, locals);
|
|
92
|
+
const form = Object.create(Form.prototype);
|
|
93
|
+
let resetValue;
|
|
94
|
+
let pristine = 0, untouched = 0;
|
|
95
|
+
Object.assign(form, {
|
|
96
|
+
isInitialized: true, entity: {id: 10}, errorMessage: 'old error', dialogData: { defaults: { title: 'Default' } },
|
|
97
|
+
form: { markAsPristine: () => pristine++, markAsUntouched: () => untouched++ },
|
|
98
|
+
formService: { resetForm: (_, entity) => { resetValue = entity; } },
|
|
99
|
+
});
|
|
100
|
+
form.ngOnChanges({ entity: { currentValue: {id: 10, title: 'Edited'} } });
|
|
101
|
+
assert.equal(resetValue.id, 10);
|
|
102
|
+
form.ngOnChanges({ entity: { currentValue: null } });
|
|
103
|
+
assert.equal(resetValue.id, null);
|
|
104
|
+
assert.equal(resetValue.title, 'Default');
|
|
105
|
+
assert.equal(form.entity, null);
|
|
106
|
+
assert.equal(form.errorMessage, null);
|
|
107
|
+
assert.equal(pristine, 1);
|
|
108
|
+
assert.equal(untouched, 1);
|
|
109
|
+
form.ngOnChanges({ entity: { currentValue: undefined } });
|
|
110
|
+
assert.equal(resetValue.id, null);
|
|
111
|
+
|
|
112
|
+
const List = load('entity/components/presentation/list/_entity_-list.component.ts.ejs', 'BookListComponent',
|
|
113
|
+
{ BaseListComponent: Base, takeUntilDestroyed: () => source => source }, {}, locals);
|
|
114
|
+
const host = Object.create(List.prototype);
|
|
115
|
+
const pending = new Map();
|
|
116
|
+
const mounts = [];
|
|
117
|
+
Object.assign(host, {
|
|
118
|
+
formRequestVersion: 0, formMode: 'sidebar', destroyRef: {}, formDrawer: { open() {}, close() {} },
|
|
119
|
+
cdr: { detectChanges: () => mounts.push(host.formVisible), markForCheck() {} },
|
|
120
|
+
bookService: { find: id => { const request = new rx.Subject(); pending.set(id, request); return request; } },
|
|
121
|
+
});
|
|
122
|
+
host.openEdit(1);
|
|
123
|
+
host.openFormDrawer();
|
|
124
|
+
pending.get(1).next({body: {id: 1, title: 'Stale'}});
|
|
125
|
+
assert.equal(host.selectedBook, null, 'Late edit response must not overwrite New');
|
|
126
|
+
assert.equal(host.drawerMode, 'new');
|
|
127
|
+
host.openEdit(1);
|
|
128
|
+
host.openEdit(2);
|
|
129
|
+
pending.get(2).next({body: {id: 2}});
|
|
130
|
+
pending.get(1).next({body: {id: 1}});
|
|
131
|
+
assert.equal(host.selectedBook.id, 2);
|
|
132
|
+
assert.deepEqual(mounts, [false, true, false, true], 'Every opening destroys before mounting');
|
|
133
|
+
host.closeFormDrawer();
|
|
134
|
+
assert.equal(host.selectedBook, null);
|
|
135
|
+
assert.equal(host.formVisible, false);
|
|
136
|
+
console.log('List state tests passed: audit names/cache/fallback, column defaults/preferences, responsive saved view, observer cleanup, reused form defaults, and stale edit responses.');
|
|
137
|
+
}
|
|
138
|
+
main().catch(error => { console.error(error); process.exitCode = 1; });
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
const assert = require('assert/strict');
|
|
2
|
+
const fs = require('fs-extra');
|
|
3
|
+
const path = require('path');
|
|
4
|
+
const os = require('os');
|
|
5
|
+
const { generate, parseJdl } = require('../src');
|
|
6
|
+
const defaults = require('../src/config/default-values');
|
|
7
|
+
|
|
8
|
+
(async () => {
|
|
9
|
+
const root = await fs.mkdtemp(path.join(os.tmpdir(), 'crudforge-micro-functions-'));
|
|
10
|
+
try {
|
|
11
|
+
const config = structuredClone(defaults);
|
|
12
|
+
config.output.directory = root;
|
|
13
|
+
config.fuse = { ...config.fuse, enabled: true, includePrebuilt: false,
|
|
14
|
+
starterPackPath: path.resolve(__dirname, '../fuse-starter-pack/fuse-v21.1') };
|
|
15
|
+
config.input.sources = [
|
|
16
|
+
{ name: 'Identity', folder: 'identityAccessModule' },
|
|
17
|
+
{ name: 'Reference', folder: 'referenceModule' },
|
|
18
|
+
];
|
|
19
|
+
const parsed = parseJdl('enum State { ACTIVE, INACTIVE }\nentity Staff {\n name String\n state State\n}\nentity Province {\n name String\n}\nrelationship ManyToOne { Staff{province} to Province }\nrelationship OneToMany { Province{staff} to Staff }');
|
|
20
|
+
for (const entity of parsed.entities) {
|
|
21
|
+
for (const field of entity.fields) field.fieldTypeIsEnum = parsed.enums.some(en => en.name === field.fieldType);
|
|
22
|
+
const identity = entity.name === 'Staff';
|
|
23
|
+
entity.folderName = identity ? 'identityAccessModule' : 'referenceModule';
|
|
24
|
+
entity.sourceName = identity ? 'Identity' : 'Reference';
|
|
25
|
+
entity.microservice = identity ? 'identity-service' : 'reference-service';
|
|
26
|
+
}
|
|
27
|
+
await generate(parsed, config);
|
|
28
|
+
const apps = path.join(root, 'src/app/domains/admin/modules/apps');
|
|
29
|
+
const staff = path.join(apps, 'micro-functions/identityAccessModule/entities/staff');
|
|
30
|
+
const province = path.join(apps, 'micro-functions/referenceModule/entities/province');
|
|
31
|
+
assert(fs.existsSync(path.join(apps, 'micro-functions/referenceModule/enum')));
|
|
32
|
+
assert(!fs.existsSync(path.join(apps, 'enums')));
|
|
33
|
+
assert(fs.existsSync(path.join(staff, 'staff.model.ts')));
|
|
34
|
+
assert(fs.existsSync(path.join(province, 'province.model.ts')));
|
|
35
|
+
assert(!fs.existsSync(path.join(apps, 'identityAccessModule')));
|
|
36
|
+
assert(!fs.existsSync(path.join(apps, 'referenceModule')));
|
|
37
|
+
const routes = fs.readFileSync(path.join(root, 'src/app/domains/admin/routes.ts'), 'utf8');
|
|
38
|
+
assert(routes.includes('./modules/apps/micro-functions/identityAccessModule/entities/staff/staff.routes'));
|
|
39
|
+
assert(fs.readFileSync(path.join(staff, 'service/staff.service.ts'), 'utf8').includes('/services/identity-service/api/staffs'));
|
|
40
|
+
// Every relative TS import must resolve, including cross-service relationship imports.
|
|
41
|
+
function verify(dir) {
|
|
42
|
+
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
|
|
43
|
+
const file = path.join(dir, entry.name);
|
|
44
|
+
if (entry.isDirectory()) verify(file);
|
|
45
|
+
else if (file.endsWith('.ts')) {
|
|
46
|
+
const content = fs.readFileSync(file, 'utf8');
|
|
47
|
+
for (const match of content.matchAll(/(?:from\s*|import\s*\()['"](\.[^'"]+)['"]/g)) {
|
|
48
|
+
const target = path.resolve(path.dirname(file), match[1]);
|
|
49
|
+
assert(fs.existsSync(target + '.ts') || fs.existsSync(path.join(target, 'index.ts')), `${file}: ${match[1]}`);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
verify(staff);
|
|
55
|
+
verify(province);
|
|
56
|
+
assert(fs.readFileSync(path.join(staff, 'staff.model.ts'), 'utf8').includes('../../enum/state.model'));
|
|
57
|
+
// Separate schemas may define the same enum name with different values.
|
|
58
|
+
const cliConfig = structuredClone(config);
|
|
59
|
+
cliConfig.output.directory = path.join(root, 'cli-output');
|
|
60
|
+
cliConfig.input.sources = [
|
|
61
|
+
{ name: 'Identity Access', folder: 'identity-access', file: path.join(root, 'identity.jdl'), microservice: 'identity-service' },
|
|
62
|
+
{ name: 'Reference', folder: 'reference', file: path.join(root, 'reference.jdl'), microservice: 'reference-service' },
|
|
63
|
+
{ name: 'Inventory', folder: 'inventory', file: path.join(root, 'inventory.jdl'), microservice: 'inventory-service' },
|
|
64
|
+
];
|
|
65
|
+
fs.writeFileSync(cliConfig.input.sources[0].file, 'enum State { ACTIVE, INACTIVE }\nentity Staff {\n state State\n}');
|
|
66
|
+
fs.writeFileSync(cliConfig.input.sources[1].file, 'enum State { OPEN, CLOSED }\nentity Province {\n state State\n}');
|
|
67
|
+
fs.writeFileSync(cliConfig.input.sources[2].file, 'entity Product {\n name String\n}');
|
|
68
|
+
const configPath = path.join(root, 'config.yml');
|
|
69
|
+
fs.writeFileSync(configPath, require('yaml').stringify(cliConfig));
|
|
70
|
+
const result = require('child_process').spawnSync(process.execPath,
|
|
71
|
+
[path.resolve(__dirname, '../cli.js'), 'generate', '--preferences', configPath, '--yes'],
|
|
72
|
+
{ encoding: 'utf8', maxBuffer: 16 * 1024 * 1024 });
|
|
73
|
+
assert.equal(result.status, 0, result.stdout + result.stderr);
|
|
74
|
+
assert(fs.readFileSync(path.join(cliConfig.output.directory, 'generator/README.md'), 'utf8')
|
|
75
|
+
.includes('Agents and developers should record generator issues'));
|
|
76
|
+
assert(fs.existsSync(path.join(cliConfig.output.directory, 'generator/issues/.gitkeep')));
|
|
77
|
+
const modules = path.join(cliConfig.output.directory, 'src/app/domains/admin/modules/apps/micro-functions');
|
|
78
|
+
assert(fs.statSync(path.join(modules, 'inventory/entities')).isDirectory());
|
|
79
|
+
assert(fs.statSync(path.join(modules, 'inventory/enum')).isDirectory());
|
|
80
|
+
assert.deepEqual(fs.readdirSync(path.join(modules, 'inventory/enum')), ['.gitkeep']);
|
|
81
|
+
const identityEnum = fs.readFileSync(path.join(modules, 'identity-access/enum/state.model.ts'), 'utf8');
|
|
82
|
+
const referenceEnum = fs.readFileSync(path.join(modules, 'reference/enum/state.model.ts'), 'utf8');
|
|
83
|
+
assert(identityEnum.includes('ACTIVE') && !identityEnum.includes('CLOSED'));
|
|
84
|
+
assert(referenceEnum.includes('CLOSED') && !referenceEnum.includes('ACTIVE'));
|
|
85
|
+
verify(path.join(modules, 'identity-access/entities'));
|
|
86
|
+
verify(path.join(modules, 'reference/entities'));
|
|
87
|
+
config.generate.enums = false;
|
|
88
|
+
config.dryRun = true;
|
|
89
|
+
config.output.directory = path.join(root, 'disabled-enums-preview');
|
|
90
|
+
const preview = await require('../src/generator/project-output').generateProject(parsed, config);
|
|
91
|
+
assert(preview.dryRunReport.newFiles.some(file => file.path.endsWith('referenceModule/enum/.gitkeep')));
|
|
92
|
+
assert(!fs.existsSync(config.output.directory));
|
|
93
|
+
console.log('Micro-functions layout passed: module grouping, routes, service APIs, enums, and cross-service imports.');
|
|
94
|
+
} finally { await fs.remove(root); }
|
|
95
|
+
})().catch(error => { console.error(error); process.exitCode = 1; });
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
const assert=require('node:assert/strict'),fs=require('fs-extra'),path=require('path'),os=require('os');
|
|
2
|
+
const {generateFromSource}=require('../src');
|
|
3
|
+
const {generateProject}=require('../src/generator/project-output');
|
|
4
|
+
const {validateConfig}=require('../src/config/load-config');
|
|
5
|
+
(async()=>{
|
|
6
|
+
const root=await fs.mkdtemp(path.join(os.tmpdir(),'crudforge-performance-check-'));
|
|
7
|
+
try {
|
|
8
|
+
const schema=await fs.readFile(path.join(__dirname,'fixtures/performance/large.gdl'),'utf8');
|
|
9
|
+
for(const mode of ['spa','ssr']) {
|
|
10
|
+
const output=path.join(root,mode);const result=await generateFromSource(schema,{configPath:path.join(__dirname,'fixtures/performance/config.yml'),fileType:'gdl',outputDirectory:output,fuse:{enabled:true,rendering:mode,starterPackPath:path.resolve('fuse-starter-pack/fuse-v21.1')}});
|
|
11
|
+
const angular=await fs.readJson(path.join(output,'angular.json'));const options=angular.projects.fuse.architect.build.options;
|
|
12
|
+
const ts=await fs.readJson(path.join(output,'tsconfig.app.json'));const strict=await fs.readJson(path.join(output,'tsconfig.json')).catch(()=>JSON.parse(fs.readFileSync(path.join(output,'tsconfig.json'),'utf8').replace(/\/\*[\s\S]*?\*\//g,'').replace(/^\/\/.*$/gm,'')));
|
|
13
|
+
assert.equal(strict.compilerOptions.strict,true);assert.equal(strict.angularCompilerOptions.strictTemplates,true);
|
|
14
|
+
assert.equal(!!options.ssr,mode==='ssr');assert.equal(ts.files.includes('src/server.ts'),mode==='ssr');assert.deepEqual(ts.include,['src/**/*.d.ts']);
|
|
15
|
+
const app=await fs.readFile(path.join(output,'src/app/app.config.ts'),'utf8');assert.equal(app.includes('provideClientHydration'),mode==='ssr');assert.ok(app.includes('withInterceptors([authInterceptor])'));
|
|
16
|
+
const pkg=await fs.readJson(path.join(output,'package.json'));const lock=await fs.readJson(path.join(output,'package-lock.json'));assert.deepEqual(lock.packages[''].dependencies,pkg.dependencies);assert.equal(!!pkg.dependencies['@angular/ssr'],mode==='ssr');
|
|
17
|
+
const docker=await fs.readFile(path.join(output,'Dockerfile'),'utf8');assert.equal(docker.includes('dist/fuse/server/server.mjs'),mode==='ssr');
|
|
18
|
+
const files=[];async function walk(dir){for(const entry of await fs.readdir(dir,{withFileTypes:true})){const p=path.join(dir,entry.name);if(entry.isDirectory())await walk(p);else files.push(p);}}await walk(path.join(output,'src'));
|
|
19
|
+
for(const name of ['confirmation-dialog.component.ts','resizable.directive.ts','list-styles.css','snackbar-styles.css'])assert.equal(files.filter(f=>path.basename(f)===name).length,1,name);
|
|
20
|
+
for(const file of files.filter(f=>f.endsWith('.ts'))){const code=await fs.readFile(file,'utf8');assert.ok(!code.includes('HttpClientModule'),file);}
|
|
21
|
+
const routes=files.filter(f=>/catalog-\d+\.routes\.ts$/.test(f));assert.equal(routes.length,24);for(const file of routes)assert.ok((await fs.readFile(file,'utf8')).includes('loadComponent: () => import('));
|
|
22
|
+
// Existing overwrite policy protects developer customization of a shared component.
|
|
23
|
+
if(mode==='spa') {
|
|
24
|
+
const shared=files.find(f=>path.basename(f)==='confirmation-dialog.component.ts');await fs.appendFile(shared,'\n// developer customization\n');result.config.output.overwritePolicy='fail';
|
|
25
|
+
await assert.rejects(generateProject(result.parsed,result.config), /conflict|existing|overwrite/i);
|
|
26
|
+
assert.ok((await fs.readFile(shared,'utf8')).includes('developer customization'));
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
assert.throws(()=>validateConfig({fuse:{rendering:'invalid'}},'config.yml'),/fuse.rendering/);
|
|
30
|
+
console.log('Performance generation passed: SPA/SSR coherence, strict checks, 25 entities, shared assets, lazy screens, root HTTP and overwrite protection.');
|
|
31
|
+
}finally{await fs.remove(root);}
|
|
32
|
+
})().catch(e=>{console.error(e);process.exitCode=1;});
|