generator-pninja 1.5.1 → 1.6.0

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.
Files changed (217) hide show
  1. package/README.md +54 -9
  2. package/generators/app/index.js +18 -4
  3. package/generators/auth/templates/packages/pninja/laravel-keycloak-guard/src/KeycloakGuard.php +7 -3
  4. package/generators/auth/templates/packages/pninja/laravel-keycloak-guard/src/TokenDecoder.php +3 -2
  5. package/generators/client/react.inc.js +143 -130
  6. package/generators/client/templates/react/package-lock.json.ejs +3422 -111
  7. package/generators/client/templates/react/package.json.ejs +5 -0
  8. package/generators/client/templates/react/public/locales/common/am.json.ejs +10 -0
  9. package/generators/client/templates/react/public/locales/common/ar.json.ejs +10 -0
  10. package/generators/client/templates/react/public/locales/common/az.json.ejs +10 -0
  11. package/generators/client/templates/react/public/locales/common/bg.json.ejs +10 -0
  12. package/generators/client/templates/react/public/locales/common/bn.json.ejs +10 -0
  13. package/generators/client/templates/react/public/locales/common/ca.json.ejs +10 -0
  14. package/generators/client/templates/react/public/locales/common/cs.json.ejs +10 -0
  15. package/generators/client/templates/react/public/locales/common/cy.json.ejs +10 -0
  16. package/generators/client/templates/react/public/locales/common/da.json.ejs +10 -0
  17. package/generators/client/templates/react/public/locales/common/de.json.ejs +10 -0
  18. package/generators/client/templates/react/public/locales/common/el.json.ejs +10 -0
  19. package/generators/client/templates/react/public/locales/common/en.json.ejs +10 -0
  20. package/generators/client/templates/react/public/locales/common/es.json.ejs +10 -0
  21. package/generators/client/templates/react/public/locales/common/et.json.ejs +10 -0
  22. package/generators/client/templates/react/public/locales/common/eu.json.ejs +10 -0
  23. package/generators/client/templates/react/public/locales/common/fa.json.ejs +10 -0
  24. package/generators/client/templates/react/public/locales/common/fi.json.ejs +10 -0
  25. package/generators/client/templates/react/public/locales/common/fr.json.ejs +10 -0
  26. package/generators/client/templates/react/public/locales/common/fy.json.ejs +10 -0
  27. package/generators/client/templates/react/public/locales/common/ga.json.ejs +10 -0
  28. package/generators/client/templates/react/public/locales/common/gl.json.ejs +10 -0
  29. package/generators/client/templates/react/public/locales/common/gu.json.ejs +10 -0
  30. package/generators/client/templates/react/public/locales/common/ha.json.ejs +10 -0
  31. package/generators/client/templates/react/public/locales/common/he.json.ejs +10 -0
  32. package/generators/client/templates/react/public/locales/common/hi.json.ejs +10 -0
  33. package/generators/client/templates/react/public/locales/common/hr.json.ejs +10 -0
  34. package/generators/client/templates/react/public/locales/common/ht.json.ejs +10 -0
  35. package/generators/client/templates/react/public/locales/common/hu.json.ejs +10 -0
  36. package/generators/client/templates/react/public/locales/common/hy.json.ejs +10 -0
  37. package/generators/client/templates/react/public/locales/common/id.json.ejs +10 -0
  38. package/generators/client/templates/react/public/locales/common/is.json.ejs +10 -0
  39. package/generators/client/templates/react/public/locales/common/it.json.ejs +10 -0
  40. package/generators/client/templates/react/public/locales/common/ja.json.ejs +10 -0
  41. package/generators/client/templates/react/public/locales/common/kk.json.ejs +10 -0
  42. package/generators/client/templates/react/public/locales/common/ko.json.ejs +10 -0
  43. package/generators/client/templates/react/public/locales/common/lt.json.ejs +10 -0
  44. package/generators/client/templates/react/public/locales/common/lv.json.ejs +10 -0
  45. package/generators/client/templates/react/public/locales/common/mi.json.ejs +10 -0
  46. package/generators/client/templates/react/public/locales/common/ms.json.ejs +10 -0
  47. package/generators/client/templates/react/public/locales/common/mt.json.ejs +10 -0
  48. package/generators/client/templates/react/public/locales/common/nl.json.ejs +10 -0
  49. package/generators/client/templates/react/public/locales/common/no.json.ejs +10 -0
  50. package/generators/client/templates/react/public/locales/common/om.json.ejs +10 -0
  51. package/generators/client/templates/react/public/locales/common/pl.json.ejs +10 -0
  52. package/generators/client/templates/react/public/locales/common/pt.json.ejs +10 -0
  53. package/generators/client/templates/react/public/locales/common/ro.json.ejs +10 -0
  54. package/generators/client/templates/react/public/locales/common/ru.json.ejs +10 -0
  55. package/generators/client/templates/react/public/locales/common/rw.json.ejs +10 -0
  56. package/generators/client/templates/react/public/locales/common/sk.json.ejs +10 -0
  57. package/generators/client/templates/react/public/locales/common/sl.json.ejs +10 -0
  58. package/generators/client/templates/react/public/locales/common/sq.json.ejs +10 -0
  59. package/generators/client/templates/react/public/locales/common/sr.json.ejs +10 -0
  60. package/generators/client/templates/react/public/locales/common/sv.json.ejs +10 -0
  61. package/generators/client/templates/react/public/locales/common/sw.json.ejs +10 -0
  62. package/generators/client/templates/react/public/locales/common/ta.json.ejs +10 -0
  63. package/generators/client/templates/react/public/locales/common/tr.json.ejs +10 -0
  64. package/generators/client/templates/react/public/locales/common/uk.json.ejs +10 -0
  65. package/generators/client/templates/react/public/locales/common/ur.json.ejs +10 -0
  66. package/generators/client/templates/react/public/locales/common/uz.json.ejs +10 -0
  67. package/generators/client/templates/react/public/locales/common/vi.json.ejs +10 -0
  68. package/generators/client/templates/react/public/locales/common/yo.json.ejs +10 -0
  69. package/generators/client/templates/react/public/locales/common/zh.json.ejs +10 -0
  70. package/generators/client/templates/react/public/locales/common/zu.json.ejs +10 -0
  71. package/generators/client/templates/react/public/locales/locking/am.json +26 -0
  72. package/generators/client/templates/react/public/locales/locking/ar.json +26 -0
  73. package/generators/client/templates/react/public/locales/locking/az.json +26 -0
  74. package/generators/client/templates/react/public/locales/locking/bg.json +26 -0
  75. package/generators/client/templates/react/public/locales/locking/bn.json +26 -0
  76. package/generators/client/templates/react/public/locales/locking/ca.json +26 -0
  77. package/generators/client/templates/react/public/locales/locking/cs.json +26 -0
  78. package/generators/client/templates/react/public/locales/locking/cy.json +26 -0
  79. package/generators/client/templates/react/public/locales/locking/da.json +26 -0
  80. package/generators/client/templates/react/public/locales/locking/de.json +26 -0
  81. package/generators/client/templates/react/public/locales/locking/el.json +26 -0
  82. package/generators/client/templates/react/public/locales/locking/en.json +26 -0
  83. package/generators/client/templates/react/public/locales/locking/es.json +26 -0
  84. package/generators/client/templates/react/public/locales/locking/et.json +26 -0
  85. package/generators/client/templates/react/public/locales/locking/eu.json +26 -0
  86. package/generators/client/templates/react/public/locales/locking/fa.json +26 -0
  87. package/generators/client/templates/react/public/locales/locking/fi.json +26 -0
  88. package/generators/client/templates/react/public/locales/locking/fr.json +26 -0
  89. package/generators/client/templates/react/public/locales/locking/fy.json +26 -0
  90. package/generators/client/templates/react/public/locales/locking/ga.json +26 -0
  91. package/generators/client/templates/react/public/locales/locking/gl.json +26 -0
  92. package/generators/client/templates/react/public/locales/locking/gu.json +26 -0
  93. package/generators/client/templates/react/public/locales/locking/ha.json +26 -0
  94. package/generators/client/templates/react/public/locales/locking/he.json +26 -0
  95. package/generators/client/templates/react/public/locales/locking/hi.json +26 -0
  96. package/generators/client/templates/react/public/locales/locking/hr.json +26 -0
  97. package/generators/client/templates/react/public/locales/locking/ht.json +26 -0
  98. package/generators/client/templates/react/public/locales/locking/hu.json +26 -0
  99. package/generators/client/templates/react/public/locales/locking/hy.json +26 -0
  100. package/generators/client/templates/react/public/locales/locking/id.json +26 -0
  101. package/generators/client/templates/react/public/locales/locking/is.json +26 -0
  102. package/generators/client/templates/react/public/locales/locking/it.json +26 -0
  103. package/generators/client/templates/react/public/locales/locking/ja.json +26 -0
  104. package/generators/client/templates/react/public/locales/locking/kk.json +26 -0
  105. package/generators/client/templates/react/public/locales/locking/ko.json +26 -0
  106. package/generators/client/templates/react/public/locales/locking/lt.json +26 -0
  107. package/generators/client/templates/react/public/locales/locking/lv.json +26 -0
  108. package/generators/client/templates/react/public/locales/locking/mi.json +26 -0
  109. package/generators/client/templates/react/public/locales/locking/ms.json +26 -0
  110. package/generators/client/templates/react/public/locales/locking/mt.json +26 -0
  111. package/generators/client/templates/react/public/locales/locking/nl.json +26 -0
  112. package/generators/client/templates/react/public/locales/locking/no.json +26 -0
  113. package/generators/client/templates/react/public/locales/locking/om.json +26 -0
  114. package/generators/client/templates/react/public/locales/locking/pl.json +26 -0
  115. package/generators/client/templates/react/public/locales/locking/pt.json +26 -0
  116. package/generators/client/templates/react/public/locales/locking/ro.json +26 -0
  117. package/generators/client/templates/react/public/locales/locking/ru.json +26 -0
  118. package/generators/client/templates/react/public/locales/locking/rw.json +26 -0
  119. package/generators/client/templates/react/public/locales/locking/sk.json +26 -0
  120. package/generators/client/templates/react/public/locales/locking/sl.json +26 -0
  121. package/generators/client/templates/react/public/locales/locking/sq.json +26 -0
  122. package/generators/client/templates/react/public/locales/locking/sr.json +26 -0
  123. package/generators/client/templates/react/public/locales/locking/sv.json +26 -0
  124. package/generators/client/templates/react/public/locales/locking/sw.json +26 -0
  125. package/generators/client/templates/react/public/locales/locking/ta.json +26 -0
  126. package/generators/client/templates/react/public/locales/locking/tr.json +26 -0
  127. package/generators/client/templates/react/public/locales/locking/uk.json +26 -0
  128. package/generators/client/templates/react/public/locales/locking/ur.json +26 -0
  129. package/generators/client/templates/react/public/locales/locking/uz.json +26 -0
  130. package/generators/client/templates/react/public/locales/locking/vi.json +26 -0
  131. package/generators/client/templates/react/public/locales/locking/yo.json +26 -0
  132. package/generators/client/templates/react/public/locales/locking/zh.json +26 -0
  133. package/generators/client/templates/react/public/locales/locking/zu.json +26 -0
  134. package/generators/client/templates/react/public/oauth2-redirect.html +36 -0
  135. package/generators/client/templates/react/public/wordlists/eff_large.txt +7776 -0
  136. package/generators/client/templates/react/src/App.tsx.ejs +140 -131
  137. package/generators/client/templates/react/src/components/ConfirmButton.tsx.ejs +5 -13
  138. package/generators/client/templates/react/src/components/DarkModeToggle.tsx.ejs +4 -4
  139. package/generators/client/templates/react/src/components/Menu.tsx.ejs +58 -24
  140. package/generators/client/templates/react/src/components/Toast.tsx.ejs +12 -3
  141. package/generators/client/templates/react/src/components/Tooltip.tsx.ejs +69 -0
  142. package/generators/client/templates/react/src/components/entities/AcRuleDeleteButton.tsx.ejs +16 -7
  143. package/generators/client/templates/react/src/components/entities/EntityDeleteButton.tsx.ejs +8 -7
  144. package/generators/client/templates/react/src/components/entities/EntityForm.tsx.ejs +23 -3
  145. package/generators/client/templates/react/src/components/formElements/FormFieldInfo.tsx.ejs +2 -1
  146. package/generators/client/templates/react/src/components/formElements/PasswordField.tsx.ejs +138 -34
  147. package/generators/client/templates/react/src/components/formElements/UuidField.tsx.ejs +1 -1
  148. package/generators/client/templates/react/src/contexts/NotificationContext.tsx.ejs +7 -0
  149. package/generators/client/templates/react/src/i18n.js.ejs +1 -1
  150. package/generators/client/templates/react/src/index.css.ejs +32 -0
  151. package/generators/client/templates/react/src/pages/{server-logs/LogViewer.tsx.ejs → admin/Logs.tsx.ejs} +7 -4
  152. package/generators/client/templates/react/src/pages/admin/Migrations.tsx.ejs +5 -2
  153. package/generators/client/templates/react/src/pages/{search-reindex/SearchReindexList.tsx.ejs → admin/SearchReindex.tsx.ejs} +19 -15
  154. package/generators/client/templates/react/src/pages/{seeder/SeederList.tsx.ejs → admin/Seeder.tsx.ejs} +12 -9
  155. package/generators/client/templates/react/src/pages/{audit → admin/audit}/AuditHistory.tsx.ejs +12 -9
  156. package/generators/client/templates/react/src/pages/{audit → admin/audit}/AuditList.tsx.ejs +18 -16
  157. package/generators/client/templates/react/src/pages/{audit → admin/audit}/AuditStatistics.tsx.ejs +11 -9
  158. package/generators/client/templates/react/src/pages/{audit → admin/audit}/AuditUserActivity.tsx.ejs +16 -20
  159. package/generators/client/templates/react/src/pages/{audit → admin/audit}/AuditView.tsx.ejs +13 -10
  160. package/generators/client/templates/react/src/pages/{audit → admin/audit}/Audits.tsx.ejs +6 -3
  161. package/generators/client/templates/react/src/pages/admin/audit/index.ts.ejs +8 -0
  162. package/generators/client/templates/react/src/pages/entities/EntityEdit.tsx.ejs +53 -14
  163. package/generators/client/templates/react/src/pages/entities/EntityList.tsx.ejs +84 -20
  164. package/generators/client/templates/react/src/pages/entities/EntityTrash.tsx.ejs +14 -16
  165. package/generators/client/templates/react/src/pages/entities/EntityView.tsx.ejs +14 -10
  166. package/generators/client/templates/react/src/pages/errors/Err403.tsx.ejs +20 -16
  167. package/generators/client/templates/react/src/pages/errors/Err404.tsx.ejs +8 -4
  168. package/generators/client/templates/react/src/pages/support/ApiDocs.tsx.ejs +18 -0
  169. package/generators/client/templates/react/src/pages/support/Guide.tsx.ejs +11 -0
  170. package/generators/client/templates/react/src/pages/support/guide.md.ejs +140 -0
  171. package/generators/client/templates/react/src/shared/entitiesIcons.tsx.ejs +5 -2
  172. package/generators/client/templates/react/src/shared/services/entity.service.ts.ejs +52 -0
  173. package/generators/entities/index.js +12 -10
  174. package/generators/entities/templates/app/Http/Controllers/EntityController.php.ejs +13 -1
  175. package/generators/entities/templates/app/Models/Entity.php.ejs +6 -0
  176. package/generators/entities/templates/database/seeders/AcRuleSeeder.php.ejs +3 -30
  177. package/generators/entities/templates/openapi.yaml.ejs +1 -0
  178. package/generators/entities/utils/controllers-generator.js +7 -13
  179. package/generators/entities/utils/entity-splitter.js +2 -0
  180. package/generators/entities/utils/factories-generator.js +7 -5
  181. package/generators/entities/utils/migrations-generator.js +22 -31
  182. package/generators/entities/utils/models-generator.js +4 -4
  183. package/generators/entities/utils/openapi-generator.js +1035 -0
  184. package/generators/entity/index.js +108 -47
  185. package/generators/final/index.js +6 -1
  186. package/generators/final/templates/README.md.ejs +136 -18
  187. package/generators/locking/index.js +75 -0
  188. package/generators/locking/templates/client/components/LockBanner.tsx.ejs +40 -0
  189. package/generators/locking/templates/client/hooks/useRecordLock.ts.ejs +89 -0
  190. package/generators/locking/templates/client/src/pages/admin/RecordsLocks.tsx.ejs +151 -0
  191. package/generators/locking/templates/server/app/Http/Controllers/RecordLockController.php.ejs +116 -0
  192. package/generators/locking/templates/server/app/Jobs/CleanExpiredLocksJob.php.ejs +20 -0
  193. package/generators/locking/templates/server/app/Models/RecordLock.php.ejs +37 -0
  194. package/generators/locking/templates/server/app/Traits/Lockable.php.ejs +30 -0
  195. package/generators/locking/templates/server/config/locking.php.ejs +9 -0
  196. package/generators/locking/templates/server/database/migrations/create_record_locks_table.php.ejs +26 -0
  197. package/generators/search/index.js +10 -9
  198. package/generators/server/index.js +5 -9
  199. package/generators/server/templates/ApiErrorHandler.php.ejs +2 -0
  200. package/generators/server/templates/app/Http/Controllers/OpenApiController.php.ejs +32 -0
  201. package/generators/server/templates/app/Http/Controllers/UserRoleController.php.ejs +3 -3
  202. package/generators/server/templates/app/Http/Middleware/AccessControl.php.ejs +13 -3
  203. package/generators/server/templates/app/Http/Middleware/SessionAuth.php.ejs +20 -3
  204. package/generators/server/templates/app/Traits/HandlesUserRoles.php.ejs +5 -3
  205. package/generators/server/templates/app/Traits/SeederHelpers.php.ejs +90 -1
  206. package/generators/server/templates/app.php.ejs +3 -0
  207. package/generators/server/templates/config/lauthz-rbac-model.conf +1 -1
  208. package/generators/server/templates/routes/api.php.ejs +20 -4
  209. package/generators/server/templates/routes/console.php.ejs +11 -3
  210. package/generators/utils/AcRule.js +1 -0
  211. package/package.json +1 -1
  212. package/generators/entities/templates/ApiErrorHandler.php.ejs +0 -31
  213. package/generators/entities/templates/HandlesUserRoles.php.ejs +0 -90
  214. package/generators/entities/templates/app.php.ejs +0 -31
  215. package/generators/entities/templates/config/audit.php.ejs +0 -202
  216. package/generators/entities/templates/config/lauthz-rbac-model.conf +0 -14
  217. package/generators/entities/templates/config/lauthz.php +0 -70
package/README.md CHANGED
@@ -113,7 +113,7 @@ Fully wired together: auth, routing, forms, CRUD, migrations.
113
113
 
114
114
  ### Data Management
115
115
 
116
- - **Soft Delete Support** - Logical deletion with `deleted_at` timestamps (use `@softDelete` annotation in JDL)
116
+ - **Soft Delete Support** - Logical deletion with `deleted_at` timestamps; includes a web interface to view, restore, or permanently delete soft-deleted records. Unique constraints are enforced at the application level. Use `@softDelete` annotation in JDL.
117
117
 
118
118
  ```jdl
119
119
  @softDelete
@@ -123,6 +123,18 @@ Fully wired together: auth, routing, forms, CRUD, migrations.
123
123
  }
124
124
  ```
125
125
 
126
+ > ⚠️ When `@softDelete` is used, unique constraints are enforced at the application level only — no unique index is generated in the migration.
127
+
128
+ - **Pessimistic Record Locking** - Records are locked when opened for editing, preventing concurrent modifications. Locks expire automatically after 15 minutes, are renewed every 2 minutes via heartbeat, and can be force-released from the lock administration interface. Use `@pessimisticLock` annotation in JDL.
129
+
130
+ ```jdl
131
+ @pessimisticLock
132
+ entity MyEntity {
133
+ name String required
134
+ description String
135
+ }
136
+ ```
137
+
126
138
  - **CSV Database Seeding** - Populate your database from CSV files
127
139
  - **Seeding Administration** - Web interface to run seeders individually or in bulk, with direct CSV upload from the browser
128
140
  - **Migration Administration** - Web interface to run `migrate`, `rollback`, `migrate:fresh` and check `migrate:status` without the command line
@@ -206,6 +218,47 @@ Fully wired together: auth, routing, forms, CRUD, migrations.
206
218
 
207
219
  - [i18next][i18next-url]
208
220
 
221
+ ## API Documentation
222
+
223
+ PNinja generates an interactive **API documentation interface** powered by **[Swagger UI](https://swagger.io/tools/swagger-ui/)** and an **OpenAPI 3.0 specification** built automatically from your JDL model.
224
+
225
+ ### In the generated application
226
+
227
+ The API docs are accessible at `/support/api-docs` in the generated React client.
228
+
229
+ **Features:**
230
+
231
+ - **Interactive console** — execute API calls directly from the browser
232
+ - **Authentication** — supports both Bearer token and OAuth2 (Keycloak) login via the **Authorize** button
233
+ - **Full endpoint coverage** — all generated entities, auth, user, and locks endpoints are documented
234
+ - **Schema reference** — read and write schemas for every entity, including blob field handling
235
+
236
+ **Authenticating via Swagger UI:**
237
+
238
+ - **Bearer token** (machine-to-machine): paste a valid JWT in the Authorize dialog
239
+ - **OAuth2** (interactive login): click Authorize → select OAuth2 → log in via Keycloak
240
+
241
+ **For machine-to-machine integrations**, use the Client Credentials flow:
242
+
243
+ ```sh
244
+ curl -X POST 'https://<keycloak-host>/realms/<realm>/protocol/openid-connect/token' \
245
+ -H 'Content-Type: application/x-www-form-urlencoded' \
246
+ -d 'grant_type=client_credentials' \
247
+ -d 'client_id=YOUR_CLIENT_ID' \
248
+ -d 'client_secret=YOUR_CLIENT_SECRET'
249
+ ```
250
+
251
+ Then use the returned `access_token` as Bearer header in all API calls.
252
+
253
+ ### How it works
254
+
255
+ The OpenAPI specification is:
256
+
257
+ - **Generated** by `generators/entities/utils/openapi-generator.js` from your JDL entities
258
+ - **Stored** as `server/resources/openapi.json` with Keycloak URL placeholders
259
+ - **Served dynamically** at `GET /api/openapi.json` by `OpenApiController`, which resolves the Keycloak URLs from `server/.env` at runtime
260
+ - **Rendered** by `swagger-ui-react` in the React client at `/support/api-docs`
261
+
209
262
  ## Roadmap
210
263
 
211
264
  ### Frontend Frameworks
@@ -218,14 +271,6 @@ Fully wired together: auth, routing, forms, CRUD, migrations.
218
271
  - [SQL Server][sqlserver-url] support
219
272
  - [Oracle][oracle-url] support
220
273
 
221
- ### Features
222
-
223
- - **Multi-tenancy Support** - Isolated data per tenant
224
- - **API Versioning** - Version management for APIs
225
- - **Real-time Features** - WebSockets/Pusher integration
226
- - **GraphQL Support** - Alternative API layer
227
- - **Advanced Caching** - Redis integration with cache strategies
228
-
229
274
  ### DevOps
230
275
 
231
276
  - **GitHub Actions CI/CD** - Automated testing and deployment
@@ -39,7 +39,7 @@ export default class extends Generator {
39
39
  this.option('searchEngine', {
40
40
  type: String,
41
41
  description: 'The search engine to use (database, algolia, elastic, meilisearch, typesense, solr, null)',
42
- })
42
+ });
43
43
  }
44
44
  async initializing() {
45
45
  hello(this.log, true);
@@ -105,6 +105,20 @@ export default class extends Generator {
105
105
  namespace: 'pninja:search'
106
106
  });
107
107
 
108
+ // sub generator Locking
109
+ const lockingGeneratorPath = path.resolve(__dirname, '../locking/index.js');
110
+ const { default: LockingGenerator } = await import(lockingGeneratorPath);
111
+
112
+ await this.composeWith({
113
+ Generator: LockingGenerator,
114
+ path: path.dirname(lockingGeneratorPath)
115
+ }, {
116
+ fromMain: true,
117
+ env: this.env,
118
+ resolved: lockingGeneratorPath,
119
+ namespace: 'pninja:locking'
120
+ });
121
+
108
122
  // sub generator Docker
109
123
  const dockerGeneratorPath = path.resolve(__dirname, '../docker/index.js');
110
124
  const { default: DockerGenerator } = await import(dockerGeneratorPath);
@@ -194,10 +208,10 @@ export default class extends Generator {
194
208
 
195
209
  async writing() {
196
210
  await this.spawn('composer', ['create-project', '--prefer-dist', 'laravel/laravel=~11.6.1', 'server']);
197
- await this.spawn('composer', ['require', '--dev', 'beyondcode/laravel-dump-server'], { cwd: 'server' });
211
+ await this.spawn('composer', ['require', '--dev', 'beyondcode/laravel-dump-server:^2.1'], { cwd: 'server' });
198
212
  await this.spawn('php', ['artisan', 'install:api', '--without-migration-prompt'], { cwd: 'server' });
199
- await this.spawn('composer', ['require', 'casbin/laravel-authz'], { cwd: 'server' });
200
- await this.spawn('composer', ['require', 'owen-it/laravel-auditing'], { cwd: 'server' });
213
+ await this.spawn('composer', ['require', 'casbin/laravel-authz:^4.1'], { cwd: 'server' });
214
+ await this.spawn('composer', ['require', 'owen-it/laravel-auditing:^14.0'], { cwd: 'server' });
201
215
  let envFileContents = fs.readFileSync(`${this.destinationPath('server')}/.env`, { encoding: 'utf8', flag: 'r' });
202
216
  envFileContents = envFileContents.replace(/^APP_NAME=.*$/m, `APP_NAME=${to.constant(this.answers.name)}`);
203
217
  envFileContents = envFileContents.replace(/^APP_KEY=.*$/m, `APP_KEY=${randomstring.generate()}`);
@@ -48,7 +48,7 @@ class KeycloakGuard implements Guard
48
48
 
49
49
  try {
50
50
  $claims = $this->getDecodedToken();
51
- } catch (InvalidTokenException) {
51
+ } catch (\Throwable) {
52
52
  return null;
53
53
  }
54
54
 
@@ -167,8 +167,12 @@ class KeycloakGuard implements Guard
167
167
  return null;
168
168
  }
169
169
 
170
- $plain = $this->decoder->decode($rawToken);
171
- $this->decodedToken = $this->decoder->claims($plain);
170
+ try {
171
+ $plain = $this->decoder->decode($rawToken);
172
+ $this->decodedToken = $this->decoder->claims($plain);
173
+ } catch (InvalidTokenException) {
174
+ return null;
175
+ }
172
176
 
173
177
  return $this->decodedToken;
174
178
  }
@@ -7,6 +7,8 @@ namespace Pninja\KeycloakGuard;
7
7
  use DateInterval;
8
8
  use Lcobucci\Clock\SystemClock;
9
9
  use Lcobucci\JWT\Configuration;
10
+ use Lcobucci\JWT\Encoding\JoseEncoder;
11
+ use Lcobucci\JWT\Token\Parser;
10
12
  use Lcobucci\JWT\Signer;
11
13
  use Lcobucci\JWT\Signer\Key\InMemory;
12
14
  use Lcobucci\JWT\Token\Plain;
@@ -33,8 +35,7 @@ class TokenDecoder
33
35
  $signer = $this->getSigner();
34
36
 
35
37
  // Parse without verification first so we can read the header (kid, alg)
36
- $insecureParser = Configuration::forUnsecuredSigner();
37
- $parsed = $insecureParser->parser()->parse($tokenString);
38
+ $parsed = (new Parser(new JoseEncoder()))->parse($tokenString);
38
39
 
39
40
  if (! $parsed instanceof Plain) {
40
41
  throw InvalidTokenException::invalidSignature();
@@ -5,6 +5,7 @@ import { getModelForeignIds } from './utils/getModelForeignIds.js';
5
5
  import { getLanguageData } from './config/languages.js';
6
6
  import { AcRule } from '../utils/AcRule.js';
7
7
  import { getEntities, getEntitiesRelationships, getEnums } from '../utils/entities-utils.js';
8
+ import { OpenApiGenerator } from '../entities/utils/openapi-generator.js';
8
9
 
9
10
  const colors = [
10
11
  "lime",
@@ -33,7 +34,12 @@ export async function createEntityPages({
33
34
  }) {
34
35
  const hasSoftDelete = entity.softDelete;
35
36
  that.fs.copyTpl(
36
- that.templatePath("react/src/pages/entities/EntityList.tsx.ejs"),
37
+ that.templatePath("../../client/templates/react/src/shared/services/entity.service.ts.ejs"),
38
+ that.destinationPath(`client/src/shared/services/${to.slug(entity.name)}.service.ts`),
39
+ { entity, to, pluralize, searchEngine }
40
+ );
41
+ that.fs.copyTpl(
42
+ that.templatePath("../../client/templates/react/src/pages/entities/EntityList.tsx.ejs"),
37
43
  that.destinationPath(`client/src/pages/entities/${entity.name}List.tsx`),
38
44
  {
39
45
  entity,
@@ -48,7 +54,7 @@ export async function createEntityPages({
48
54
  });
49
55
  if (hasSoftDelete) {
50
56
  that.fs.copyTpl(
51
- that.templatePath("react/src/pages/entities/EntityTrash.tsx.ejs"),
57
+ that.templatePath("../../client/templates/react/src/pages/entities/EntityTrash.tsx.ejs"),
52
58
  that.destinationPath(`client/src/pages/entities/${entity.name}Trash.tsx`),
53
59
  {
54
60
  entity,
@@ -63,7 +69,7 @@ export async function createEntityPages({
63
69
  });
64
70
  }
65
71
  that.fs.copyTpl(
66
- that.templatePath("react/src/pages/entities/EntityView.tsx.ejs"),
72
+ that.templatePath("../../client/templates/react/src/pages/entities/EntityView.tsx.ejs"),
67
73
  that.destinationPath(`client/src/pages/entities/${entity.name}View.tsx`),
68
74
  {
69
75
  entity,
@@ -76,7 +82,7 @@ export async function createEntityPages({
76
82
  relatedEntities: getModelRelatedEntities(entity, relationships)
77
83
  });
78
84
  that.fs.copyTpl(
79
- that.templatePath("react/src/pages/entities/EntityEdit.tsx.ejs"),
85
+ that.templatePath("../../client/templates/react/src/pages/entities/EntityEdit.tsx.ejs"),
80
86
  that.destinationPath(`client/src/pages/entities/${entity.name}Edit.tsx`),
81
87
  {
82
88
  entity,
@@ -84,10 +90,11 @@ export async function createEntityPages({
84
90
  pluralize,
85
91
  columns: entity.fields.map(c => to.snake(c.name)),
86
92
  foreignIds: getModelForeignIds(entity, relationships),
87
- relatedEntities: getModelRelatedEntities(entity, relationships)
93
+ relatedEntities: getModelRelatedEntities(entity, relationships).length,
94
+ locking: entity.pessimisticLock
88
95
  });
89
96
  that.fs.copyTpl(
90
- that.templatePath("react/src/components/entities/EntityForm.tsx.ejs"),
97
+ that.templatePath("../../client/templates/react/src/components/entities/EntityForm.tsx.ejs"),
91
98
  that.destinationPath(`client/src/components/entities/${entity.name}Form.tsx`),
92
99
  {
93
100
  entity,
@@ -103,11 +110,12 @@ export async function createEntityPages({
103
110
  ).map(rel => to.snake(rel.relationshipName || rel.otherEntityName)),
104
111
  to,
105
112
  pluralize,
106
- searchEngine
113
+ searchEngine,
114
+ locking: entity.pessimisticLock
107
115
  }
108
116
  );
109
117
  that.fs.copyTpl(
110
- that.templatePath("react/src/components/entities/EntityDeleteButton.tsx.ejs"),
118
+ that.templatePath("../../client/templates/react/src/components/entities/EntityDeleteButton.tsx.ejs"),
111
119
  that.destinationPath(`client/src/components/entities/${entity.name}DeleteButton.tsx`),
112
120
  {
113
121
  entity,
@@ -116,7 +124,7 @@ export async function createEntityPages({
116
124
  }
117
125
  );
118
126
  that.fs.copyTpl(
119
- that.templatePath("react/src/shared/model/entity.model.ts.ejs"),
127
+ that.templatePath("../../client/templates/react/src/shared/model/entity.model.ts.ejs"),
120
128
  that.destinationPath(`client/src/shared/model/${to.slug(entity.name)}.model.ts`),
121
129
  {
122
130
  entity,
@@ -138,27 +146,28 @@ export async function createReactClient(that) {
138
146
 
139
147
  await that.spawn('npm', ['create', 'vite@6.1.1', 'client', '--', '--template', 'react-ts', '--no-install']);
140
148
 
141
- that.fs.copyTpl(that.templatePath('react/.env.ejs'), that.destinationPath('client/.env'), { searchEngine });
142
- that.fs.copyTpl(that.templatePath('react/.gitignore.ejs'), that.destinationPath('client/.gitignore'), {});
143
- that.fs.copyTpl(that.templatePath('react/eslint.config.js.ejs'), that.destinationPath('client/eslint.config.js'), {});
144
- that.fs.copyTpl(that.templatePath('react/index.html.ejs'), that.destinationPath('client/index.html'), { appName });
145
- that.fs.copyTpl(that.templatePath('react/package.json.ejs'), that.destinationPath('client/package.json'), { name: to.slug(appName) });
146
- that.fs.copyTpl(that.templatePath('react/package-lock.json.ejs'), that.destinationPath('client/package-lock.json'), { name: to.slug(appName) });
147
- that.fs.copyTpl(that.templatePath('react/tsconfig.app.json.ejs'), that.destinationPath('client/tsconfig.app.json'), {});
148
- that.fs.copyTpl(that.templatePath('react/tsconfig.json.ejs'), that.destinationPath('client/tsconfig.json'), {});
149
- that.fs.copyTpl(that.templatePath('react/tsconfig.node.json.ejs'), that.destinationPath('client/tsconfig.node.json'), {});
150
- that.fs.copyTpl(that.templatePath('react/vite.config.ts.ejs'), that.destinationPath('client/vite.config.ts'), {});
149
+ that.fs.copyTpl(that.templatePath('../../client/templates/react/.env.ejs'), that.destinationPath('client/.env'), { searchEngine });
150
+ that.fs.copyTpl(that.templatePath('../../client/templates/react/.gitignore.ejs'), that.destinationPath('client/.gitignore'), {});
151
+ that.fs.copyTpl(that.templatePath('../../client/templates/react/eslint.config.js.ejs'), that.destinationPath('client/eslint.config.js'), {});
152
+ that.fs.copyTpl(that.templatePath('../../client/templates/react/index.html.ejs'), that.destinationPath('client/index.html'), { appName });
153
+ that.fs.copyTpl(that.templatePath('../../client/templates/react/package.json.ejs'), that.destinationPath('client/package.json'), { name: to.slug(appName) });
154
+ that.fs.copyTpl(that.templatePath('../../client/templates/react/package-lock.json.ejs'), that.destinationPath('client/package-lock.json'), { name: to.slug(appName) });
155
+ that.fs.copyTpl(that.templatePath('../../client/templates/react/tsconfig.app.json.ejs'), that.destinationPath('client/tsconfig.app.json'), {});
156
+ that.fs.copyTpl(that.templatePath('../../client/templates/react/tsconfig.json.ejs'), that.destinationPath('client/tsconfig.json'), {});
157
+ that.fs.copyTpl(that.templatePath('../../client/templates/react/tsconfig.node.json.ejs'), that.destinationPath('client/tsconfig.node.json'), {});
158
+ that.fs.copyTpl(that.templatePath('../../client/templates/react/vite.config.ts.ejs'), that.destinationPath('client/vite.config.ts'), {});
151
159
 
152
160
  for (const lang of languages) {
153
- that.fs.copyTpl(that.templatePath(`react/public/locales/log/${lang}.json`), that.destinationPath(`client/public/locales/${lang}/log.json`));
154
- that.fs.copyTpl(that.templatePath(`react/public/locales/audit/${lang}.json`), that.destinationPath(`client/public/locales/${lang}/audit.json`));
155
- that.fs.copyTpl(that.templatePath(`react/public/locales/seeder/${lang}.json`), that.destinationPath(`client/public/locales/${lang}/seeder.json`));
156
- that.fs.copyTpl(that.templatePath(`react/public/locales/migrations/${lang}.json`), that.destinationPath(`client/public/locales/${lang}/migrations.json`));
157
- that.fs.copyTpl(that.templatePath(`react/public/locales/common/${lang}.json.ejs`), that.destinationPath(`client/public/locales/${lang}/common.json`), { appName });
161
+ that.fs.copyTpl(that.templatePath(`../../client/templates/react/public/locales/log/${lang}.json`), that.destinationPath(`client/public/locales/${lang}/log.json`));
162
+ that.fs.copyTpl(that.templatePath(`../../client/templates/react/public/locales/audit/${lang}.json`), that.destinationPath(`client/public/locales/${lang}/audit.json`));
163
+ that.fs.copyTpl(that.templatePath(`../../client/templates/react/public/locales/seeder/${lang}.json`), that.destinationPath(`client/public/locales/${lang}/seeder.json`));
164
+ that.fs.copyTpl(that.templatePath(`../../client/templates/react/public/locales/migrations/${lang}.json`), that.destinationPath(`client/public/locales/${lang}/migrations.json`));
165
+ that.fs.copyTpl(that.templatePath(`../../client/templates/react/public/locales/common/${lang}.json.ejs`), that.destinationPath(`client/public/locales/${lang}/common.json`), { appName });
158
166
  if (!['null', 'database'].includes(searchEngine)) {
159
- that.fs.copyTpl(that.templatePath(`react/public/locales/searchReindex/${lang}.json`), that.destinationPath(`client/public/locales/${lang}/searchReindex.json`));
167
+ that.fs.copyTpl(that.templatePath(`../../client/templates/react/public/locales/searchReindex/${lang}.json`), that.destinationPath(`client/public/locales/${lang}/searchReindex.json`));
160
168
  }
161
- that.fs.copyTpl(that.templatePath(`react/public/locales/entities/entities.json.ejs`), that.destinationPath(`client/public/locales/${lang}/entities.json`), {
169
+ that.fs.copyTpl(that.templatePath(`../../client/templates/react/public/locales/locking/${lang}.json`), that.destinationPath(`client/public/locales/${lang}/locking.json`));
170
+ that.fs.copyTpl(that.templatePath(`../../client/templates/react/public/locales/entities/entities.json.ejs`), that.destinationPath(`client/public/locales/${lang}/entities.json`), {
162
171
  entities: [AcRule],
163
172
  relationships: [],
164
173
  to,
@@ -167,137 +176,141 @@ export async function createReactClient(that) {
167
176
  getModelRelatedEntities
168
177
  });
169
178
  };
170
- that.fs.copyTpl(that.templatePath("react/public/fonts/material-symbols-outlined.woff2"), that.destinationPath(`client/public/fonts/material-symbols-outlined.woff2`));
171
- that.fs.copyTpl(that.templatePath("react/public/fonts/material-symbols-rounded.woff2"), that.destinationPath(`client/public/fonts/material-symbols-rounded.woff2`));
172
- that.fs.copyTpl(that.templatePath("react/public/fonts/material-symbols-sharp.woff2"), that.destinationPath(`client/public/fonts/material-symbols-sharp.woff2`));
173
- that.fs.copyTpl(that.templatePath("react/public/fonts/IBMPlexMono-Regular.ttf"), that.destinationPath(`client/public/fonts/IBMPlexMono-Regular.ttf`));
174
- that.fs.copyTpl(that.templatePath("react/public/fonts/InterVariable-Italic.woff2"), that.destinationPath(`client/public/fonts/InterVariable-Italic.woff2`));
175
- that.fs.copyTpl(that.templatePath("react/public/fonts/InterVariable.woff2"), that.destinationPath(`client/public/fonts/InterVariable.woff2`));
179
+ that.fs.copy(that.templatePath("../../client/templates/react/public/fonts"), that.destinationPath("client/public/fonts"));
180
+ that.fs.copy(that.templatePath("../../client/templates/react/public/wordlists"), that.destinationPath("client/public/wordlists"));
176
181
 
177
- that.fs.copyTpl(that.templatePath("react/src/App.css.ejs"), that.destinationPath(`client/src/App.css`), {});
178
- that.fs.copyTpl(that.templatePath("react/src/App.tsx.ejs"), that.destinationPath(`client/src/App.tsx`), { entities: [AcRule], to, pluralize, searchEngine });
179
- that.fs.copyTpl(that.templatePath("react/src/i18n.js.ejs"), that.destinationPath(`client/src/i18n.js`), {
182
+ that.fs.copyTpl(that.templatePath("../../client/templates/react/src/App.css.ejs"), that.destinationPath(`client/src/App.css`), {});
183
+ that.fs.copyTpl(that.templatePath("../../client/templates/react/src/App.tsx.ejs"), that.destinationPath(`client/src/App.tsx`), { entities: [AcRule], to, pluralize, searchEngine });
184
+ that.fs.copyTpl(that.templatePath("../../client/templates/react/src/i18n.js.ejs"), that.destinationPath(`client/src/i18n.js`), {
180
185
  supportedLngs: JSON.stringify(languages).replaceAll(`"`, `'`),
181
186
  fallbackLng: nativeLanguage,
182
- searchEngine
187
+ searchEngine,
183
188
  });
184
- that.fs.copyTpl(that.templatePath("react/src/index.css.ejs"), that.destinationPath(`client/src/index.css`), { navbarStartcolor });
185
- that.fs.copyTpl(that.templatePath("react/src/main.tsx.ejs"), that.destinationPath(`client/src/main.tsx`), {});
189
+ that.fs.copyTpl(that.templatePath("../../client/templates/react/src/index.css.ejs"), that.destinationPath(`client/src/index.css`), { navbarStartcolor });
190
+ that.fs.copyTpl(that.templatePath("../../client/templates/react/src/main.tsx.ejs"), that.destinationPath(`client/src/main.tsx`), {});
186
191
 
187
- that.fs.copyTpl(that.templatePath("assets/icon.png"), that.destinationPath(`client/public/icon.png`));
188
- that.fs.copyTpl(that.templatePath("assets/icon.svg"), that.destinationPath(`client/public/icon.svg`));
189
- that.fs.copyTpl(that.templatePath("assets/algolia-logo.svg"), that.destinationPath(`client/src/assets/algolia-logo.svg`));
190
- that.fs.copyTpl(that.templatePath("assets/elastic-logo.svg"), that.destinationPath(`client/src/assets/elastic-logo.svg`));
191
- that.fs.copyTpl(that.templatePath("assets/laravel-logo.svg"), that.destinationPath(`client/src/assets/laravel-logo.svg`));
192
- that.fs.copyTpl(that.templatePath("assets/logo.svg"), that.destinationPath(`client/src/assets/logo.svg`));
193
- that.fs.copyTpl(that.templatePath("assets/mariadb-logo.svg"), that.destinationPath(`client/src/assets/mariadb-logo.svg`));
194
- that.fs.copyTpl(that.templatePath("assets/meilisearch-logo.svg"), that.destinationPath(`client/src/assets/meilisearch-logo.svg`));
195
- that.fs.copyTpl(that.templatePath("assets/mysql-logo.svg"), that.destinationPath(`client/src/assets/mysql-logo.svg`));
196
- that.fs.copyTpl(that.templatePath("assets/pgsql-logo.svg"), that.destinationPath(`client/src/assets/pgsql-logo.svg`));
197
- that.fs.copyTpl(that.templatePath("assets/pninja-logo-dark.svg"), that.destinationPath(`client/src/assets/pninja-logo-dark.svg`));
198
- that.fs.copyTpl(that.templatePath("assets/pninja-logo-light.svg"), that.destinationPath(`client/src/assets/pninja-logo-light.svg`));
199
- that.fs.copyTpl(that.templatePath("assets/react.svg"), that.destinationPath(`client/src/assets/react.svg`));
200
- that.fs.copyTpl(that.templatePath("assets/solr-logo.svg"), that.destinationPath(`client/src/assets/solr-logo.svg`));
201
- that.fs.copyTpl(that.templatePath("assets/sqlite-logo.svg"), that.destinationPath(`client/src/assets/sqlite-logo.svg`));
202
- that.fs.copyTpl(that.templatePath("assets/typesense-logo.svg"), that.destinationPath(`client/src/assets/typesense-logo.svg`));
203
- that.fs.copyTpl(that.templatePath("assets/vite.svg"), that.destinationPath(`client/src/assets/vite.svg`));
204
- that.fs.copyTpl(that.templatePath("assets/vue.svg"), that.destinationPath(`client/src/assets/vue.svg`));
192
+ that.fs.copyTpl(that.templatePath("../../client/templates/assets/icon.png"), that.destinationPath(`client/public/icon.png`));
193
+ that.fs.copyTpl(that.templatePath("../../client/templates/assets/icon.svg"), that.destinationPath(`client/public/icon.svg`));
194
+ that.fs.copyTpl(that.templatePath("../../client/templates/assets/algolia-logo.svg"), that.destinationPath(`client/src/assets/algolia-logo.svg`));
195
+ that.fs.copyTpl(that.templatePath("../../client/templates/assets/elastic-logo.svg"), that.destinationPath(`client/src/assets/elastic-logo.svg`));
196
+ that.fs.copyTpl(that.templatePath("../../client/templates/assets/laravel-logo.svg"), that.destinationPath(`client/src/assets/laravel-logo.svg`));
197
+ that.fs.copyTpl(that.templatePath("../../client/templates/assets/logo.svg"), that.destinationPath(`client/src/assets/logo.svg`));
198
+ that.fs.copyTpl(that.templatePath("../../client/templates/assets/mariadb-logo.svg"), that.destinationPath(`client/src/assets/mariadb-logo.svg`));
199
+ that.fs.copyTpl(that.templatePath("../../client/templates/assets/meilisearch-logo.svg"), that.destinationPath(`client/src/assets/meilisearch-logo.svg`));
200
+ that.fs.copyTpl(that.templatePath("../../client/templates/assets/mysql-logo.svg"), that.destinationPath(`client/src/assets/mysql-logo.svg`));
201
+ that.fs.copyTpl(that.templatePath("../../client/templates/assets/pgsql-logo.svg"), that.destinationPath(`client/src/assets/pgsql-logo.svg`));
202
+ that.fs.copyTpl(that.templatePath("../../client/templates/assets/pninja-logo-dark.svg"), that.destinationPath(`client/src/assets/pninja-logo-dark.svg`));
203
+ that.fs.copyTpl(that.templatePath("../../client/templates/assets/pninja-logo-light.svg"), that.destinationPath(`client/src/assets/pninja-logo-light.svg`));
204
+ that.fs.copyTpl(that.templatePath("../../client/templates/assets/react.svg"), that.destinationPath(`client/src/assets/react.svg`));
205
+ that.fs.copyTpl(that.templatePath("../../client/templates/assets/solr-logo.svg"), that.destinationPath(`client/src/assets/solr-logo.svg`));
206
+ that.fs.copyTpl(that.templatePath("../../client/templates/assets/sqlite-logo.svg"), that.destinationPath(`client/src/assets/sqlite-logo.svg`));
207
+ that.fs.copyTpl(that.templatePath("../../client/templates/assets/typesense-logo.svg"), that.destinationPath(`client/src/assets/typesense-logo.svg`));
208
+ that.fs.copyTpl(that.templatePath("../../client/templates/assets/vite.svg"), that.destinationPath(`client/src/assets/vite.svg`));
209
+ that.fs.copyTpl(that.templatePath("../../client/templates/assets/vue.svg"), that.destinationPath(`client/src/assets/vue.svg`));
205
210
 
206
- that.fs.copyTpl(that.templatePath("react/src/components/ApiResponsePagination.tsx.ejs"), that.destinationPath(`client/src/components/ApiResponsePagination.tsx`), {});
207
- that.fs.copyTpl(that.templatePath("react/src/components/Can.tsx.ejs"), that.destinationPath(`client/src/components/Can.tsx`), {});
208
- that.fs.copyTpl(that.templatePath("react/src/components/ConfirmButton.tsx.ejs"), that.destinationPath(`client/src/components/ConfirmButton.tsx`), {});
209
- that.fs.copyTpl(that.templatePath("react/src/components/DarkModeToggle.tsx.ejs"), that.destinationPath(`client/src/components/DarkModeToggle.tsx`), { to });
210
- that.fs.copyTpl(that.templatePath("react/src/components/Footer.tsx.ejs"), that.destinationPath(`client/src/components/Footer.tsx`), {});
211
- that.fs.copyTpl(that.templatePath("react/src/components/formElements/index.ts.ejs"), that.destinationPath(`client/src/components/formElements/index.ts`), {});
212
- that.fs.copyTpl(that.templatePath("react/src/components/formElements/Checkbox.tsx.ejs"), that.destinationPath(`client/src/components/formElements/Checkbox.tsx`), {});
213
- that.fs.copyTpl(that.templatePath("react/src/components/formElements/ColorField.tsx.ejs"), that.destinationPath(`client/src/components/formElements/ColorField.tsx`), {});
214
- that.fs.copyTpl(that.templatePath("react/src/components/formElements/DateField.tsx.ejs"), that.destinationPath(`client/src/components/formElements/DateField.tsx`), {});
215
- that.fs.copyTpl(that.templatePath("react/src/components/formElements/DateTimeField.tsx.ejs"), that.destinationPath(`client/src/components/formElements/DateTimeField.tsx`), {});
216
- that.fs.copyTpl(that.templatePath("react/src/components/formElements/DurationField.tsx.ejs"), that.destinationPath(`client/src/components/formElements/DurationField.tsx`), {});
217
- that.fs.copyTpl(that.templatePath("react/src/components/formElements/EmailField.tsx.ejs"), that.destinationPath(`client/src/components/formElements/EmailField.tsx`), {});
218
- that.fs.copyTpl(that.templatePath("react/src/components/formElements/FileField.tsx.ejs"), that.destinationPath(`client/src/components/formElements/FileField.tsx`), {});
219
- that.fs.copyTpl(that.templatePath("react/src/components/formElements/FormErrors.tsx.ejs"), that.destinationPath(`client/src/components/formElements/FormErrors.tsx`), {});
220
- that.fs.copyTpl(that.templatePath("react/src/components/formElements/FormFieldInfo.tsx.ejs"), that.destinationPath(`client/src/components/formElements/FormFieldInfo.tsx`), {});
221
- that.fs.copyTpl(that.templatePath("react/src/components/formElements/FormLabel.tsx.ejs"), that.destinationPath(`client/src/components/formElements/FormLabel.tsx`), {});
222
- that.fs.copyTpl(that.templatePath("react/src/components/formElements/InfoValidations.tsx.ejs"), that.destinationPath(`client/src/components/formElements/InfoValidations.tsx`), {});
223
- that.fs.copyTpl(that.templatePath("react/src/components/formElements/NumberField.tsx.ejs"), that.destinationPath(`client/src/components/formElements/NumberField.tsx`), {});
224
- that.fs.copyTpl(that.templatePath("react/src/components/formElements/PasswordField.tsx.ejs"), that.destinationPath(`client/src/components/formElements/PasswordField.tsx`), {});
225
- that.fs.copyTpl(that.templatePath("react/src/components/formElements/RadioGroup.tsx.ejs"), that.destinationPath(`client/src/components/formElements/RadioGroup.tsx`), {});
226
- that.fs.copyTpl(that.templatePath("react/src/components/formElements/RangeField.tsx.ejs"), that.destinationPath(`client/src/components/formElements/RangeField.tsx`), {});
227
- that.fs.copyTpl(that.templatePath("react/src/components/formElements/SelectField.tsx.ejs"), that.destinationPath(`client/src/components/formElements/SelectField.tsx`), { searchEngine });
228
- that.fs.copyTpl(that.templatePath("react/src/components/formElements/TelField.tsx.ejs"), that.destinationPath(`client/src/components/formElements/TelField.tsx`), {});
229
- that.fs.copyTpl(that.templatePath("react/src/components/formElements/Textarea.tsx.ejs"), that.destinationPath(`client/src/components/formElements/Textarea.tsx`), {});
230
- that.fs.copyTpl(that.templatePath("react/src/components/formElements/Textarea.css"), that.destinationPath(`client/src/components/formElements/Textarea.css`), {});
231
- that.fs.copyTpl(that.templatePath("react/src/components/formElements/TextField.tsx.ejs"), that.destinationPath(`client/src/components/formElements/TextField.tsx`), {});
232
- that.fs.copyTpl(that.templatePath("react/src/components/formElements/TimeField.tsx.ejs"), that.destinationPath(`client/src/components/formElements/TimeField.tsx`), {});
233
- that.fs.copyTpl(that.templatePath("react/src/components/formElements/UrlField.tsx.ejs"), that.destinationPath(`client/src/components/formElements/UrlField.tsx`), {});
234
- that.fs.copyTpl(that.templatePath("react/src/components/formElements/UuidField.tsx.ejs"), that.destinationPath(`client/src/components/formElements/UuidField.tsx`), {});
235
- that.fs.copyTpl(that.templatePath("react/src/components/HtmlViewer.tsx.ejs"), that.destinationPath(`client/src/components/HtmlViewer.tsx`), {});
236
- that.fs.copyTpl(that.templatePath("react/src/components/Icon.tsx.ejs"), that.destinationPath(`client/src/components/Icon.tsx`), {});
237
- that.fs.copyTpl(that.templatePath("react/src/components/JsonPrint.tsx.ejs"), that.destinationPath(`client/src/components/JsonPrint.tsx`), {});
238
- that.fs.copyTpl(that.templatePath("react/src/components/LangSelect.tsx.ejs"), that.destinationPath(`client/src/components/LangSelect.tsx`), { to });
239
- that.fs.copyTpl(that.templatePath("react/src/components/LoginButton.tsx.ejs"), that.destinationPath(`client/src/components/LoginButton.tsx`), {});
240
- that.fs.copyTpl(that.templatePath("react/src/components/LogoutButton.tsx.ejs"), that.destinationPath(`client/src/components/LogoutButton.tsx`), {});
241
- that.fs.copyTpl(that.templatePath("react/src/components/Menu.tsx.ejs"), that.destinationPath(`client/src/components/Menu.tsx`), { appName, entities, to, pluralize, withLangSelect: languages.length > 1, searchEngine });
242
- that.fs.copyTpl(that.templatePath("react/src/components/LoginRedirector.tsx.ejs"), that.destinationPath(`client/src/components/LoginRedirector.tsx`));
243
- that.fs.copyTpl(that.templatePath("react/src/components/SearchInput.css"), that.destinationPath(`client/src/components/SearchInput.css`), {});
244
- that.fs.copyTpl(that.templatePath("react/src/components/SearchInput.tsx.ejs"), that.destinationPath(`client/src/components/SearchInput.tsx`), {});
245
- that.fs.copyTpl(that.templatePath("react/src/components/SimpleLoader.tsx.ejs"), that.destinationPath(`client/src/components/SimpleLoader.tsx`), {});
246
- that.fs.copyTpl(that.templatePath("react/src/components/TableSkeletonLoader.tsx.ejs"), that.destinationPath(`client/src/components/TableSkeletonLoader.tsx`), {});
247
- that.fs.copyTpl(that.templatePath("react/src/components/Toast.tsx.ejs"), that.destinationPath(`client/src/components/Toast.tsx`), {});
211
+ that.fs.copyTpl(that.templatePath("../../client/templates/react/src/components/ApiResponsePagination.tsx.ejs"), that.destinationPath(`client/src/components/ApiResponsePagination.tsx`), {});
212
+ that.fs.copyTpl(that.templatePath("../../client/templates/react/src/components/Can.tsx.ejs"), that.destinationPath(`client/src/components/Can.tsx`), {});
213
+ that.fs.copyTpl(that.templatePath("../../client/templates/react/src/components/ConfirmButton.tsx.ejs"), that.destinationPath(`client/src/components/ConfirmButton.tsx`), {});
214
+ that.fs.copyTpl(that.templatePath("../../client/templates/react/src/components/DarkModeToggle.tsx.ejs"), that.destinationPath(`client/src/components/DarkModeToggle.tsx`), { to });
215
+ that.fs.copyTpl(that.templatePath("../../client/templates/react/src/components/Footer.tsx.ejs"), that.destinationPath(`client/src/components/Footer.tsx`), {});
216
+ that.fs.copyTpl(that.templatePath("../../client/templates/react/src/components/formElements/index.ts.ejs"), that.destinationPath(`client/src/components/formElements/index.ts`), {});
217
+ that.fs.copyTpl(that.templatePath("../../client/templates/react/src/components/formElements/Checkbox.tsx.ejs"), that.destinationPath(`client/src/components/formElements/Checkbox.tsx`), {});
218
+ that.fs.copyTpl(that.templatePath("../../client/templates/react/src/components/formElements/ColorField.tsx.ejs"), that.destinationPath(`client/src/components/formElements/ColorField.tsx`), {});
219
+ that.fs.copyTpl(that.templatePath("../../client/templates/react/src/components/formElements/DateField.tsx.ejs"), that.destinationPath(`client/src/components/formElements/DateField.tsx`), {});
220
+ that.fs.copyTpl(that.templatePath("../../client/templates/react/src/components/formElements/DateTimeField.tsx.ejs"), that.destinationPath(`client/src/components/formElements/DateTimeField.tsx`), {});
221
+ that.fs.copyTpl(that.templatePath("../../client/templates/react/src/components/formElements/DurationField.tsx.ejs"), that.destinationPath(`client/src/components/formElements/DurationField.tsx`), {});
222
+ that.fs.copyTpl(that.templatePath("../../client/templates/react/src/components/formElements/EmailField.tsx.ejs"), that.destinationPath(`client/src/components/formElements/EmailField.tsx`), {});
223
+ that.fs.copyTpl(that.templatePath("../../client/templates/react/src/components/formElements/FileField.tsx.ejs"), that.destinationPath(`client/src/components/formElements/FileField.tsx`), {});
224
+ that.fs.copyTpl(that.templatePath("../../client/templates/react/src/components/formElements/FormErrors.tsx.ejs"), that.destinationPath(`client/src/components/formElements/FormErrors.tsx`), {});
225
+ that.fs.copyTpl(that.templatePath("../../client/templates/react/src/components/formElements/FormFieldInfo.tsx.ejs"), that.destinationPath(`client/src/components/formElements/FormFieldInfo.tsx`), {});
226
+ that.fs.copyTpl(that.templatePath("../../client/templates/react/src/components/formElements/FormLabel.tsx.ejs"), that.destinationPath(`client/src/components/formElements/FormLabel.tsx`), {});
227
+ that.fs.copyTpl(that.templatePath("../../client/templates/react/src/components/formElements/InfoValidations.tsx.ejs"), that.destinationPath(`client/src/components/formElements/InfoValidations.tsx`), {});
228
+ that.fs.copyTpl(that.templatePath("../../client/templates/react/src/components/formElements/NumberField.tsx.ejs"), that.destinationPath(`client/src/components/formElements/NumberField.tsx`), {});
229
+ that.fs.copyTpl(that.templatePath("../../client/templates/react/src/components/formElements/PasswordField.tsx.ejs"), that.destinationPath(`client/src/components/formElements/PasswordField.tsx`), {});
230
+ that.fs.copyTpl(that.templatePath("../../client/templates/react/src/components/formElements/RadioGroup.tsx.ejs"), that.destinationPath(`client/src/components/formElements/RadioGroup.tsx`), {});
231
+ that.fs.copyTpl(that.templatePath("../../client/templates/react/src/components/formElements/RangeField.tsx.ejs"), that.destinationPath(`client/src/components/formElements/RangeField.tsx`), {});
232
+ that.fs.copyTpl(that.templatePath("../../client/templates/react/src/components/formElements/SelectField.tsx.ejs"), that.destinationPath(`client/src/components/formElements/SelectField.tsx`), { searchEngine });
233
+ that.fs.copyTpl(that.templatePath("../../client/templates/react/src/components/formElements/TelField.tsx.ejs"), that.destinationPath(`client/src/components/formElements/TelField.tsx`), {});
234
+ that.fs.copyTpl(that.templatePath("../../client/templates/react/src/components/formElements/Textarea.tsx.ejs"), that.destinationPath(`client/src/components/formElements/Textarea.tsx`), {});
235
+ that.fs.copyTpl(that.templatePath("../../client/templates/react/src/components/formElements/Textarea.css"), that.destinationPath(`client/src/components/formElements/Textarea.css`), {});
236
+ that.fs.copyTpl(that.templatePath("../../client/templates/react/src/components/formElements/TextField.tsx.ejs"), that.destinationPath(`client/src/components/formElements/TextField.tsx`), {});
237
+ that.fs.copyTpl(that.templatePath("../../client/templates/react/src/components/formElements/TimeField.tsx.ejs"), that.destinationPath(`client/src/components/formElements/TimeField.tsx`), {});
238
+ that.fs.copyTpl(that.templatePath("../../client/templates/react/src/components/formElements/UrlField.tsx.ejs"), that.destinationPath(`client/src/components/formElements/UrlField.tsx`), {});
239
+ that.fs.copyTpl(that.templatePath("../../client/templates/react/src/components/formElements/UuidField.tsx.ejs"), that.destinationPath(`client/src/components/formElements/UuidField.tsx`), {});
240
+ that.fs.copyTpl(that.templatePath("../../client/templates/react/src/components/HtmlViewer.tsx.ejs"), that.destinationPath(`client/src/components/HtmlViewer.tsx`), {});
241
+ that.fs.copyTpl(that.templatePath("../../client/templates/react/src/components/Icon.tsx.ejs"), that.destinationPath(`client/src/components/Icon.tsx`), {});
242
+ that.fs.copyTpl(that.templatePath("../../client/templates/react/src/components/JsonPrint.tsx.ejs"), that.destinationPath(`client/src/components/JsonPrint.tsx`), {});
243
+ that.fs.copyTpl(that.templatePath("../../client/templates/react/src/components/LangSelect.tsx.ejs"), that.destinationPath(`client/src/components/LangSelect.tsx`), { to });
244
+ that.fs.copyTpl(that.templatePath("../../client/templates/react/src/components/LoginButton.tsx.ejs"), that.destinationPath(`client/src/components/LoginButton.tsx`), {});
245
+ that.fs.copyTpl(that.templatePath("../../client/templates/react/src/components/LogoutButton.tsx.ejs"), that.destinationPath(`client/src/components/LogoutButton.tsx`), {});
246
+ that.fs.copyTpl(that.templatePath("../../client/templates/react/src/components/Menu.tsx.ejs"), that.destinationPath(`client/src/components/Menu.tsx`), { appName, entities, to, pluralize, withLangSelect: languages.length > 1, searchEngine });
247
+ that.fs.copyTpl(that.templatePath("../../client/templates/react/src/components/LoginRedirector.tsx.ejs"), that.destinationPath(`client/src/components/LoginRedirector.tsx`));
248
+ that.fs.copyTpl(that.templatePath("../../client/templates/react/src/components/SearchInput.css"), that.destinationPath(`client/src/components/SearchInput.css`), {});
249
+ that.fs.copyTpl(that.templatePath("../../client/templates/react/src/components/SearchInput.tsx.ejs"), that.destinationPath(`client/src/components/SearchInput.tsx`), {});
250
+ that.fs.copyTpl(that.templatePath("../../client/templates/react/src/components/SimpleLoader.tsx.ejs"), that.destinationPath(`client/src/components/SimpleLoader.tsx`), {});
251
+ that.fs.copyTpl(that.templatePath("../../client/templates/react/src/components/TableSkeletonLoader.tsx.ejs"), that.destinationPath(`client/src/components/TableSkeletonLoader.tsx`), {});
252
+ that.fs.copyTpl(that.templatePath("../../client/templates/react/src/components/Toast.tsx.ejs"), that.destinationPath(`client/src/components/Toast.tsx`));
253
+ that.fs.copyTpl(that.templatePath("../../client/templates/react/src/components/Tooltip.tsx.ejs"), that.destinationPath(`client/src/components/Tooltip.tsx`));
248
254
 
249
- that.fs.copyTpl(that.templatePath("react/src/config/languages.ts.ejs"), that.destinationPath(`client/src/config/languages.ts`), {
255
+ that.fs.copyTpl(that.templatePath("../../client/templates/react/src/config/languages.ts.ejs"), that.destinationPath(`client/src/config/languages.ts`), {
250
256
  languages: JSON.stringify(languages).replaceAll(`"`, `'`),
251
257
  languagesData: JSON.stringify(languages.map(lng => getLanguageData(lng)), null, 2)
252
258
  });
253
259
 
254
- that.fs.copyTpl(that.templatePath("react/src/contexts/AuthContext.tsx.ejs"), that.destinationPath(`client/src/contexts/AuthContext.tsx`));
255
- that.fs.copyTpl(that.templatePath("react/src/contexts/AuthorizationContext.tsx.ejs"), that.destinationPath(`client/src/contexts/AuthorizationContext.tsx`));
256
- that.fs.copyTpl(that.templatePath("react/src/contexts/AuthProvider.tsx.ejs"), that.destinationPath(`client/src/contexts/AuthProvider.tsx`));
257
- that.fs.copyTpl(that.templatePath("react/src/contexts/NotificationContext.tsx.ejs"), that.destinationPath(`client/src/contexts/NotificationContext.tsx`), {});
260
+ that.fs.copyTpl(that.templatePath("../../client/templates/react/src/contexts/AuthContext.tsx.ejs"), that.destinationPath(`client/src/contexts/AuthContext.tsx`));
261
+ that.fs.copyTpl(that.templatePath("../../client/templates/react/src/contexts/AuthorizationContext.tsx.ejs"), that.destinationPath(`client/src/contexts/AuthorizationContext.tsx`));
262
+ that.fs.copyTpl(that.templatePath("../../client/templates/react/src/contexts/AuthProvider.tsx.ejs"), that.destinationPath(`client/src/contexts/AuthProvider.tsx`));
263
+ that.fs.copyTpl(that.templatePath("../../client/templates/react/src/contexts/NotificationContext.tsx.ejs"), that.destinationPath(`client/src/contexts/NotificationContext.tsx`), {});
258
264
 
259
- that.fs.copyTpl(that.templatePath("react/src/pages/Home.tsx.ejs"), that.destinationPath(`client/src/pages/Home.tsx`), {
265
+ that.fs.copyTpl(that.templatePath("../../client/templates/react/src/pages/Home.tsx.ejs"), that.destinationPath(`client/src/pages/Home.tsx`), {
260
266
  dbms: that.config.get('dbms'),
261
267
  searchEngine: that.config.get('searchEngine')
262
268
  });
263
- that.fs.copyTpl(that.templatePath("react/src/pages/Login.tsx.ejs"), that.destinationPath(`client/src/pages/Login.tsx`));
264
- that.fs.copyTpl(that.templatePath("react/src/pages/Logout.tsx.ejs"), that.destinationPath(`client/src/pages/Logout.tsx`));
269
+ that.fs.copyTpl(that.templatePath("../../client/templates/react/src/pages/Login.tsx.ejs"), that.destinationPath(`client/src/pages/Login.tsx`));
270
+ that.fs.copyTpl(that.templatePath("../../client/templates/react/src/pages/Logout.tsx.ejs"), that.destinationPath(`client/src/pages/Logout.tsx`));
265
271
 
266
- that.fs.copyTpl(that.templatePath("react/src/pages/errors/Err403.tsx.ejs"), that.destinationPath(`client/src/pages/errors/Err403.tsx`), {});
267
- that.fs.copyTpl(that.templatePath("react/src/pages/errors/Err404.tsx.ejs"), that.destinationPath(`client/src/pages/errors/Err404.tsx`), {});
272
+ that.fs.copyTpl(that.templatePath("../../client/templates/react/src/pages/errors/Err403.tsx.ejs"), that.destinationPath(`client/src/pages/errors/Err403.tsx`), {});
273
+ that.fs.copyTpl(that.templatePath("../../client/templates/react/src/pages/errors/Err404.tsx.ejs"), that.destinationPath(`client/src/pages/errors/Err404.tsx`), {});
268
274
 
269
- that.fs.copyTpl(that.templatePath("react/src/pages/seeder/SeederList.tsx.ejs"), that.destinationPath(`client/src/pages/seeder/SeederList.tsx`));
275
+ that.fs.copyTpl(that.templatePath("../../client/templates/react/src/pages/admin/Seeder.tsx.ejs"), that.destinationPath(`client/src/pages/admin/Seeder.tsx`));
270
276
 
271
- that.fs.copyTpl(that.templatePath("react/src/pages/admin/Migrations.tsx.ejs"), that.destinationPath(`client/src/pages/admin/Migrations.tsx`));
277
+ that.fs.copyTpl(that.templatePath("../../client/templates/react/src/pages/admin/Migrations.tsx.ejs"), that.destinationPath(`client/src/pages/admin/Migrations.tsx`));
272
278
 
273
279
  if (!['null', 'database'].includes(searchEngine)) {
274
- that.fs.copyTpl(that.templatePath("react/src/pages/search-reindex/SearchReindexList.tsx.ejs"), that.destinationPath(`client/src/pages/search-reindex/SearchReindexList.tsx`), { searchEngine });
280
+ that.fs.copyTpl(that.templatePath("../../client/templates/react/src/pages/admin/SearchReindex.tsx.ejs"), that.destinationPath(`client/src/pages/admin/SearchReindex.tsx`), { searchEngine });
275
281
  }
276
282
 
277
- that.fs.copyTpl(that.templatePath("react/src/pages/server-logs/LogViewer.tsx.ejs"), that.destinationPath(`client/src/pages/server-logs/LogViewer.tsx`), {});
283
+ that.fs.copyTpl(that.templatePath("../../client/templates/react/src/pages/admin/Logs.tsx.ejs"), that.destinationPath(`client/src/pages/admin/Logs.tsx`), {});
284
+
285
+ that.fs.copyTpl(that.templatePath("../../client/templates/react/src/pages/support/ApiDocs.tsx.ejs"), that.destinationPath(`client/src/pages/support/ApiDocs.tsx`), {});
278
286
 
279
- that.fs.copyTpl(that.templatePath("react/src/hooks/useAuthState.ts.ejs"), that.destinationPath(`client/src/hooks/useAuthState.ts`), {});
280
- that.fs.copyTpl(that.templatePath("react/src/hooks/useAutoShortcuts.tsx.ejs"), that.destinationPath(`client/src/hooks/useAutoShortcuts.tsx`), {});
281
- that.fs.copyTpl(that.templatePath("react/src/hooks/useRoles.ts.ejs"), that.destinationPath(`client/src/hooks/useRoles.ts`), {});
287
+ that.fs.copyTpl(that.templatePath("../../client/templates/react/src/hooks/useAuthState.ts.ejs"), that.destinationPath(`client/src/hooks/useAuthState.ts`), {});
288
+ that.fs.copyTpl(that.templatePath("../../client/templates/react/src/hooks/useAutoShortcuts.tsx.ejs"), that.destinationPath(`client/src/hooks/useAutoShortcuts.tsx`), {});
289
+ that.fs.copyTpl(that.templatePath("../../client/templates/react/src/hooks/useRoles.ts.ejs"), that.destinationPath(`client/src/hooks/useRoles.ts`), {});
282
290
 
283
- that.fs.copyTpl(that.templatePath("react/src/shared/axiosInstance.ts.ejs"), that.destinationPath(`client/src/shared/axiosInstance.ts`));
284
- that.fs.copyTpl(that.templatePath("react/src/shared/axiosInterceptors.ts.ejs"), that.destinationPath(`client/src/shared/axiosInterceptors.ts`));
285
- that.fs.copyTpl(that.templatePath("react/src/shared/entitiesIcons.tsx.ejs"), that.destinationPath(`client/src/shared/entitiesIcons.tsx`), { entities });
286
- that.fs.copyTpl(that.templatePath("react/src/shared/model/ac-rule.model.ts.ejs"), that.destinationPath(`client/src/shared/model/ac-rule.model.ts`));
291
+ that.fs.copyTpl(that.templatePath("../../client/templates/react/src/shared/axiosInstance.ts.ejs"), that.destinationPath(`client/src/shared/axiosInstance.ts`));
292
+ that.fs.copyTpl(that.templatePath("../../client/templates/react/src/shared/axiosInterceptors.ts.ejs"), that.destinationPath(`client/src/shared/axiosInterceptors.ts`));
293
+ that.fs.copyTpl(that.templatePath("../../client/templates/react/src/shared/entitiesIcons.tsx.ejs"), that.destinationPath(`client/src/shared/entitiesIcons.tsx`), { entities });
294
+ that.fs.copyTpl(that.templatePath("../../client/templates/react/src/shared/model/ac-rule.model.ts.ejs"), that.destinationPath(`client/src/shared/model/ac-rule.model.ts`));
287
295
 
288
- that.fs.copyTpl(that.templatePath("react/src/pages/audit/Audits.tsx.ejs"), that.destinationPath(`client/src/pages/audit/Audits.tsx`));
289
- that.fs.copyTpl(that.templatePath("react/src/pages/audit/AuditHistory.tsx.ejs"), that.destinationPath(`client/src/pages/audit/AuditHistory.tsx`));
290
- that.fs.copyTpl(that.templatePath("react/src/pages/audit/AuditList.tsx.ejs"), that.destinationPath(`client/src/pages/audit/AuditList.tsx`));
291
- that.fs.copyTpl(that.templatePath("react/src/pages/audit/AuditStatistics.tsx.ejs"), that.destinationPath(`client/src/pages/audit/AuditStatistics.tsx`));
292
- that.fs.copyTpl(that.templatePath("react/src/pages/audit/AuditUserActivity.tsx.ejs"), that.destinationPath(`client/src/pages/audit/AuditUserActivity.tsx`));
293
- that.fs.copyTpl(that.templatePath("react/src/pages/audit/AuditView.tsx.ejs"), that.destinationPath(`client/src/pages/audit/AuditView.tsx`));
296
+ that.fs.copyTpl(that.templatePath("../../client/templates/react/src/pages/admin/audit/index.ts.ejs"), that.destinationPath(`client/src/pages/admin/audit/index.ts`));
297
+ that.fs.copyTpl(that.templatePath("../../client/templates/react/src/pages/admin/audit/Audits.tsx.ejs"), that.destinationPath(`client/src/pages/admin/audit/Audits.tsx`));
298
+ that.fs.copyTpl(that.templatePath("../../client/templates/react/src/pages/admin/audit/AuditHistory.tsx.ejs"), that.destinationPath(`client/src/pages/admin/audit/AuditHistory.tsx`));
299
+ that.fs.copyTpl(that.templatePath("../../client/templates/react/src/pages/admin/audit/AuditList.tsx.ejs"), that.destinationPath(`client/src/pages/admin/audit/AuditList.tsx`));
300
+ that.fs.copyTpl(that.templatePath("../../client/templates/react/src/pages/admin/audit/AuditStatistics.tsx.ejs"), that.destinationPath(`client/src/pages/admin/audit/AuditStatistics.tsx`));
301
+ that.fs.copyTpl(that.templatePath("../../client/templates/react/src/pages/admin/audit/AuditUserActivity.tsx.ejs"), that.destinationPath(`client/src/pages/admin/audit/AuditUserActivity.tsx`));
302
+ that.fs.copyTpl(that.templatePath("../../client/templates/react/src/pages/admin/audit/AuditView.tsx.ejs"), that.destinationPath(`client/src/pages/admin/audit/AuditView.tsx`));
294
303
 
295
304
  createEntityPages({ that, entity: AcRule, enums: [], relationships: [], searchEngine });
296
305
 
297
- that.fs.copyTpl(that.templatePath("react/src/types/api-response.types.ts.ejs"), that.destinationPath(`client/src/types/api-response.types.ts`));
298
- that.fs.copyTpl(that.templatePath("react/src/types/auth.ts.ejs"), that.destinationPath(`client/src/types/auth.ts`));
299
- that.fs.copyTpl(that.templatePath("react/src/types/authorization.ts.ejs"), that.destinationPath(`client/src/types/authorization.ts`));
306
+ that.fs.copyTpl(that.templatePath("../../client/templates/react/src/types/api-response.types.ts.ejs"), that.destinationPath(`client/src/types/api-response.types.ts`));
307
+ that.fs.copyTpl(that.templatePath("../../client/templates/react/src/types/auth.ts.ejs"), that.destinationPath(`client/src/types/auth.ts`));
308
+ that.fs.copyTpl(that.templatePath("../../client/templates/react/src/types/authorization.ts.ejs"), that.destinationPath(`client/src/types/authorization.ts`));
309
+
310
+ that.fs.copyTpl(that.templatePath("../../client/templates/blobs/dummy.pdf"), that.destinationPath(`server/database/factories/dummy.pdf`));
311
+ that.fs.copyTpl(that.templatePath("../../client/templates/blobs/dummy.png"), that.destinationPath(`server/database/factories/dummy.png`));
300
312
 
301
- that.fs.copyTpl(that.templatePath("blobs/dummy.pdf"), that.destinationPath(`server/database/factories/dummy.pdf`));
302
- that.fs.copyTpl(that.templatePath("blobs/dummy.png"), that.destinationPath(`server/database/factories/dummy.png`));
313
+ // Api Docs generation
314
+ const openApiGen = new OpenApiGenerator(that);
315
+ openApiGen.generateOpenApi([AcRule]);
303
316
  }