@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.
- package/bin/create-dynamics-app.js +1 -1
- package/dist/index.js +140 -15
- package/dist/index.js.map +1 -1
- package/dist/utils/consultingHelpers.d.ts +13 -0
- package/dist/utils/consultingHelpers.d.ts.map +1 -0
- package/dist/utils/consultingHelpers.js +569 -0
- package/dist/utils/consultingHelpers.js.map +1 -0
- package/dist/utils/copyTemplate.d.ts.map +1 -1
- package/dist/utils/copyTemplate.js.map +1 -1
- package/dist/utils/initGit.d.ts.map +1 -1
- package/dist/utils/initGit.js.map +1 -1
- package/dist/utils/installDependencies.d.ts.map +1 -1
- package/dist/utils/installDependencies.js +3 -2
- package/dist/utils/installDependencies.js.map +1 -1
- package/dist/utils/updatePackageJson.d.ts +1 -1
- package/dist/utils/updatePackageJson.d.ts.map +1 -1
- package/dist/utils/updatePackageJson.js +11 -1
- package/dist/utils/updatePackageJson.js.map +1 -1
- package/package.json +1 -1
- package/templates/dynamics-365-starter/INTEGRATION_TEST_RESULTS.md +302 -0
- package/templates/dynamics-365-starter/PHASE_4_COMPLETION_SUMMARY.md +305 -0
- package/templates/dynamics-365-starter/README.md +566 -137
- package/templates/dynamics-365-starter/deployment/QUICKSTART-MAC.md +507 -0
- package/templates/dynamics-365-starter/deployment/QUICKSTART-WINDOWS.md +372 -0
- package/templates/dynamics-365-starter/deployment/README.md +484 -0
- package/templates/dynamics-365-starter/deployment/pipelines/README.md +375 -0
- package/templates/dynamics-365-starter/deployment/pipelines/azure-pipelines.yml +330 -0
- package/templates/dynamics-365-starter/deployment/pipelines/github-actions.yml +422 -0
- package/templates/dynamics-365-starter/deployment/pipelines/jenkins.groovy +636 -0
- package/templates/dynamics-365-starter/deployment/scripts/deploy.ps1 +417 -0
- package/templates/dynamics-365-starter/deployment/scripts/deploy.sh +582 -0
- package/templates/dynamics-365-starter/deployment/scripts/team-onboarding.ps1 +486 -0
- package/templates/dynamics-365-starter/deployment/scripts/team-onboarding.sh +567 -0
- package/templates/dynamics-365-starter/deployment/scripts/validate-setup.ps1 +703 -0
- package/templates/dynamics-365-starter/deployment/scripts/validate-setup.sh +671 -0
- package/templates/dynamics-365-starter/docs/ARCHITECTURE_OVERVIEW.md +506 -0
- package/templates/dynamics-365-starter/docs/BEST_PRACTICES.md +723 -0
- package/templates/dynamics-365-starter/docs/MIGRATION_GUIDE.md +447 -0
- package/templates/dynamics-365-starter/docs/team-standards/README.md +273 -0
- package/templates/dynamics-365-starter/docs/team-standards/client-onboarding.md +577 -0
- package/templates/dynamics-365-starter/docs/team-standards/code-review-checklist.md +359 -0
- package/templates/dynamics-365-starter/docs/team-standards/coding-standards.md +700 -0
- package/templates/dynamics-365-starter/docs/team-standards/cross-platform-team-guide.md +736 -0
- package/templates/dynamics-365-starter/docs/team-standards/development-workflows.md +727 -0
- package/templates/dynamics-365-starter/docs/troubleshooting/common-errors.md +758 -0
- package/templates/dynamics-365-starter/docs/troubleshooting/platform-specific-issues.md +878 -0
- package/templates/dynamics-365-starter/package.json +22 -1
- package/templates/dynamics-365-starter/public/index.html +8 -11
- package/templates/dynamics-365-starter/scripts/custom-build.js +255 -0
- package/templates/dynamics-365-starter/src/client-project-template/README.md +234 -0
- package/templates/dynamics-365-starter/src/client-project-template/config/client.template.json +114 -0
- package/templates/dynamics-365-starter/src/client-project-template/config/environments/template.json +186 -0
- package/templates/dynamics-365-starter/src/client-project-template/scripts/client-setup.js +667 -0
- package/templates/dynamics-365-starter/src/components/AccountForm.css +71 -0
- package/templates/dynamics-365-starter/src/components/AccountForm.tsx +541 -0
- package/templates/dynamics-365-starter/src/components/AccountManagement.css +86 -0
- package/templates/dynamics-365-starter/src/components/AccountManagement.tsx +370 -0
- package/templates/dynamics-365-starter/src/components/ContactForm.tsx +149 -63
- package/templates/dynamics-365-starter/src/components/ContactManagement.tsx +153 -63
- package/templates/dynamics-365-starter/src/components/Logging/LogDialog.tsx +291 -0
- package/templates/dynamics-365-starter/src/components/Logging/LoggingContext.tsx +166 -0
- package/templates/dynamics-365-starter/src/components/Logging/LoggingDebugPanel.css +192 -0
- package/templates/dynamics-365-starter/src/components/Logging/LoggingDebugPanel.tsx +177 -0
- package/templates/dynamics-365-starter/src/components/Logging/LoggingProvider.tsx +3 -0
- package/templates/dynamics-365-starter/src/components/Logging/logger.ts +193 -0
- package/templates/dynamics-365-starter/src/constants/account.ts +410 -0
- package/templates/dynamics-365-starter/src/constants/contact.ts +362 -0
- package/templates/dynamics-365-starter/src/examples/README.md +52 -0
- package/templates/dynamics-365-starter/src/examples/component-examples/opportunity-management.tsx +625 -0
- package/templates/dynamics-365-starter/src/examples/entity-examples/opportunity-model.ts +545 -0
- package/templates/dynamics-365-starter/src/examples/integration-examples/custom-pcf-wrapper.tsx +722 -0
- package/templates/dynamics-365-starter/src/examples/workflow-examples/sales-workflow.ts +662 -0
- package/templates/dynamics-365-starter/src/index.tsx +107 -19
- package/templates/dynamics-365-starter/src/models/Account.ts +480 -0
- package/templates/dynamics-365-starter/src/models/BaseEntity.ts +204 -0
- package/templates/dynamics-365-starter/src/models/Contact.ts +580 -0
- package/templates/dynamics-365-starter/src/page-templates/EntityDashboard.tsx +519 -0
- package/templates/dynamics-365-starter/src/page-templates/EntityDetailPage.tsx +456 -0
- package/templates/dynamics-365-starter/src/page-templates/EntityListPage.tsx +406 -0
- package/templates/dynamics-365-starter/src/page-templates/RelatedEntitiesPage.tsx +578 -0
- package/templates/dynamics-365-starter/src/page-templates/SearchPage.tsx +629 -0
- package/templates/dynamics-365-starter/src/pcf/ContactControlWrapper.tsx +75 -22
- package/templates/dynamics-365-starter/src/pcf/MultiEntityControlWrapper.tsx +205 -0
- package/templates/dynamics-365-starter/src/providers/DynamicsProvider.tsx +297 -80
- package/templates/dynamics-365-starter/src/services/MockApiService.ts +260 -0
- package/templates/dynamics-365-starter/src/services/ServiceFactory.ts +65 -0
- package/templates/dynamics-365-starter/src/services/XrmApiService.ts +213 -0
- package/templates/dynamics-365-starter/src/styles/index.css +74 -7
- package/templates/dynamics-365-starter/tools/entity-generator/index.js +168 -0
- package/templates/dynamics-365-starter/tools/entity-generator/templates/constants.template.ts +124 -0
- package/templates/dynamics-365-starter/tools/entity-generator/templates/form.template.css +283 -0
- package/templates/dynamics-365-starter/tools/entity-generator/templates/form.template.tsx +275 -0
- package/templates/dynamics-365-starter/tools/entity-generator/templates/management.template.css +204 -0
- package/templates/dynamics-365-starter/tools/entity-generator/templates/management.template.tsx +413 -0
- package/templates/dynamics-365-starter/tools/entity-generator/templates/model.template.ts +250 -0
- package/templates/dynamics-365-starter/tools/metadata-sync/d365-client.js +410 -0
- package/templates/dynamics-365-starter/tools/metadata-sync/index.js +512 -0
- package/templates/dynamics-365-starter/tools/metadata-sync/type-generator.js +675 -0
- package/templates/dynamics-365-starter/tsconfig.json +11 -8
- package/templates/dynamics-365-starter/webpack.config.js +8 -9
- package/templates/power-pages-starter/README.md +7 -1
- package/templates/power-pages-starter/public/index.html +8 -11
- package/templates/power-pages-starter/src/components/ContactForm.tsx +60 -41
- package/templates/power-pages-starter/src/index.tsx +3 -3
- package/templates/power-pages-starter/src/providers/PowerPagesProvider.tsx +46 -23
- package/templates/power-pages-starter/tsconfig.json +3 -9
- package/templates/power-pages-starter/webpack.config.js +8 -3
|
@@ -1,178 +1,607 @@
|
|
|
1
|
-
# Dynamics 365
|
|
1
|
+
# Dynamics 365 Enhanced Template
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
A sophisticated, enterprise-grade Dynamics 365 application template built with the Dynamics UI Kit.
|
|
4
|
+
Features advanced entity management for Accounts and Contacts with comprehensive CRUD operations,
|
|
5
|
+
smart environment detection, centralized logging, and optimized deployment capabilities.
|
|
4
6
|
|
|
5
|
-
## Features
|
|
7
|
+
## 🚀 Features
|
|
6
8
|
|
|
7
|
-
|
|
8
|
-
- **Advanced UI Components**: Uses DetailsList, Dialog, Panel, and Form components
|
|
9
|
-
- **PCF Integration**: Includes wrapper for PowerApps Component Framework
|
|
10
|
-
- **Responsive Design**: Works on desktop and mobile devices
|
|
11
|
-
- **Type Safety**: Full TypeScript support
|
|
9
|
+
### **Dual Entity Management**
|
|
12
10
|
|
|
13
|
-
|
|
11
|
+
- **Account Management**: Complete CRUD operations with industry codes, revenue tracking, and
|
|
12
|
+
address management
|
|
13
|
+
- **Contact Management**: Full contact lifecycle with preferred contact methods and relationship
|
|
14
|
+
tracking
|
|
15
|
+
- **Unified Interface**: Seamless navigation between Account and Contact management via tabbed
|
|
16
|
+
interface
|
|
14
17
|
|
|
15
|
-
###
|
|
18
|
+
### **Enterprise Architecture**
|
|
16
19
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
20
|
+
- **BaseEntity Pattern**: Abstract base class with static CRUD methods and validation
|
|
21
|
+
- **ServiceFactory**: Smart environment detection (development vs production) with automatic API
|
|
22
|
+
service selection
|
|
23
|
+
- **Centralized Logging**: Comprehensive logging system with debug UI and export capabilities
|
|
24
|
+
- **Entity Constants**: Complete field dictionaries with metadata for type safety
|
|
21
25
|
|
|
22
|
-
|
|
23
|
-
```bash
|
|
24
|
-
npm run dev
|
|
25
|
-
```
|
|
26
|
-
This starts the development server at http://localhost:3000
|
|
26
|
+
### **Advanced UI Components**
|
|
27
27
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
28
|
+
- **Enhanced Forms**: Account and Contact forms with validation and error handling
|
|
29
|
+
- **Interactive Debug Panel**: Real-time logging with filtering and export functionality
|
|
30
|
+
- **Responsive Design**: Mobile-optimized layouts with accessibility features
|
|
31
|
+
- **PCF Integration**: Multi-entity control wrapper for Dynamics 365 custom controls
|
|
32
32
|
|
|
33
|
-
###
|
|
33
|
+
### **Production-Ready Deployment**
|
|
34
34
|
|
|
35
|
-
|
|
35
|
+
- **Custom Build System**: D365-optimized webpack configuration with single-file output
|
|
36
|
+
- **Multiple Deployment Targets**: Web Resources, PCF Controls, and Custom Pages
|
|
37
|
+
- **Environment Detection**: Automatic MockApiService vs XrmApiService selection
|
|
38
|
+
- **Performance Optimization**: Minified production builds with deployment guidance
|
|
36
39
|
|
|
37
|
-
|
|
40
|
+
## 🏁 Quick Start
|
|
38
41
|
|
|
39
|
-
|
|
40
|
-
```bash
|
|
41
|
-
npm install -g @microsoft/powerapps-cli
|
|
42
|
-
```
|
|
42
|
+
### Installation
|
|
43
43
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
```
|
|
44
|
+
```bash
|
|
45
|
+
# Using the CLI tool
|
|
46
|
+
npx create-dynamics-app my-d365-app --template dynamics-365-starter
|
|
48
47
|
|
|
49
|
-
|
|
48
|
+
# Or clone and install
|
|
49
|
+
git clone <repository-url>
|
|
50
|
+
cd dynamics-365-starter
|
|
51
|
+
npm install
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### Development
|
|
50
55
|
|
|
51
|
-
|
|
56
|
+
```bash
|
|
57
|
+
# Start development server with mock data
|
|
58
|
+
npm start
|
|
59
|
+
# Opens http://localhost:3000 with Account and Contact management
|
|
60
|
+
|
|
61
|
+
# Build for development (unminified)
|
|
62
|
+
npm run build:dev
|
|
63
|
+
|
|
64
|
+
# Build for production (optimized for D365)
|
|
65
|
+
npm run build:prod
|
|
66
|
+
|
|
67
|
+
# Serve built files locally
|
|
68
|
+
npm run serve
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
## 📋 Project Structure
|
|
52
72
|
|
|
53
73
|
```
|
|
54
74
|
src/
|
|
55
|
-
├── components/
|
|
56
|
-
│ ├──
|
|
57
|
-
│ ├──
|
|
58
|
-
│
|
|
59
|
-
├──
|
|
60
|
-
│ └──
|
|
61
|
-
├──
|
|
62
|
-
│
|
|
63
|
-
├──
|
|
64
|
-
│
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
-
|
|
80
|
-
-
|
|
81
|
-
|
|
82
|
-
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
75
|
+
├── components/
|
|
76
|
+
│ ├── AccountManagement.tsx # Account CRUD interface
|
|
77
|
+
│ ├── AccountForm.tsx # Account creation/editing form
|
|
78
|
+
│ ├── ContactManagement.tsx # Contact CRUD interface
|
|
79
|
+
│ ├── ContactForm.tsx # Contact creation/editing form
|
|
80
|
+
│ └── Logging/ # Centralized logging system
|
|
81
|
+
│ ├── logger.ts # Logger utility class
|
|
82
|
+
│ ├── LoggingContext.tsx # React context for logs
|
|
83
|
+
│ ├── LoggingProvider.tsx # Provider component
|
|
84
|
+
│ └── LoggingDebugPanel.tsx # Debug UI with filtering
|
|
85
|
+
├── models/
|
|
86
|
+
│ ├── BaseEntity.ts # Abstract base class with CRUD
|
|
87
|
+
│ ├── Account.ts # Account entity with validation
|
|
88
|
+
│ └── Contact.ts # Contact entity with validation
|
|
89
|
+
├── constants/
|
|
90
|
+
│ ├── account.ts # Account field constants & metadata
|
|
91
|
+
│ └── contact.ts # Contact field constants & metadata
|
|
92
|
+
├── services/
|
|
93
|
+
│ ├── ServiceFactory.ts # Environment-aware service factory
|
|
94
|
+
│ ├── XrmApiService.ts # Production Dynamics 365 API service
|
|
95
|
+
│ └── MockApiService.ts # Development mock service
|
|
96
|
+
├── providers/
|
|
97
|
+
│ └── DynamicsProvider.tsx # API context with environment detection
|
|
98
|
+
├── pcf/
|
|
99
|
+
│ ├── ContactControlWrapper.tsx # Single-entity PCF wrapper
|
|
100
|
+
│ └── MultiEntityControlWrapper.tsx # Multi-entity PCF wrapper
|
|
101
|
+
├── scripts/
|
|
102
|
+
│ └── custom-build.js # D365-optimized build configuration
|
|
103
|
+
├── styles/
|
|
104
|
+
│ └── index.css # Global styles and responsive design
|
|
105
|
+
└── index.tsx # Application entry with navigation
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
## 🏗️ Entity Model Architecture
|
|
109
|
+
|
|
110
|
+
### BaseEntity Pattern
|
|
111
|
+
|
|
112
|
+
All entities inherit from `BaseEntity` which provides:
|
|
113
|
+
|
|
114
|
+
```typescript
|
|
115
|
+
// Static CRUD methods with validation and logging
|
|
116
|
+
export abstract class BaseEntity {
|
|
117
|
+
protected static async createEntity<T>(
|
|
118
|
+
apiService: IApiService,
|
|
119
|
+
entity: T,
|
|
120
|
+
entityCollectionName: string,
|
|
121
|
+
loggerContext: string
|
|
122
|
+
): Promise<T>;
|
|
123
|
+
|
|
124
|
+
protected static async updateEntity<T>(...): Promise<T>;
|
|
125
|
+
protected static async deleteEntity(...): Promise<void>;
|
|
126
|
+
protected static async retrieveEntitiesByFilter<T>(...): Promise<T[]>;
|
|
127
|
+
}
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
### Entity Implementation Example
|
|
131
|
+
|
|
132
|
+
```typescript
|
|
133
|
+
// Account entity with complete CRUD operations
|
|
134
|
+
export class Account extends BaseEntity implements IAccount {
|
|
135
|
+
// Constructor and properties...
|
|
136
|
+
|
|
137
|
+
// Static CRUD methods
|
|
138
|
+
public static async create(apiService: IApiService, account: Account): Promise<Account> {
|
|
139
|
+
const loggerContext = 'Account.create';
|
|
140
|
+
console.log(`${loggerContext}: Creating new account`, { name: account.name });
|
|
141
|
+
|
|
142
|
+
return await this.createEntity<Account>(
|
|
143
|
+
apiService,
|
|
144
|
+
account,
|
|
145
|
+
AccountConstants.EntityCollectionName,
|
|
146
|
+
loggerContext
|
|
147
|
+
);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
public static async retrieveActiveAccounts(apiService: IApiService): Promise<Account[]> {
|
|
151
|
+
// Built-in FetchXML generation and error handling
|
|
152
|
+
const filter = `<filter type="and">
|
|
153
|
+
<condition attribute="${AccountConstants.StateCode}" operator="eq" value="0" />
|
|
154
|
+
</filter>`;
|
|
155
|
+
|
|
156
|
+
return await this.retrieveByFilter(apiService, filter);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// Client-side validation
|
|
160
|
+
validate(): boolean {
|
|
161
|
+
if (!this.name || this.name.trim().length === 0) {
|
|
162
|
+
throw new Error('Account name is required');
|
|
163
|
+
}
|
|
164
|
+
// Additional validation rules...
|
|
165
|
+
return true;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
### Entity Constants
|
|
171
|
+
|
|
172
|
+
Complete field dictionaries with metadata:
|
|
173
|
+
|
|
174
|
+
```typescript
|
|
175
|
+
export class AccountConstants {
|
|
176
|
+
/** Type: String, RequiredLevel: ApplicationRequired, MaxLength: 160 */
|
|
177
|
+
public static readonly PrimaryName: string = 'name';
|
|
178
|
+
|
|
179
|
+
/** Type: String, RequiredLevel: None, MaxLength: 100, Format: Email */
|
|
180
|
+
public static readonly EMailAddress1: string = 'emailaddress1';
|
|
181
|
+
|
|
182
|
+
/** Type: Money, RequiredLevel: None, MinValue: -922337203685477 */
|
|
183
|
+
public static readonly Revenue: string = 'revenue';
|
|
184
|
+
}
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
## ⚙️ Service Factory & Environment Detection
|
|
188
|
+
|
|
189
|
+
The `ServiceFactory` automatically detects the runtime environment:
|
|
190
|
+
|
|
191
|
+
```typescript
|
|
192
|
+
export class ServiceFactory {
|
|
193
|
+
// Automatic environment detection
|
|
194
|
+
public static get isMockEnvironment(): boolean {
|
|
195
|
+
const hostname = window.location.hostname;
|
|
196
|
+
return hostname === 'localhost' || hostname === '127.0.0.1';
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
// Smart API service creation
|
|
200
|
+
public static createApiService(Xrm?: any): IApiService {
|
|
201
|
+
if (this.isMockEnvironment) {
|
|
202
|
+
return new MockApiService(); // Development with mock data
|
|
203
|
+
}
|
|
204
|
+
return new XrmApiService(Xrm); // Production with Dynamics 365
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
## 📊 Centralized Logging System
|
|
210
|
+
|
|
211
|
+
Comprehensive logging with UI:
|
|
212
|
+
|
|
213
|
+
```typescript
|
|
214
|
+
// Logger usage throughout the application
|
|
215
|
+
Logger.log('Application initialized', 'App');
|
|
216
|
+
Logger.userAction('Contact created', { contactId: '123' }, 'ContactForm');
|
|
217
|
+
Logger.error('API call failed', 'ContactManagement', error);
|
|
218
|
+
Logger.apiOperation('CREATE', 'contact', contactData, 'ContactForm.submit');
|
|
219
|
+
Logger.validation('Contact', ['Email is required'], 'ContactForm.validate');
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
The debug panel provides:
|
|
223
|
+
|
|
224
|
+
- Real-time log viewing with level filtering
|
|
225
|
+
- Search and export capabilities
|
|
226
|
+
- Performance timing and API operation tracking
|
|
227
|
+
- User action audit trail
|
|
228
|
+
|
|
229
|
+
## 🎯 Deployment Options
|
|
230
|
+
|
|
231
|
+
### 1. Dynamics 365 Web Resources
|
|
232
|
+
|
|
233
|
+
**Optimal for**: Dashboard widgets, form sections, custom pages
|
|
234
|
+
|
|
235
|
+
```bash
|
|
236
|
+
# Build optimized for D365
|
|
237
|
+
npm run build:d365
|
|
238
|
+
|
|
239
|
+
# Upload generated files as web resources:
|
|
240
|
+
# - dist/main.js → Script (JScript) web resource
|
|
241
|
+
# - dist/index.html → Web Page (HTML) web resource
|
|
242
|
+
# - Set "Available for Dynamics 365 mobile" if needed
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
The custom build process:
|
|
246
|
+
|
|
247
|
+
- Disables code splitting for single-file deployment
|
|
248
|
+
- Removes content hashes for consistent web resource naming
|
|
249
|
+
- Optimizes bundle size and provides deployment guidance
|
|
250
|
+
- Generates deployment info with asset details
|
|
251
|
+
|
|
252
|
+
### 2. PCF Custom Controls
|
|
253
|
+
|
|
254
|
+
**Optimal for**: Form controls, view extensions, embedded components
|
|
255
|
+
|
|
256
|
+
#### Single Entity Control
|
|
257
|
+
|
|
258
|
+
```typescript
|
|
259
|
+
import { ContactControlWrapper } from './pcf/ContactControlWrapper';
|
|
260
|
+
|
|
261
|
+
// In your PCF component
|
|
262
|
+
export class ContactControl implements ComponentFramework.StandardControl<IInputs, IOutputs> {
|
|
263
|
+
public init(context: ComponentFramework.Context<IInputs>): void {
|
|
264
|
+
// Render ContactControlWrapper with PCF context
|
|
265
|
+
ReactDOM.render(React.createElement(ContactControlWrapper, { context }), this.container);
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
#### Multi-Entity Control
|
|
271
|
+
|
|
272
|
+
```typescript
|
|
273
|
+
import { MultiEntityControlWrapper } from './pcf/MultiEntityControlWrapper';
|
|
274
|
+
|
|
275
|
+
// Support both Account and Contact management in one control
|
|
276
|
+
ReactDOM.render(
|
|
277
|
+
React.createElement(MultiEntityControlWrapper, {
|
|
278
|
+
context,
|
|
279
|
+
defaultEntity: 'contact',
|
|
280
|
+
showTabs: true,
|
|
281
|
+
}),
|
|
282
|
+
this.container
|
|
283
|
+
);
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
### 3. Dynamics 365 Custom Pages
|
|
287
|
+
|
|
288
|
+
**Optimal for**: Full-page applications, complex workflows
|
|
289
|
+
|
|
290
|
+
```bash
|
|
291
|
+
# Build for Custom Pages
|
|
292
|
+
npm run build:prod
|
|
293
|
+
|
|
294
|
+
# Deploy as model-driven app page:
|
|
295
|
+
# 1. Upload main.js as web resource
|
|
296
|
+
# 2. Create Custom Page in Power Apps
|
|
297
|
+
# 3. Add HTML control with web resource reference
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
## 🔧 Configuration
|
|
110
301
|
|
|
111
302
|
### Environment Variables
|
|
112
|
-
|
|
303
|
+
|
|
304
|
+
```bash
|
|
305
|
+
# .env.local
|
|
306
|
+
REACT_APP_D365_URL=https://yourorg.crm.dynamics.com
|
|
307
|
+
REACT_APP_ENVIRONMENT=development
|
|
113
308
|
```
|
|
114
|
-
|
|
115
|
-
|
|
309
|
+
|
|
310
|
+
### API Service Configuration
|
|
311
|
+
|
|
312
|
+
```typescript
|
|
313
|
+
// Automatic configuration via ServiceFactory
|
|
314
|
+
const DynamicsProvider: React.FC = ({ children }) => {
|
|
315
|
+
useEffect(() => {
|
|
316
|
+
// ServiceFactory handles environment detection
|
|
317
|
+
const xrmObject = ServiceFactory.isDynamics365Context() ? window.Xrm : undefined;
|
|
318
|
+
const service = ServiceFactory.createApiService(xrmObject);
|
|
319
|
+
setApiService(service);
|
|
320
|
+
}, []);
|
|
321
|
+
|
|
322
|
+
// Provider implementation...
|
|
323
|
+
};
|
|
116
324
|
```
|
|
117
325
|
|
|
118
|
-
###
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
326
|
+
### PCF Integration
|
|
327
|
+
|
|
328
|
+
```typescript
|
|
329
|
+
// Custom API service for PCF context
|
|
330
|
+
const createPCFApiService = () => ({
|
|
331
|
+
createRecord: async (entityName: string, data: any) =>
|
|
332
|
+
await context.webAPI.createRecord(entityName, data),
|
|
333
|
+
retrieveMultipleRecords: async (entityName: string, fetchXml: string) =>
|
|
334
|
+
await context.webAPI.retrieveMultipleRecords(
|
|
335
|
+
entityName,
|
|
336
|
+
`?fetchXml=${encodeURIComponent(fetchXml)}`
|
|
337
|
+
),
|
|
338
|
+
// Additional PCF WebAPI methods...
|
|
339
|
+
});
|
|
340
|
+
```
|
|
123
341
|
|
|
124
|
-
##
|
|
342
|
+
## 🛠️ Development Workflow
|
|
125
343
|
|
|
126
344
|
### Adding New Entities
|
|
127
|
-
1. Create new form components following the `ContactForm` pattern
|
|
128
|
-
2. Add CRUD operations to your provider
|
|
129
|
-
3. Create management components like `ContactManagement`
|
|
130
345
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
346
|
+
1. **Create Entity Model**:
|
|
347
|
+
|
|
348
|
+
```typescript
|
|
349
|
+
// src/models/Opportunity.ts
|
|
350
|
+
export class Opportunity extends BaseEntity implements IOpportunity {
|
|
351
|
+
// Entity properties and validation
|
|
352
|
+
public static async create(
|
|
353
|
+
apiService: IApiService,
|
|
354
|
+
opportunity: Opportunity
|
|
355
|
+
): Promise<Opportunity> {
|
|
356
|
+
return await this.createEntity<Opportunity>(/*...*/);
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
```
|
|
135
360
|
|
|
136
|
-
|
|
137
|
-
- Extend `DynamicsProvider` for additional entities
|
|
138
|
-
- Add custom business logic in service layers
|
|
139
|
-
- Implement caching and offline capabilities
|
|
361
|
+
2. **Create Entity Constants**:
|
|
140
362
|
|
|
141
|
-
|
|
363
|
+
```typescript
|
|
364
|
+
// src/constants/opportunity.ts
|
|
365
|
+
export class OpportunityConstants {
|
|
366
|
+
public static readonly EntityName: string = 'opportunity';
|
|
367
|
+
public static readonly PrimaryName: string = 'name';
|
|
368
|
+
// Field definitions with metadata...
|
|
369
|
+
}
|
|
370
|
+
```
|
|
142
371
|
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
372
|
+
3. **Create Management Component**:
|
|
373
|
+
|
|
374
|
+
```typescript
|
|
375
|
+
// src/components/OpportunityManagement.tsx
|
|
376
|
+
export const OpportunityManagement: React.FC = () => {
|
|
377
|
+
// Follow AccountManagement pattern
|
|
378
|
+
const loadOpportunities = useCallback(async () => {
|
|
379
|
+
const opportunities = await Opportunity.retrieveActiveOpportunities(apiService);
|
|
380
|
+
// Component implementation...
|
|
381
|
+
}, [apiService]);
|
|
382
|
+
};
|
|
383
|
+
```
|
|
384
|
+
|
|
385
|
+
### Custom Validation
|
|
386
|
+
|
|
387
|
+
```typescript
|
|
388
|
+
// In entity models
|
|
389
|
+
validate(): boolean {
|
|
390
|
+
const validationErrors: string[] = [];
|
|
391
|
+
|
|
392
|
+
if (!this.name?.trim()) {
|
|
393
|
+
validationErrors.push('Name is required');
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
if (this.revenue && this.revenue < 0) {
|
|
397
|
+
validationErrors.push('Revenue cannot be negative');
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
if (validationErrors.length > 0) {
|
|
401
|
+
Logger.validation('Account', validationErrors, 'Account.validate');
|
|
402
|
+
throw new Error(validationErrors.join(', '));
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
return true;
|
|
406
|
+
}
|
|
407
|
+
```
|
|
408
|
+
|
|
409
|
+
### Extending Logging
|
|
410
|
+
|
|
411
|
+
```typescript
|
|
412
|
+
// Add custom log types
|
|
413
|
+
Logger.performance('Data fetch completed', startTime, 'AccountManagement');
|
|
414
|
+
Logger.businessRule('Credit limit exceeded', { accountId, creditLimit }, 'AccountForm');
|
|
415
|
+
```
|
|
416
|
+
|
|
417
|
+
## 📋 Available Scripts
|
|
418
|
+
|
|
419
|
+
```bash
|
|
420
|
+
# Development
|
|
421
|
+
npm start # Start development server with hot reload
|
|
422
|
+
npm run dev # Alias for start
|
|
423
|
+
|
|
424
|
+
# Building
|
|
425
|
+
npm run build # Standard webpack production build
|
|
426
|
+
npm run build:dev # Unminified build for debugging
|
|
427
|
+
npm run build:prod # Optimized build for D365 deployment
|
|
428
|
+
npm run build:d365 # Alias for build:prod
|
|
429
|
+
|
|
430
|
+
# Quality Assurance
|
|
431
|
+
npm run typecheck # TypeScript compilation check
|
|
432
|
+
npm run lint # ESLint code quality check
|
|
433
|
+
npm run clean # Clean build directory
|
|
434
|
+
|
|
435
|
+
# Deployment
|
|
436
|
+
npm run serve # Serve built files locally on port 62874
|
|
437
|
+
```
|
|
149
438
|
|
|
150
|
-
##
|
|
439
|
+
## 🧪 Testing Workflow
|
|
440
|
+
|
|
441
|
+
### Component Testing
|
|
442
|
+
|
|
443
|
+
```typescript
|
|
444
|
+
// Test entity models
|
|
445
|
+
const account = new Account({ name: 'Test Account' });
|
|
446
|
+
account.validate(); // Should pass
|
|
447
|
+
|
|
448
|
+
// Test API operations
|
|
449
|
+
const mockApiService = new MockApiService();
|
|
450
|
+
const createdAccount = await Account.create(mockApiService, account);
|
|
451
|
+
```
|
|
452
|
+
|
|
453
|
+
### Environment Testing
|
|
454
|
+
|
|
455
|
+
```bash
|
|
456
|
+
# Test development environment
|
|
457
|
+
npm start # Should use MockApiService
|
|
458
|
+
|
|
459
|
+
# Test production build
|
|
460
|
+
npm run build:prod
|
|
461
|
+
npm run serve # Verify optimized bundle
|
|
462
|
+
```
|
|
463
|
+
|
|
464
|
+
### PCF Testing
|
|
465
|
+
|
|
466
|
+
```typescript
|
|
467
|
+
// Test PCF wrapper with mock context
|
|
468
|
+
const mockContext = {
|
|
469
|
+
webAPI: {
|
|
470
|
+
createRecord: jest.fn(),
|
|
471
|
+
retrieveMultipleRecords: jest.fn()
|
|
472
|
+
}
|
|
473
|
+
};
|
|
474
|
+
|
|
475
|
+
render(<ContactControlWrapper context={mockContext} />);
|
|
476
|
+
```
|
|
477
|
+
|
|
478
|
+
## 🔍 Troubleshooting
|
|
151
479
|
|
|
152
480
|
### Common Issues
|
|
153
481
|
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
482
|
+
#### Build Errors
|
|
483
|
+
|
|
484
|
+
```bash
|
|
485
|
+
# Clear cache and reinstall
|
|
486
|
+
rm -rf node_modules package-lock.json
|
|
487
|
+
npm install
|
|
157
488
|
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
489
|
+
# Check TypeScript compilation
|
|
490
|
+
npm run typecheck
|
|
491
|
+
```
|
|
161
492
|
|
|
162
|
-
|
|
163
|
-
- Ensure proper manifest configuration
|
|
164
|
-
- Check component lifecycle methods
|
|
493
|
+
#### Environment Detection Issues
|
|
165
494
|
|
|
166
|
-
|
|
495
|
+
```typescript
|
|
496
|
+
// Force environment for testing
|
|
497
|
+
ServiceFactory.isMockEnvironment = true; // Development
|
|
498
|
+
ServiceFactory.isMockEnvironment = false; // Production
|
|
499
|
+
```
|
|
167
500
|
|
|
168
|
-
|
|
169
|
-
|
|
501
|
+
#### PCF Integration Problems
|
|
502
|
+
|
|
503
|
+
- Verify `context.webAPI` is available
|
|
504
|
+
- Check PCF manifest configuration
|
|
505
|
+
- Ensure proper component lifecycle implementation
|
|
506
|
+
- Review browser console for Xrm object availability
|
|
507
|
+
|
|
508
|
+
#### Logging Not Working
|
|
509
|
+
|
|
510
|
+
```typescript
|
|
511
|
+
// Check logger configuration
|
|
512
|
+
console.log('Has custom logger:', Logger.hasCustomLogger());
|
|
513
|
+
|
|
514
|
+
// Manually set logger function
|
|
515
|
+
Logger.setLoggerFunction((message, source) => {
|
|
516
|
+
console.log(`[${source}] ${message}`);
|
|
517
|
+
});
|
|
518
|
+
```
|
|
519
|
+
|
|
520
|
+
### Performance Optimization
|
|
521
|
+
|
|
522
|
+
#### Bundle Size
|
|
523
|
+
|
|
524
|
+
```bash
|
|
525
|
+
# Analyze bundle with webpack-bundle-analyzer
|
|
526
|
+
npm install --save-dev webpack-bundle-analyzer
|
|
527
|
+
# Add analyzer to build script and review output
|
|
528
|
+
```
|
|
529
|
+
|
|
530
|
+
#### Entity Model Performance
|
|
531
|
+
|
|
532
|
+
```typescript
|
|
533
|
+
// Use selective field retrieval
|
|
534
|
+
const accounts = await Account.retrieveByFilter(apiService, filter, [
|
|
535
|
+
AccountConstants.PrimaryName,
|
|
536
|
+
AccountConstants.EMailAddress1,
|
|
537
|
+
AccountConstants.Telephone1,
|
|
538
|
+
]);
|
|
539
|
+
```
|
|
540
|
+
|
|
541
|
+
## 📚 Learning Resources
|
|
542
|
+
|
|
543
|
+
### Essential Documentation
|
|
544
|
+
|
|
545
|
+
- [Dynamics UI Kit Components](https://github.com/your-org/dynamics-ui-kit)
|
|
546
|
+
- [Dynamics 365 Web API Reference](https://docs.microsoft.com/dynamics365/customer-engagement/web-api/)
|
|
170
547
|
- [PowerApps Component Framework](https://docs.microsoft.com/powerapps/developer/component-framework/)
|
|
171
|
-
- [Fluent UI
|
|
548
|
+
- [Fluent UI v8 Components](https://developer.microsoft.com/fluentui/get-started/web#fluent-ui-react-v8)
|
|
549
|
+
|
|
550
|
+
### Advanced Topics
|
|
551
|
+
|
|
552
|
+
- [Entity Relationship Modeling in D365](https://docs.microsoft.com/dynamics365/customerengagement/on-premises/developer/introduction-entities)
|
|
553
|
+
- [Custom Page Development](https://docs.microsoft.com/powerapps/developer/model-driven-apps/customizable-controls-custom-pages)
|
|
554
|
+
- [FetchXML Query Examples](https://docs.microsoft.com/powerapps/developer/data-platform/use-fetchxml-construct-query)
|
|
555
|
+
|
|
556
|
+
## 🤝 Contributing
|
|
557
|
+
|
|
558
|
+
### Development Setup
|
|
559
|
+
|
|
560
|
+
1. **Fork and Clone**: Create a fork of the repository
|
|
561
|
+
2. **Install Dependencies**: Run `npm install` in the template directory
|
|
562
|
+
3. **Create Feature Branch**: `git checkout -b feature/your-feature`
|
|
563
|
+
4. **Follow Patterns**: Use existing entity models and components as templates
|
|
564
|
+
5. **Add Tests**: Include validation and component tests
|
|
565
|
+
6. **Update Documentation**: Add examples and update README
|
|
566
|
+
|
|
567
|
+
### Code Standards
|
|
568
|
+
|
|
569
|
+
- **TypeScript**: Full type safety with strict mode
|
|
570
|
+
- **Entity Models**: Follow BaseEntity pattern with validation
|
|
571
|
+
- **Components**: Use functional components with hooks
|
|
572
|
+
- **Logging**: Include comprehensive logging for debugging
|
|
573
|
+
- **Error Handling**: Implement proper error boundaries and validation
|
|
574
|
+
|
|
575
|
+
### Pull Request Guidelines
|
|
576
|
+
|
|
577
|
+
1. Ensure TypeScript compilation is clean
|
|
578
|
+
2. Test in both development and production builds
|
|
579
|
+
3. Verify PCF wrapper functionality
|
|
580
|
+
4. Update documentation for new features
|
|
581
|
+
5. Include migration guide for breaking changes
|
|
582
|
+
|
|
583
|
+
## 📄 License
|
|
584
|
+
|
|
585
|
+
This template is part of the Dynamics UI Kit and follows the same licensing terms.
|
|
586
|
+
|
|
587
|
+
## 🆘 Support
|
|
588
|
+
|
|
589
|
+
### Getting Help
|
|
590
|
+
|
|
591
|
+
- **Issues**: Create issues in the Dynamics UI Kit repository
|
|
592
|
+
- **Documentation**: Check the comprehensive guides and examples
|
|
593
|
+
- **Community**: Join discussions in the project community
|
|
594
|
+
|
|
595
|
+
### Enterprise Support
|
|
596
|
+
|
|
597
|
+
For enterprise deployments and custom development:
|
|
598
|
+
|
|
599
|
+
- Architecture consulting for complex D365 integrations
|
|
600
|
+
- Custom entity model development
|
|
601
|
+
- Performance optimization and scaling guidance
|
|
602
|
+
- Advanced PCF control development
|
|
172
603
|
|
|
173
|
-
|
|
604
|
+
---
|
|
174
605
|
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
- Check the documentation and examples
|
|
178
|
-
- Join the community discussions
|
|
606
|
+
Built with ❤️ using [Dynamics UI Kit](https://github.com/your-org/dynamics-ui-kit) | Optimized for
|
|
607
|
+
Microsoft Dynamics 365
|