@devstroupe/devkit-cli 1.0.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 (170) hide show
  1. package/README.md +40 -0
  2. package/dist/boilerplates/angular-template/.dockerignore +4 -0
  3. package/dist/boilerplates/angular-template/.postcssrc.json +5 -0
  4. package/dist/boilerplates/angular-template/Dockerfile +14 -0
  5. package/dist/boilerplates/angular-template/angular.json +85 -0
  6. package/dist/boilerplates/angular-template/components.json +5 -0
  7. package/dist/boilerplates/angular-template/framework.code-workspace +7 -0
  8. package/dist/boilerplates/angular-template/nginx.conf +23 -0
  9. package/dist/boilerplates/angular-template/node_modules/.bin/browserslist +21 -0
  10. package/dist/boilerplates/angular-template/node_modules/.bin/jiti +21 -0
  11. package/dist/boilerplates/angular-template/node_modules/.bin/lessc +21 -0
  12. package/dist/boilerplates/angular-template/node_modules/.bin/ng +21 -0
  13. package/dist/boilerplates/angular-template/node_modules/.bin/ng-xi18n +21 -0
  14. package/dist/boilerplates/angular-template/node_modules/.bin/ngc +21 -0
  15. package/dist/boilerplates/angular-template/node_modules/.bin/sass +21 -0
  16. package/dist/boilerplates/angular-template/node_modules/.bin/terser +21 -0
  17. package/dist/boilerplates/angular-template/node_modules/.bin/tsc +21 -0
  18. package/dist/boilerplates/angular-template/node_modules/.bin/tsserver +21 -0
  19. package/dist/boilerplates/angular-template/node_modules/.bin/vite +21 -0
  20. package/dist/boilerplates/angular-template/node_modules/.bin/vitest +21 -0
  21. package/dist/boilerplates/angular-template/node_modules/.bin/yaml +21 -0
  22. package/dist/boilerplates/angular-template/package.json +47 -0
  23. package/dist/boilerplates/angular-template/postcss.config.js +5 -0
  24. package/dist/boilerplates/angular-template/proxy.conf.json +7 -0
  25. package/dist/boilerplates/angular-template/src/app/app.component.html +3 -0
  26. package/dist/boilerplates/angular-template/src/app/app.component.ts +12 -0
  27. package/dist/boilerplates/angular-template/src/app/app.config.ts +59 -0
  28. package/dist/boilerplates/angular-template/src/app/app.entity-routes.ts +4 -0
  29. package/dist/boilerplates/angular-template/src/app/app.routes.ts +25 -0
  30. package/dist/boilerplates/angular-template/src/app/core/guards/auth.guard.ts +16 -0
  31. package/dist/boilerplates/angular-template/src/app/core/services/auth.service.ts +98 -0
  32. package/dist/boilerplates/angular-template/src/app/modules/auth/login/login.component.html +51 -0
  33. package/dist/boilerplates/angular-template/src/app/modules/auth/login/login.component.ts +47 -0
  34. package/dist/boilerplates/angular-template/src/app/modules/auth/register/register.component.html +59 -0
  35. package/dist/boilerplates/angular-template/src/app/modules/auth/register/register.component.ts +47 -0
  36. package/dist/boilerplates/angular-template/src/app/modules/dashboard/dashboard.component.html +14 -0
  37. package/dist/boilerplates/angular-template/src/app/modules/dashboard/dashboard.component.ts +23 -0
  38. package/dist/boilerplates/angular-template/src/app/shared/interceptors/tenant.interceptor.ts +25 -0
  39. package/dist/boilerplates/angular-template/src/index.html +64 -0
  40. package/dist/boilerplates/angular-template/src/main.ts +6 -0
  41. package/dist/boilerplates/angular-template/src/styles.css +9 -0
  42. package/dist/boilerplates/angular-template/tsconfig.json +36 -0
  43. package/dist/boilerplates/nest-template/Dockerfile +16 -0
  44. package/dist/boilerplates/nest-template/node_modules/.bin/acorn +21 -0
  45. package/dist/boilerplates/nest-template/node_modules/.bin/nest +21 -0
  46. package/dist/boilerplates/nest-template/node_modules/.bin/prettier +21 -0
  47. package/dist/boilerplates/nest-template/node_modules/.bin/tsc +21 -0
  48. package/dist/boilerplates/nest-template/node_modules/.bin/tsserver +21 -0
  49. package/dist/boilerplates/nest-template/node_modules/.bin/typeorm +21 -0
  50. package/dist/boilerplates/nest-template/node_modules/.bin/typeorm-ts-node-commonjs +21 -0
  51. package/dist/boilerplates/nest-template/node_modules/.bin/typeorm-ts-node-esm +21 -0
  52. package/dist/boilerplates/nest-template/node_modules/.bin/webpack +21 -0
  53. package/dist/boilerplates/nest-template/package.json +43 -0
  54. package/dist/boilerplates/nest-template/src/app.module.ts +24 -0
  55. package/dist/boilerplates/nest-template/src/database/data-source.ts +16 -0
  56. package/dist/boilerplates/nest-template/src/database/migrations/1700000000000-create-users.ts +26 -0
  57. package/dist/boilerplates/nest-template/src/main.ts +46 -0
  58. package/dist/boilerplates/nest-template/src/modules/auth/auth.controller.ts +34 -0
  59. package/dist/boilerplates/nest-template/src/modules/auth/auth.module.ts +22 -0
  60. package/dist/boilerplates/nest-template/src/modules/auth/auth.service.ts +57 -0
  61. package/dist/boilerplates/nest-template/src/modules/auth/current-user.decorator.ts +8 -0
  62. package/dist/boilerplates/nest-template/src/modules/auth/jwt-auth.guard.ts +31 -0
  63. package/dist/boilerplates/nest-template/src/modules/auth/roles.decorator.ts +4 -0
  64. package/dist/boilerplates/nest-template/src/modules/auth/roles.guard.ts +24 -0
  65. package/dist/boilerplates/nest-template/src/modules/user/database-seed.service.ts +47 -0
  66. package/dist/boilerplates/nest-template/src/modules/user/domain/user.repository.ts +9 -0
  67. package/dist/boilerplates/nest-template/src/modules/user/domain/user.ts +9 -0
  68. package/dist/boilerplates/nest-template/src/modules/user/infra/database/user.orm-entity.ts +31 -0
  69. package/dist/boilerplates/nest-template/src/modules/user/infra/database/user.repository.adapter.ts +53 -0
  70. package/dist/boilerplates/nest-template/src/modules/user/service/user.service.ts +44 -0
  71. package/dist/boilerplates/nest-template/src/modules/user/user.module.ts +20 -0
  72. package/dist/boilerplates/nest-template/tsconfig.build.json +4 -0
  73. package/dist/boilerplates/nest-template/tsconfig.json +21 -0
  74. package/dist/index.d.ts +2 -0
  75. package/dist/index.js +1967 -0
  76. package/dist/migrations/sort-entities.d.ts +2 -0
  77. package/dist/migrations/sort-entities.js +30 -0
  78. package/dist/rules/linter-rules.d.ts +12 -0
  79. package/dist/rules/linter-rules.js +338 -0
  80. package/dist/rules/linter-rules.test.d.ts +1 -0
  81. package/dist/rules/linter-rules.test.js +214 -0
  82. package/dist/templates/angular/dialog-handler.template.d.ts +2 -0
  83. package/dist/templates/angular/dialog-handler.template.js +49 -0
  84. package/dist/templates/angular/form.template.d.ts +3 -0
  85. package/dist/templates/angular/form.template.js +453 -0
  86. package/dist/templates/angular/index.d.ts +4 -0
  87. package/dist/templates/angular/index.js +20 -0
  88. package/dist/templates/angular/list.template.d.ts +3 -0
  89. package/dist/templates/angular/list.template.js +213 -0
  90. package/dist/templates/angular/service.template.d.ts +1 -0
  91. package/dist/templates/angular/service.template.js +20 -0
  92. package/dist/templates/cli-templates.d.ts +2 -0
  93. package/dist/templates/cli-templates.js +18 -0
  94. package/dist/templates/nest/crud.templates.d.ts +9 -0
  95. package/dist/templates/nest/crud.templates.js +362 -0
  96. package/dist/templates/nest/index.d.ts +3 -0
  97. package/dist/templates/nest/index.js +19 -0
  98. package/dist/templates/nest/microservice.templates.d.ts +4 -0
  99. package/dist/templates/nest/microservice.templates.js +157 -0
  100. package/dist/templates/nest/migration.template.d.ts +3 -0
  101. package/dist/templates/nest/migration.template.js +127 -0
  102. package/dist/templates/relationship-templates.test.d.ts +1 -0
  103. package/dist/templates/relationship-templates.test.js +181 -0
  104. package/dist/templates/shared/names.d.ts +3 -0
  105. package/dist/templates/shared/names.js +14 -0
  106. package/dist/templates/shared/relationships.d.ts +27 -0
  107. package/dist/templates/shared/relationships.js +96 -0
  108. package/dist/templates/ui/components/avatar.template.d.ts +3 -0
  109. package/dist/templates/ui/components/avatar.template.js +66 -0
  110. package/dist/templates/ui/components/badge.template.d.ts +3 -0
  111. package/dist/templates/ui/components/badge.template.js +27 -0
  112. package/dist/templates/ui/components/button.template.d.ts +5 -0
  113. package/dist/templates/ui/components/button.template.js +64 -0
  114. package/dist/templates/ui/components/card-list.template.d.ts +5 -0
  115. package/dist/templates/ui/components/card-list.template.js +79 -0
  116. package/dist/templates/ui/components/dialog.template.d.ts +5 -0
  117. package/dist/templates/ui/components/dialog.template.js +51 -0
  118. package/dist/templates/ui/components/filter.template.d.ts +4 -0
  119. package/dist/templates/ui/components/filter.template.js +218 -0
  120. package/dist/templates/ui/components/index.d.ts +10 -0
  121. package/dist/templates/ui/components/index.js +26 -0
  122. package/dist/templates/ui/components/input.template.d.ts +4 -0
  123. package/dist/templates/ui/components/input.template.js +76 -0
  124. package/dist/templates/ui/components/select.template.d.ts +4 -0
  125. package/dist/templates/ui/components/select.template.js +176 -0
  126. package/dist/templates/ui/components/simple-list.template.d.ts +5 -0
  127. package/dist/templates/ui/components/simple-list.template.js +89 -0
  128. package/dist/templates/ui/components/table.template.d.ts +5 -0
  129. package/dist/templates/ui/components/table.template.js +112 -0
  130. package/dist/templates/ui/index.d.ts +9 -0
  131. package/dist/templates/ui/index.js +25 -0
  132. package/dist/templates/ui/layout/header.template.d.ts +5 -0
  133. package/dist/templates/ui/layout/header.template.js +236 -0
  134. package/dist/templates/ui/layout/index.d.ts +4 -0
  135. package/dist/templates/ui/layout/index.js +20 -0
  136. package/dist/templates/ui/layout/main-layout.template.d.ts +5 -0
  137. package/dist/templates/ui/layout/main-layout.template.js +126 -0
  138. package/dist/templates/ui/layout/shell.template.d.ts +5 -0
  139. package/dist/templates/ui/layout/shell.template.js +76 -0
  140. package/dist/templates/ui/layout/sidebar.template.d.ts +5 -0
  141. package/dist/templates/ui/layout/sidebar.template.js +412 -0
  142. package/dist/templates/ui/playground.template.d.ts +5 -0
  143. package/dist/templates/ui/playground.template.js +570 -0
  144. package/dist/templates/ui/readme.template.d.ts +1 -0
  145. package/dist/templates/ui/readme.template.js +23 -0
  146. package/dist/templates/ui/shared/colors.d.ts +1 -0
  147. package/dist/templates/ui/shared/colors.js +31 -0
  148. package/dist/templates/ui/shared/profile-component.template.d.ts +5 -0
  149. package/dist/templates/ui/shared/profile-component.template.js +403 -0
  150. package/dist/templates/ui/shared/profile-service.template.d.ts +1 -0
  151. package/dist/templates/ui/shared/profile-service.template.js +44 -0
  152. package/dist/templates/ui/shared/theme-service.template.d.ts +1 -0
  153. package/dist/templates/ui/shared/theme-service.template.js +47 -0
  154. package/dist/templates/ui/spartan/badge-directive.template.d.ts +3 -0
  155. package/dist/templates/ui/spartan/badge-directive.template.js +50 -0
  156. package/dist/templates/ui/spartan/button-directive.template.d.ts +3 -0
  157. package/dist/templates/ui/spartan/button-directive.template.js +82 -0
  158. package/dist/templates/ui/spartan/button-token.template.d.ts +3 -0
  159. package/dist/templates/ui/spartan/button-token.template.js +31 -0
  160. package/dist/templates/ui/spartan/hlm-core.template.d.ts +3 -0
  161. package/dist/templates/ui/spartan/hlm-core.template.js +322 -0
  162. package/dist/templates/ui/spartan/index.d.ts +5 -0
  163. package/dist/templates/ui/spartan/index.js +21 -0
  164. package/dist/templates/ui/spartan/input-directive.template.d.ts +3 -0
  165. package/dist/templates/ui/spartan/input-directive.template.js +31 -0
  166. package/dist/templates/ui/theme-css.template.d.ts +7 -0
  167. package/dist/templates/ui/theme-css.template.js +210 -0
  168. package/dist/templates/ui-templates.d.ts +1 -0
  169. package/dist/templates/ui-templates.js +17 -0
  170. package/package.json +50 -0
@@ -0,0 +1,3 @@
1
+ import { IDevkitEntityConfig, IDevkitEntityProperty } from '@devstroupe/devkit-core';
2
+ export declare function angularFormHtmlTemplate(name: string, properties: IDevkitEntityProperty[], entities?: IDevkitEntityConfig[]): string;
3
+ export declare function angularFormTsTemplate(name: string, properties: IDevkitEntityProperty[], entities?: IDevkitEntityConfig[]): string;
@@ -0,0 +1,453 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.angularFormHtmlTemplate = angularFormHtmlTemplate;
4
+ exports.angularFormTsTemplate = angularFormTsTemplate;
5
+ const names_1 = require("../shared/names");
6
+ const relationships_1 = require("../shared/relationships");
7
+ function relationStateName(relationship) {
8
+ return (0, names_1.kebabToCamel)(relationship.property.name);
9
+ }
10
+ function formControlName(property) {
11
+ if (property.type !== 'relationship')
12
+ return property.name;
13
+ const relationship = (0, relationships_1.getRelationships)([property])[0];
14
+ return relationship.kind === 'many-to-many'
15
+ ? relationship.relationName
16
+ : relationship.foreignKey ?? property.name;
17
+ }
18
+ function relationshipColumns(relationship, entities) {
19
+ const target = (0, relationships_1.getTargetEntity)(relationship, entities);
20
+ if (relationship.columns.length > 0) {
21
+ return relationship.columns.map((column) => ({
22
+ key: column.key,
23
+ label: column.label
24
+ ?? target?.properties.find((property) => property.name === column.key)?.label
25
+ ?? column.key,
26
+ }));
27
+ }
28
+ return (target?.properties ?? [])
29
+ .filter((property) => property.type !== 'relationship')
30
+ .slice(0, 4)
31
+ .map((property) => ({ key: property.name, label: property.label }));
32
+ }
33
+ function angularFormHtmlTemplate(name, properties, entities = []) {
34
+ const pascalName = (0, names_1.kebabToPascal)(name);
35
+ const relationships = (0, relationships_1.getRelationships)(properties);
36
+ const dependentRelationships = relationships.filter((relationship) => relationship.kind === 'one-to-many' && relationship.embedded);
37
+ const fields = properties
38
+ .filter((property) => property.type !== 'relationship' || (0, relationships_1.getRelationships)([property])[0].kind !== 'one-to-many')
39
+ .map((property) => {
40
+ const controlName = formControlName(property);
41
+ if (property.type === 'boolean') {
42
+ return ` <div *ngIf="!isFieldHidden('${controlName}')" class="flex items-center space-x-2 pt-2">
43
+ <input type="checkbox" formControlName="${controlName}" id="${controlName}" class="h-4 w-4 rounded border-input bg-background text-primary focus:ring-ring">
44
+ <label for="${controlName}" class="text-sm font-medium text-foreground">${property.label}</label>
45
+ </div>`;
46
+ }
47
+ if (property.type === 'relationship') {
48
+ const relationship = (0, relationships_1.getRelationships)([property])[0];
49
+ const stateName = relationStateName(relationship);
50
+ return ` <devkit-select
51
+ *ngIf="!isFieldHidden('${controlName}')"
52
+ formControlName="${controlName}"
53
+ label="${property.label}"
54
+ placeholder="Selecione ${property.label.toLowerCase()}"
55
+ [options]="${stateName}Lookup.options"
56
+ [multiple]="${relationship.kind === 'many-to-many'}"
57
+ [searchable]="${relationship.lookupMode === 'remote'}"
58
+ [loading]="${stateName}Lookup.loading"
59
+ [hasMore]="${stateName}Lookup.hasMore"
60
+ (searchChange)="${stateName}Lookup.setSearch($event)"
61
+ (loadMore)="${stateName}Lookup.loadMore()"
62
+ [required]="${Boolean(property.required)}">
63
+ </devkit-select>`;
64
+ }
65
+ const isNumber = property.type === 'number';
66
+ return ` <devkit-input
67
+ *ngIf="!isFieldHidden('${controlName}')"
68
+ ${isNumber ? 'type="number"' : ''}
69
+ formControlName="${controlName}"
70
+ label="${property.label}"
71
+ placeholder="Digite ${property.label.toLowerCase()}"
72
+ [required]="${Boolean(property.required)}">
73
+ </devkit-input>`;
74
+ })
75
+ .join('\n\n');
76
+ const dependentSections = dependentRelationships.map((relationship) => {
77
+ const stateName = relationStateName(relationship);
78
+ const relationPascal = (0, names_1.kebabToPascal)(stateName);
79
+ const component = relationship.control === 'card'
80
+ ? 'devkit-card-list'
81
+ : relationship.control === 'list'
82
+ ? 'devkit-simple-list'
83
+ : 'devkit-table';
84
+ return `
85
+ <section *ngIf="isEdit" class="border-t border-border pt-4 space-y-3">
86
+ <div class="flex items-center justify-between gap-3">
87
+ <h2 class="text-base font-semibold text-foreground">${relationship.property.label}</h2>
88
+ <devkit-button type="button" (btnClick)="openNew${relationPascal}()">Criar</devkit-button>
89
+ </div>
90
+ <${component}
91
+ [columns]="${stateName}Columns"
92
+ [items]="${stateName}Items"
93
+ (rowClick)="open${relationPascal}($event.id)"
94
+ ></${component}>
95
+ <div *ngIf="${stateName}TotalPages > 1" class="flex items-center justify-end gap-2">
96
+ <devkit-button variant="secondary" type="button" [disabled]="${stateName}Page <= 1 || ${stateName}Loading" (btnClick)="previous${relationPascal}Page()">Anterior</devkit-button>
97
+ <span class="text-sm text-muted-foreground">Página {{ ${stateName}Page }} de {{ ${stateName}TotalPages }}</span>
98
+ <devkit-button variant="secondary" type="button" [disabled]="${stateName}Page >= ${stateName}TotalPages || ${stateName}Loading" (btnClick)="next${relationPascal}Page()">Próxima</devkit-button>
99
+ </div>
100
+ </section>
101
+
102
+ <devkit-dialog size="xl" [isOpen]="${stateName}DialogOpen" (close)="close${relationPascal}Dialog()">
103
+ <app-${relationship.target}-form
104
+ [isDialog]="true"
105
+ [itemId]="${stateName}SelectedId"
106
+ [initialValues]="${stateName}InitialValues"
107
+ [hiddenFields]="['${relationship.foreignKey}']"
108
+ (saved)="on${relationPascal}Saved()"
109
+ (cancelled)="close${relationPascal}Dialog()"
110
+ ></app-${relationship.target}-form>
111
+ </devkit-dialog>`;
112
+ }).join('\n');
113
+ return `<div [class.${dependentRelationships.length > 0 ? 'max-w-5xl' : 'max-w-xl'}]="!isDialog" [class.mx-auto]="!isDialog" class="flex flex-col space-y-4 text-foreground">
114
+ <div>
115
+ <h1 class="text-2xl font-bold tracking-tight text-foreground">
116
+ {{ isEdit ? 'Editar' : 'Criar Novo' }} ${pascalName}
117
+ </h1>
118
+ </div>
119
+
120
+ <ng-container *ngIf="!isDialog; else formOrSkeleton">
121
+ <div hlmCard class="p-4">
122
+ <ng-container *ngTemplateOutlet="formOrSkeleton"></ng-container>
123
+ </div>
124
+ </ng-container>
125
+
126
+ <ng-template #formOrSkeleton>
127
+ <ng-container *ngIf="isFetching; else formTemplate">
128
+ <div class="space-y-4">
129
+ <div *ngFor="let item of [1, 2, 3]" class="space-y-2">
130
+ <hlm-skeleton class="h-4 w-1/4 rounded"></hlm-skeleton>
131
+ <hlm-skeleton class="h-10 w-full rounded-md"></hlm-skeleton>
132
+ </div>
133
+ </div>
134
+ </ng-container>
135
+ </ng-template>
136
+
137
+ <ng-template #formTemplate>
138
+ <form [formGroup]="form" (ngSubmit)="onSubmit()" class="flex flex-col space-y-4">
139
+ ${fields}
140
+
141
+ <div class="flex justify-end space-x-2 pt-4">
142
+ <devkit-button *ngIf="isEdit" variant="danger" type="button" [disabled]="loading" (btnClick)="deleteItem()">Excluir</devkit-button>
143
+ <span class="flex-1"></span>
144
+ <devkit-button variant="secondary" type="button" [disabled]="loading" (btnClick)="onCancel()">Cancelar</devkit-button>
145
+ <devkit-button type="submit" [disabled]="form.invalid || loading" [loading]="loading">Salvar</devkit-button>
146
+ </div>
147
+ </form>
148
+ ${dependentSections}
149
+ </ng-template>
150
+ </div>
151
+ `;
152
+ }
153
+ function angularFormTsTemplate(name, properties, entities = []) {
154
+ const pascalName = (0, names_1.kebabToPascal)(name);
155
+ const relationships = (0, relationships_1.getRelationships)(properties);
156
+ const optionRelationships = relationships.filter((relationship) => relationship.kind !== 'one-to-many');
157
+ const dependents = relationships.filter((relationship) => relationship.kind === 'one-to-many' && relationship.embedded);
158
+ const usesInput = properties.some((property) => property.type === 'string' || property.type === 'number' || property.type === 'datepicker');
159
+ const usesSelect = optionRelationships.length > 0;
160
+ const formGroupProps = properties
161
+ .filter((property) => property.type !== 'relationship' || (0, relationships_1.getRelationships)([property])[0].kind !== 'one-to-many')
162
+ .map((property) => {
163
+ const relationship = property.type === 'relationship' ? (0, relationships_1.getRelationships)([property])[0] : undefined;
164
+ const defaultValue = relationship?.kind === 'many-to-many'
165
+ ? '[]'
166
+ : property.type === 'boolean'
167
+ ? String(property.default ?? false)
168
+ : property.default !== undefined
169
+ ? JSON.stringify(property.default)
170
+ : "''";
171
+ const validators = property.required ? '[Validators.required]' : '[]';
172
+ return ` ${JSON.stringify(formControlName(property))}: [${defaultValue}, ${validators}]`;
173
+ })
174
+ .join(',\n');
175
+ const relatedTargets = [...new Set(relationships.map((relationship) => relationship.target))];
176
+ const serviceImports = relatedTargets
177
+ .map((target) => `import { ${(0, names_1.kebabToPascal)(target)}Service } from '../../../services/${target}.service';`)
178
+ .join('\n');
179
+ const dependentFormImports = [...new Set(dependents.map((relationship) => relationship.target))]
180
+ .map((target) => `import { ${(0, names_1.kebabToPascal)(target)}FormComponent } from '../../${target}/form/${target}-form.component';`)
181
+ .join('\n');
182
+ const relationServiceInjections = relationships.map((relationship) => {
183
+ const stateName = relationStateName(relationship);
184
+ return ` private ${stateName}Service = inject(${(0, names_1.kebabToPascal)(relationship.target)}Service);`;
185
+ }).join('\n');
186
+ const optionState = optionRelationships.map((relationship) => {
187
+ const stateName = relationStateName(relationship);
188
+ const filters = JSON.stringify(relationship.filters);
189
+ const limitOverride = relationship.lookupMode === 'all' ? `, limit: 'all'` : '';
190
+ return ` readonly ${stateName}Lookup = new RelationshipLookup<any>({
191
+ loader: (filter) => this.${stateName}Service.list({
192
+ ...filter${limitOverride},
193
+ filter: { ...(filter.filter ?? {}), ...${filters} }
194
+ }),
195
+ valueField: '${relationship.valueField}',
196
+ displayField: '${relationship.displayField}',
197
+ pageSize: ${relationship.pageSize},
198
+ minSearchLength: ${relationship.minSearchLength}
199
+ });`;
200
+ }).join('\n');
201
+ const dependentState = dependents.map((relationship) => {
202
+ const stateName = relationStateName(relationship);
203
+ const columns = relationshipColumns(relationship, entities);
204
+ return ` ${stateName}Items: any[] = [];
205
+ ${stateName}Columns: ITableColumn[] = ${JSON.stringify(columns)};
206
+ ${stateName}Page = 1;
207
+ ${stateName}TotalPages = 1;
208
+ ${stateName}Loading = false;
209
+ ${stateName}DialogOpen = false;
210
+ ${stateName}SelectedId?: number | string;`;
211
+ }).join('\n');
212
+ const optionLoadCalls = optionRelationships
213
+ .map((relationship) => ` this.${relationStateName(relationship)}Lookup.load();`)
214
+ .join('\n');
215
+ const dependentLoadCalls = dependents
216
+ .map((relationship) => ` this.load${(0, names_1.kebabToPascal)(relationStateName(relationship))}Items();`)
217
+ .join('\n');
218
+ const dependentMethods = dependents.map((relationship) => {
219
+ const stateName = relationStateName(relationship);
220
+ const methodName = (0, names_1.kebabToPascal)(stateName);
221
+ const configuredFilters = JSON.stringify(relationship.filters);
222
+ return ` private load${methodName}Items(): void {
223
+ if (!this.itemId) return;
224
+ this.${stateName}Loading = true;
225
+ this.${stateName}Service.list({
226
+ page: this.${stateName}Page,
227
+ limit: ${relationship.pageSize},
228
+ filter: { ...${configuredFilters}, ${relationship.foreignKey}: this.itemId }
229
+ }).subscribe({
230
+ next: (data: any) => {
231
+ this.${stateName}Items = data?.items ?? data?.data ?? data ?? [];
232
+ this.${stateName}TotalPages = Number(data?.meta?.totalPage ?? data?.meta?.totalPages ?? 1);
233
+ this.${stateName}Loading = false;
234
+ },
235
+ error: (err: any) => {
236
+ console.error('Erro ao carregar ${relationship.target}:', err);
237
+ this.${stateName}Loading = false;
238
+ }
239
+ });
240
+ }
241
+
242
+ previous${methodName}Page(): void {
243
+ if (this.${stateName}Page <= 1) return;
244
+ this.${stateName}Page--;
245
+ this.load${methodName}Items();
246
+ }
247
+
248
+ next${methodName}Page(): void {
249
+ if (this.${stateName}Page >= this.${stateName}TotalPages) return;
250
+ this.${stateName}Page++;
251
+ this.load${methodName}Items();
252
+ }
253
+
254
+ get ${stateName}InitialValues(): Record<string, any> {
255
+ return { ${relationship.foreignKey}: this.itemId };
256
+ }
257
+
258
+ openNew${methodName}(): void {
259
+ this.${stateName}SelectedId = undefined;
260
+ this.${stateName}DialogOpen = true;
261
+ }
262
+
263
+ open${methodName}(id: number | string): void {
264
+ this.${stateName}SelectedId = id;
265
+ this.${stateName}DialogOpen = true;
266
+ }
267
+
268
+ close${methodName}Dialog(): void {
269
+ this.${stateName}DialogOpen = false;
270
+ this.${stateName}SelectedId = undefined;
271
+ }
272
+
273
+ on${methodName}Saved(): void {
274
+ this.close${methodName}Dialog();
275
+ this.load${methodName}Items();
276
+ }`;
277
+ }).join('\n\n');
278
+ const relationPatchCode = optionRelationships
279
+ .map((relationship) => relationship.kind === 'many-to-many' ? `
280
+ if (Array.isArray(item.${relationship.relationName})) {
281
+ item.${relationship.relationName}.forEach((related: any) => this.${relationStateName(relationship)}Lookup.include(related));
282
+ item.${relationship.relationName} = item.${relationship.relationName}.map((related: any) =>
283
+ typeof related === 'object' ? related.${relationship.valueField} : related
284
+ );
285
+ }` : `
286
+ this.${relationStateName(relationship)}Lookup.include(item.${relationship.relationName});`)
287
+ .join('');
288
+ const optionDestroyCalls = optionRelationships
289
+ .map((relationship) => ` this.${relationStateName(relationship)}Lookup.destroy();`)
290
+ .join('\n');
291
+ const dependentImports = dependents.length > 0
292
+ ? `\nimport { DevkitDialogComponent } from '@devstroupe/ui/dialog/dialog.component';\nimport { ITableColumn } from '@devstroupe/ui/table/table.component';`
293
+ : '';
294
+ const listImports = [
295
+ dependents.some((relationship) => relationship.control !== 'list' && relationship.control !== 'card')
296
+ ? `import { DevkitTableComponent } from '@devstroupe/ui/table/table.component';`
297
+ : '',
298
+ dependents.some((relationship) => relationship.control === 'list')
299
+ ? `import { DevkitSimpleListComponent } from '@devstroupe/ui/simple-list/simple-list.component';`
300
+ : '',
301
+ dependents.some((relationship) => relationship.control === 'card')
302
+ ? `import { DevkitCardListComponent } from '@devstroupe/ui/card-list/card-list.component';`
303
+ : '',
304
+ ].filter(Boolean).join('\n');
305
+ const componentImports = [
306
+ ...dependents.map((relationship) => `${(0, names_1.kebabToPascal)(relationship.target)}FormComponent`),
307
+ ...(dependents.length > 0 ? ['DevkitDialogComponent'] : []),
308
+ ...(dependents.some((relationship) => relationship.control !== 'list' && relationship.control !== 'card') ? ['DevkitTableComponent'] : []),
309
+ ...(dependents.some((relationship) => relationship.control === 'list') ? ['DevkitSimpleListComponent'] : []),
310
+ ...(dependents.some((relationship) => relationship.control === 'card') ? ['DevkitCardListComponent'] : []),
311
+ ];
312
+ return `import { ChangeDetectorRef, Component, OnInit${optionRelationships.length > 0 ? ', OnDestroy' : ''}, inject, Input, Output, EventEmitter } from '@angular/core';
313
+ import { finalize } from 'rxjs';
314
+ import { CommonModule } from '@angular/common';
315
+ import { FormBuilder, FormGroup, Validators, ReactiveFormsModule } from '@angular/forms';
316
+ import { ActivatedRoute, Router } from '@angular/router';
317
+ ${usesInput ? "import { DevkitInputComponent } from '@devstroupe/ui/input/input.component';" : ''}
318
+ ${usesSelect ? "import { DevkitSelectComponent } from '@devstroupe/ui/select/select.component';" : ''}
319
+ import { DevkitButtonComponent } from '@devstroupe/ui/button/button.component';
320
+ import { HlmCardImports } from '@spartan-ng/helm/card';
321
+ import { HlmSkeletonImports } from '@spartan-ng/helm/skeleton';${dependentImports}
322
+ ${optionRelationships.length > 0 ? "import { RelationshipLookup } from '@devstroupe/devkit-angular';" : ''}
323
+ ${listImports}
324
+ ${serviceImports}
325
+ ${dependentFormImports}
326
+ import { ${pascalName}Service } from '../../../services/${name}.service';
327
+
328
+ @Component({
329
+ selector: 'app-${name}-form',
330
+ standalone: true,
331
+ imports: [CommonModule, ReactiveFormsModule${usesInput ? ', DevkitInputComponent' : ''}${usesSelect ? ', DevkitSelectComponent' : ''}, DevkitButtonComponent, HlmCardImports, HlmSkeletonImports${componentImports.map((item) => `, ${item}`).join('')}],
332
+ templateUrl: './${name}-form.component.html'
333
+ })
334
+ export class ${pascalName}FormComponent implements OnInit${optionRelationships.length > 0 ? ', OnDestroy' : ''} {
335
+ private fb = inject(FormBuilder);
336
+ private service = inject(${pascalName}Service);
337
+ private route = inject(ActivatedRoute);
338
+ private router = inject(Router);
339
+ private changeDetector = inject(ChangeDetectorRef);
340
+ ${relationServiceInjections}
341
+
342
+ @Input() isDialog = false;
343
+ @Input() itemId?: number | string;
344
+ @Input() initialValues: Record<string, any> = {};
345
+ @Input() hiddenFields: string[] = [];
346
+
347
+ @Output() saved = new EventEmitter<void>();
348
+ @Output() cancelled = new EventEmitter<void>();
349
+
350
+ form!: FormGroup;
351
+ isEdit = false;
352
+ isFetching = false;
353
+ loading = false;
354
+ ${optionState}
355
+ ${dependentState}
356
+
357
+ ngOnInit(): void {
358
+ this.initForm();
359
+ this.form.patchValue(this.initialValues);
360
+ this.checkEditMode();
361
+ ${optionLoadCalls}
362
+ }
363
+
364
+ ${optionRelationships.length > 0 ? ` ngOnDestroy(): void {
365
+ ${optionDestroyCalls}
366
+ }
367
+ ` : ''}
368
+
369
+ isFieldHidden(field: string): boolean {
370
+ return this.hiddenFields.includes(field);
371
+ }
372
+
373
+ private initForm(): void {
374
+ this.form = this.fb.group({
375
+ ${formGroupProps}
376
+ });
377
+ }
378
+
379
+ private checkEditMode(): void {
380
+ const id = this.isDialog ? this.itemId : this.route.snapshot.paramMap.get('id');
381
+ if (!id) return;
382
+
383
+ this.isEdit = true;
384
+ this.itemId = id;
385
+ this.isFetching = true;
386
+ this.service.findOne(id).pipe(
387
+ finalize(() => {
388
+ this.isFetching = false;
389
+ this.changeDetector.markForCheck();
390
+ })
391
+ ).subscribe({
392
+ next: (data: any) => {
393
+ const item = { ...(data?.data ?? data?.item ?? data) };${relationPatchCode}
394
+ this.form.patchValue({ ...item, ...this.initialValues });
395
+ ${dependentLoadCalls}
396
+ },
397
+ error: (err: any) => {
398
+ console.error('Erro ao buscar dados:', err);
399
+ }
400
+ });
401
+ }
402
+
403
+ onSubmit(): void {
404
+ if (this.form.invalid) return;
405
+
406
+ this.loading = true;
407
+ const payload = { ...this.form.getRawValue(), ...this.initialValues };
408
+ const request = this.isEdit
409
+ ? this.service.update(this.itemId!, payload)
410
+ : this.service.create(payload);
411
+
412
+ request.subscribe({
413
+ next: () => {
414
+ this.loading = false;
415
+ if (this.isDialog) this.saved.emit();
416
+ else this.navigateBack();
417
+ },
418
+ error: (err: any) => {
419
+ console.error('Erro ao salvar:', err);
420
+ this.loading = false;
421
+ }
422
+ });
423
+ }
424
+
425
+ onCancel(): void {
426
+ if (this.isDialog) this.cancelled.emit();
427
+ else this.navigateBack();
428
+ }
429
+
430
+ deleteItem(): void {
431
+ if (!this.itemId || !confirm('Tem certeza que deseja excluir este item?')) return;
432
+ this.loading = true;
433
+ this.service.delete(this.itemId).subscribe({
434
+ next: () => {
435
+ this.loading = false;
436
+ if (this.isDialog) this.saved.emit();
437
+ else this.navigateBack();
438
+ },
439
+ error: (err: any) => {
440
+ console.error('Erro ao excluir:', err);
441
+ this.loading = false;
442
+ }
443
+ });
444
+ }
445
+
446
+ private navigateBack(): void {
447
+ this.router.navigate(['../'], { relativeTo: this.route });
448
+ }
449
+
450
+ ${dependentMethods}
451
+ }
452
+ `;
453
+ }
@@ -0,0 +1,4 @@
1
+ export * from './service.template';
2
+ export * from './list.template';
3
+ export * from './form.template';
4
+ export * from './dialog-handler.template';
@@ -0,0 +1,20 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./service.template"), exports);
18
+ __exportStar(require("./list.template"), exports);
19
+ __exportStar(require("./form.template"), exports);
20
+ __exportStar(require("./dialog-handler.template"), exports);
@@ -0,0 +1,3 @@
1
+ import { IDevkitEntityProperty } from '@devstroupe/devkit-core';
2
+ export declare function angularListHtmlTemplate(name: string, properties: IDevkitEntityProperty[], listType?: string, formType?: string, filterType?: string): string;
3
+ export declare function angularListTsTemplate(name: string, properties: IDevkitEntityProperty[], listType?: string, formType?: string): string;