@khester/create-dynamics-app 1.0.8 → 1.1.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 (107) hide show
  1. package/bin/create-dynamics-app.js +1 -1
  2. package/dist/index.js +140 -15
  3. package/dist/index.js.map +1 -1
  4. package/dist/utils/consultingHelpers.d.ts +13 -0
  5. package/dist/utils/consultingHelpers.d.ts.map +1 -0
  6. package/dist/utils/consultingHelpers.js +569 -0
  7. package/dist/utils/consultingHelpers.js.map +1 -0
  8. package/dist/utils/copyTemplate.d.ts.map +1 -1
  9. package/dist/utils/copyTemplate.js.map +1 -1
  10. package/dist/utils/initGit.d.ts.map +1 -1
  11. package/dist/utils/initGit.js.map +1 -1
  12. package/dist/utils/installDependencies.d.ts.map +1 -1
  13. package/dist/utils/installDependencies.js +3 -2
  14. package/dist/utils/installDependencies.js.map +1 -1
  15. package/dist/utils/updatePackageJson.d.ts +1 -1
  16. package/dist/utils/updatePackageJson.d.ts.map +1 -1
  17. package/dist/utils/updatePackageJson.js +11 -1
  18. package/dist/utils/updatePackageJson.js.map +1 -1
  19. package/package.json +1 -1
  20. package/templates/dynamics-365-starter/INTEGRATION_TEST_RESULTS.md +302 -0
  21. package/templates/dynamics-365-starter/PHASE_4_COMPLETION_SUMMARY.md +305 -0
  22. package/templates/dynamics-365-starter/README.md +566 -137
  23. package/templates/dynamics-365-starter/deployment/QUICKSTART-MAC.md +507 -0
  24. package/templates/dynamics-365-starter/deployment/QUICKSTART-WINDOWS.md +372 -0
  25. package/templates/dynamics-365-starter/deployment/README.md +484 -0
  26. package/templates/dynamics-365-starter/deployment/pipelines/README.md +375 -0
  27. package/templates/dynamics-365-starter/deployment/pipelines/azure-pipelines.yml +330 -0
  28. package/templates/dynamics-365-starter/deployment/pipelines/github-actions.yml +422 -0
  29. package/templates/dynamics-365-starter/deployment/pipelines/jenkins.groovy +636 -0
  30. package/templates/dynamics-365-starter/deployment/scripts/deploy.ps1 +417 -0
  31. package/templates/dynamics-365-starter/deployment/scripts/deploy.sh +582 -0
  32. package/templates/dynamics-365-starter/deployment/scripts/team-onboarding.ps1 +486 -0
  33. package/templates/dynamics-365-starter/deployment/scripts/team-onboarding.sh +567 -0
  34. package/templates/dynamics-365-starter/deployment/scripts/validate-setup.ps1 +703 -0
  35. package/templates/dynamics-365-starter/deployment/scripts/validate-setup.sh +671 -0
  36. package/templates/dynamics-365-starter/docs/ARCHITECTURE_OVERVIEW.md +506 -0
  37. package/templates/dynamics-365-starter/docs/BEST_PRACTICES.md +723 -0
  38. package/templates/dynamics-365-starter/docs/MIGRATION_GUIDE.md +447 -0
  39. package/templates/dynamics-365-starter/docs/team-standards/README.md +273 -0
  40. package/templates/dynamics-365-starter/docs/team-standards/client-onboarding.md +577 -0
  41. package/templates/dynamics-365-starter/docs/team-standards/code-review-checklist.md +359 -0
  42. package/templates/dynamics-365-starter/docs/team-standards/coding-standards.md +700 -0
  43. package/templates/dynamics-365-starter/docs/team-standards/cross-platform-team-guide.md +736 -0
  44. package/templates/dynamics-365-starter/docs/team-standards/development-workflows.md +727 -0
  45. package/templates/dynamics-365-starter/docs/troubleshooting/common-errors.md +758 -0
  46. package/templates/dynamics-365-starter/docs/troubleshooting/platform-specific-issues.md +878 -0
  47. package/templates/dynamics-365-starter/package.json +22 -1
  48. package/templates/dynamics-365-starter/public/index.html +8 -11
  49. package/templates/dynamics-365-starter/scripts/custom-build.js +255 -0
  50. package/templates/dynamics-365-starter/src/client-project-template/README.md +234 -0
  51. package/templates/dynamics-365-starter/src/client-project-template/config/client.template.json +114 -0
  52. package/templates/dynamics-365-starter/src/client-project-template/config/environments/template.json +186 -0
  53. package/templates/dynamics-365-starter/src/client-project-template/scripts/client-setup.js +667 -0
  54. package/templates/dynamics-365-starter/src/components/AccountForm.css +71 -0
  55. package/templates/dynamics-365-starter/src/components/AccountForm.tsx +541 -0
  56. package/templates/dynamics-365-starter/src/components/AccountManagement.css +86 -0
  57. package/templates/dynamics-365-starter/src/components/AccountManagement.tsx +370 -0
  58. package/templates/dynamics-365-starter/src/components/ContactForm.tsx +149 -63
  59. package/templates/dynamics-365-starter/src/components/ContactManagement.tsx +153 -63
  60. package/templates/dynamics-365-starter/src/components/Logging/LogDialog.tsx +291 -0
  61. package/templates/dynamics-365-starter/src/components/Logging/LoggingContext.tsx +166 -0
  62. package/templates/dynamics-365-starter/src/components/Logging/LoggingDebugPanel.css +192 -0
  63. package/templates/dynamics-365-starter/src/components/Logging/LoggingDebugPanel.tsx +177 -0
  64. package/templates/dynamics-365-starter/src/components/Logging/LoggingProvider.tsx +3 -0
  65. package/templates/dynamics-365-starter/src/components/Logging/logger.ts +193 -0
  66. package/templates/dynamics-365-starter/src/constants/account.ts +410 -0
  67. package/templates/dynamics-365-starter/src/constants/contact.ts +362 -0
  68. package/templates/dynamics-365-starter/src/examples/README.md +52 -0
  69. package/templates/dynamics-365-starter/src/examples/component-examples/opportunity-management.tsx +625 -0
  70. package/templates/dynamics-365-starter/src/examples/entity-examples/opportunity-model.ts +545 -0
  71. package/templates/dynamics-365-starter/src/examples/integration-examples/custom-pcf-wrapper.tsx +722 -0
  72. package/templates/dynamics-365-starter/src/examples/workflow-examples/sales-workflow.ts +662 -0
  73. package/templates/dynamics-365-starter/src/index.tsx +107 -19
  74. package/templates/dynamics-365-starter/src/models/Account.ts +480 -0
  75. package/templates/dynamics-365-starter/src/models/BaseEntity.ts +204 -0
  76. package/templates/dynamics-365-starter/src/models/Contact.ts +580 -0
  77. package/templates/dynamics-365-starter/src/page-templates/EntityDashboard.tsx +519 -0
  78. package/templates/dynamics-365-starter/src/page-templates/EntityDetailPage.tsx +456 -0
  79. package/templates/dynamics-365-starter/src/page-templates/EntityListPage.tsx +406 -0
  80. package/templates/dynamics-365-starter/src/page-templates/RelatedEntitiesPage.tsx +578 -0
  81. package/templates/dynamics-365-starter/src/page-templates/SearchPage.tsx +629 -0
  82. package/templates/dynamics-365-starter/src/pcf/ContactControlWrapper.tsx +75 -22
  83. package/templates/dynamics-365-starter/src/pcf/MultiEntityControlWrapper.tsx +205 -0
  84. package/templates/dynamics-365-starter/src/providers/DynamicsProvider.tsx +297 -80
  85. package/templates/dynamics-365-starter/src/services/MockApiService.ts +260 -0
  86. package/templates/dynamics-365-starter/src/services/ServiceFactory.ts +65 -0
  87. package/templates/dynamics-365-starter/src/services/XrmApiService.ts +213 -0
  88. package/templates/dynamics-365-starter/src/styles/index.css +74 -7
  89. package/templates/dynamics-365-starter/tools/entity-generator/index.js +168 -0
  90. package/templates/dynamics-365-starter/tools/entity-generator/templates/constants.template.ts +124 -0
  91. package/templates/dynamics-365-starter/tools/entity-generator/templates/form.template.css +283 -0
  92. package/templates/dynamics-365-starter/tools/entity-generator/templates/form.template.tsx +275 -0
  93. package/templates/dynamics-365-starter/tools/entity-generator/templates/management.template.css +204 -0
  94. package/templates/dynamics-365-starter/tools/entity-generator/templates/management.template.tsx +413 -0
  95. package/templates/dynamics-365-starter/tools/entity-generator/templates/model.template.ts +250 -0
  96. package/templates/dynamics-365-starter/tools/metadata-sync/d365-client.js +410 -0
  97. package/templates/dynamics-365-starter/tools/metadata-sync/index.js +512 -0
  98. package/templates/dynamics-365-starter/tools/metadata-sync/type-generator.js +675 -0
  99. package/templates/dynamics-365-starter/tsconfig.json +11 -8
  100. package/templates/dynamics-365-starter/webpack.config.js +8 -9
  101. package/templates/power-pages-starter/README.md +7 -1
  102. package/templates/power-pages-starter/public/index.html +8 -11
  103. package/templates/power-pages-starter/src/components/ContactForm.tsx +60 -41
  104. package/templates/power-pages-starter/src/index.tsx +3 -3
  105. package/templates/power-pages-starter/src/providers/PowerPagesProvider.tsx +46 -23
  106. package/templates/power-pages-starter/tsconfig.json +3 -9
  107. package/templates/power-pages-starter/webpack.config.js +8 -3
@@ -0,0 +1,204 @@
1
+ import { IApiService } from '@khester/dynamics-ui-api-client';
2
+
3
+ /**
4
+ * Abstract base class for all entity models in the system.
5
+ * Provides common CRUD operations and validation patterns.
6
+ */
7
+ export abstract class BaseEntity {
8
+ /**
9
+ * Validates the entity instance.
10
+ * @returns True if valid, throws error if invalid
11
+ */
12
+ abstract validate(): boolean;
13
+
14
+ /**
15
+ * Creates a new entity record in Dynamics 365.
16
+ * @param apiService The API service instance
17
+ * @param entity The entity instance to create
18
+ * @param entityName The entity collection name
19
+ * @param loggerContext Optional logger context for debugging
20
+ * @returns Promise resolving to the created entity
21
+ */
22
+ protected static async createEntity<T extends BaseEntity>(
23
+ apiService: IApiService,
24
+ entity: T,
25
+ entityName: string,
26
+ loggerContext?: string
27
+ ): Promise<T> {
28
+ try {
29
+ entity.validate();
30
+
31
+ const result = await apiService.createRecord(entityName, entity);
32
+
33
+ if (loggerContext) {
34
+ console.log(`${loggerContext}: Entity created successfully`, result);
35
+ }
36
+
37
+ return result as T;
38
+ } catch (error) {
39
+ const errorMessage = `Error creating ${entityName}: ${error}`;
40
+ if (loggerContext) {
41
+ console.error(`${loggerContext}: ${errorMessage}`);
42
+ }
43
+ throw new Error(errorMessage);
44
+ }
45
+ }
46
+
47
+ /**
48
+ * Updates an existing entity record in Dynamics 365.
49
+ * @param apiService The API service instance
50
+ * @param entityId The ID of the entity to update
51
+ * @param entity The entity instance with updated values
52
+ * @param entityName The entity collection name
53
+ * @param primaryKey The primary key field name
54
+ * @param loggerContext Optional logger context for debugging
55
+ * @returns Promise resolving to the updated entity
56
+ */
57
+ protected static async updateEntity<T extends BaseEntity>(
58
+ apiService: IApiService,
59
+ entityId: string,
60
+ entity: T,
61
+ entityName: string,
62
+ primaryKey: string,
63
+ loggerContext?: string
64
+ ): Promise<T> {
65
+ try {
66
+ entity.validate();
67
+
68
+ // Remove the primary key from the update payload
69
+ const updatePayload = { ...entity };
70
+ delete (updatePayload as any)[primaryKey];
71
+
72
+ await apiService.updateRecord(entityName, entityId, updatePayload);
73
+
74
+ if (loggerContext) {
75
+ console.log(`${loggerContext}: Entity updated successfully`);
76
+ }
77
+
78
+ // Return the entity with the ID set
79
+ (entity as any)[primaryKey] = entityId;
80
+ return entity;
81
+ } catch (error) {
82
+ const errorMessage = `Error updating ${entityName}: ${error}`;
83
+ if (loggerContext) {
84
+ console.error(`${loggerContext}: ${errorMessage}`);
85
+ }
86
+ throw new Error(errorMessage);
87
+ }
88
+ }
89
+
90
+ /**
91
+ * Deletes an entity record from Dynamics 365.
92
+ * @param apiService The API service instance
93
+ * @param entityId The ID of the entity to delete
94
+ * @param entityName The entity collection name
95
+ * @param loggerContext Optional logger context for debugging
96
+ * @returns Promise resolving when deletion is complete
97
+ */
98
+ protected static async deleteEntity(
99
+ apiService: IApiService,
100
+ entityId: string,
101
+ entityName: string,
102
+ loggerContext?: string
103
+ ): Promise<void> {
104
+ try {
105
+ await apiService.deleteRecord(entityName, entityId);
106
+
107
+ if (loggerContext) {
108
+ console.log(`${loggerContext}: Entity deleted successfully`);
109
+ }
110
+ } catch (error) {
111
+ const errorMessage = `Error deleting ${entityName}: ${error}`;
112
+ if (loggerContext) {
113
+ console.error(`${loggerContext}: ${errorMessage}`);
114
+ }
115
+ throw new Error(errorMessage);
116
+ }
117
+ }
118
+
119
+ /**
120
+ * Retrieves entities based on a FetchXML filter.
121
+ * @param apiService The API service instance
122
+ * @param entityName The entity collection name
123
+ * @param fetchXml The FetchXML query
124
+ * @param EntityClass The entity class constructor
125
+ * @param loggerContext Optional logger context for debugging
126
+ * @returns Promise resolving to an array of entities
127
+ */
128
+ protected static async retrieveEntitiesByFilter<T extends BaseEntity>(
129
+ apiService: IApiService,
130
+ entityName: string,
131
+ fetchXml: string,
132
+ EntityClass: new (data: any) => T,
133
+ loggerContext?: string
134
+ ): Promise<T[]> {
135
+ try {
136
+ const result = await apiService.retrieveMultipleRecords(
137
+ entityName,
138
+ fetchXml
139
+ );
140
+
141
+ const entities = result.entities.map(
142
+ (record: any) => new EntityClass(record)
143
+ );
144
+
145
+ if (loggerContext) {
146
+ console.log(`${loggerContext}: Retrieved ${entities.length} entities`);
147
+ }
148
+
149
+ return entities;
150
+ } catch (error) {
151
+ const errorMessage = `Error retrieving ${entityName} records: ${error}`;
152
+ if (loggerContext) {
153
+ console.error(`${loggerContext}: ${errorMessage}`);
154
+ }
155
+ throw new Error(errorMessage);
156
+ }
157
+ }
158
+
159
+ /**
160
+ * Builds a FetchXML query with proper escaping.
161
+ * @param entityName The entity name
162
+ * @param attributes Array of attribute names to retrieve
163
+ * @param filter Optional filter XML string
164
+ * @param orderBy Optional order by configuration
165
+ * @returns FetchXML string
166
+ */
167
+ protected static buildFetchXml(
168
+ entityName: string,
169
+ attributes: string[],
170
+ filter?: string,
171
+ orderBy?: { attribute: string; descending?: boolean }
172
+ ): string {
173
+ const attributesXml = attributes
174
+ .map((attr) => `<attribute name="${attr}" />`)
175
+ .join('\n ');
176
+ const orderXml = orderBy
177
+ ? `<order attribute="${orderBy.attribute}" descending="${orderBy.descending || false}" />`
178
+ : '';
179
+
180
+ return `<fetch mapping="logical">
181
+ <entity name="${entityName}">
182
+ ${attributesXml}
183
+ ${orderXml}
184
+ ${filter || ''}
185
+ </entity>
186
+ </fetch>`;
187
+ }
188
+
189
+ /**
190
+ * Escapes XML special characters in a string.
191
+ * @param value The string to escape
192
+ * @returns Escaped string safe for XML
193
+ */
194
+ protected static escapeXml(value: string): string {
195
+ if (!value) return value;
196
+
197
+ return value
198
+ .replace(/&/g, '&amp;')
199
+ .replace(/</g, '&lt;')
200
+ .replace(/>/g, '&gt;')
201
+ .replace(/"/g, '&quot;')
202
+ .replace(/'/g, '&apos;');
203
+ }
204
+ }