@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
|
@@ -5,11 +5,28 @@
|
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"scripts": {
|
|
7
7
|
"build": "webpack --mode=production",
|
|
8
|
+
"build:dev": "node scripts/custom-build.js --dev",
|
|
9
|
+
"build:prod": "node scripts/custom-build.js",
|
|
10
|
+
"build:d365": "node scripts/custom-build.js",
|
|
8
11
|
"dev": "webpack serve --mode=development",
|
|
9
12
|
"start": "webpack serve --mode=development",
|
|
13
|
+
"serve": "serve -s dist -l 62874",
|
|
10
14
|
"typecheck": "tsc --noEmit",
|
|
11
15
|
"clean": "rimraf dist",
|
|
12
|
-
"lint": "eslint src --ext .ts,.tsx"
|
|
16
|
+
"lint": "eslint src --ext .ts,.tsx",
|
|
17
|
+
"lint:fix": "eslint src --ext .ts,.tsx --fix",
|
|
18
|
+
"quality": "npm run lint && npm run typecheck",
|
|
19
|
+
"quality:fix": "npm run lint:fix && npm run typecheck",
|
|
20
|
+
"validate": "npm run quality && npm run build:prod",
|
|
21
|
+
"test:build": "npm run clean && npm run build:dev && npm run build:prod",
|
|
22
|
+
"test:serve": "npm run build:prod && npm run serve",
|
|
23
|
+
"precommit": "npm run quality",
|
|
24
|
+
"prepublishOnly": "npm run validate",
|
|
25
|
+
"generate:entity": "node tools/entity-generator/index.js generate",
|
|
26
|
+
"metadata:pull": "node tools/metadata-sync/index.js pull",
|
|
27
|
+
"metadata:generate": "node tools/metadata-sync/index.js generate",
|
|
28
|
+
"metadata:validate": "node tools/metadata-sync/index.js validate",
|
|
29
|
+
"metadata:sync": "node tools/metadata-sync/index.js sync"
|
|
13
30
|
},
|
|
14
31
|
"dependencies": {
|
|
15
32
|
"@khester/dynamics-ui-api-client": "^1.0.0",
|
|
@@ -20,8 +37,12 @@
|
|
|
20
37
|
"devDependencies": {
|
|
21
38
|
"@types/react": "^18.2.0",
|
|
22
39
|
"@types/react-dom": "^18.2.0",
|
|
40
|
+
"commander": "^11.1.0",
|
|
23
41
|
"css-loader": "^6.8.1",
|
|
42
|
+
"eslint": "^8.57.0",
|
|
24
43
|
"html-webpack-plugin": "^5.5.3",
|
|
44
|
+
"rimraf": "^5.0.5",
|
|
45
|
+
"serve": "^14.2.1",
|
|
25
46
|
"style-loader": "^3.3.3",
|
|
26
47
|
"ts-loader": "^9.5.1",
|
|
27
48
|
"typescript": "^5.3.3",
|
|
@@ -1,18 +1,15 @@
|
|
|
1
1
|
<!DOCTYPE html>
|
|
2
2
|
<html lang="en">
|
|
3
|
-
|
|
3
|
+
<head>
|
|
4
4
|
<meta charset="utf-8" />
|
|
5
|
-
<link rel="icon" href="
|
|
5
|
+
<link rel="icon" href="data:," />
|
|
6
6
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
7
|
-
<meta name="theme-color" content="#
|
|
8
|
-
<meta
|
|
9
|
-
name="description"
|
|
10
|
-
content="Dynamics 365 application built with Dynamics UI Kit"
|
|
11
|
-
/>
|
|
7
|
+
<meta name="theme-color" content="#000000" />
|
|
8
|
+
<meta name="description" content="Dynamics 365 Application built with Dynamics UI Kit" />
|
|
12
9
|
<title>Dynamics 365 App - Dynamics UI Kit</title>
|
|
13
|
-
|
|
14
|
-
|
|
10
|
+
</head>
|
|
11
|
+
<body>
|
|
15
12
|
<noscript>You need to enable JavaScript to run this app.</noscript>
|
|
16
13
|
<div id="root"></div>
|
|
17
|
-
|
|
18
|
-
</html>
|
|
14
|
+
</body>
|
|
15
|
+
</html>
|
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
const webpack = require('webpack');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
|
|
5
|
+
// Get webpack config
|
|
6
|
+
const webpackConfigPath = path.resolve(__dirname, '../webpack.config.js');
|
|
7
|
+
const getWebpackConfig = require(webpackConfigPath);
|
|
8
|
+
|
|
9
|
+
// Check command line arguments for dev mode
|
|
10
|
+
const isDev = process.argv.includes('--dev') || process.argv.includes('-dev');
|
|
11
|
+
const mode = isDev ? 'development' : 'production';
|
|
12
|
+
|
|
13
|
+
console.log(`Custom Build Script - Mode: ${mode}`);
|
|
14
|
+
|
|
15
|
+
// Create custom webpack config for D365 deployment
|
|
16
|
+
function createD365WebpackConfig() {
|
|
17
|
+
// Get base config
|
|
18
|
+
const baseConfig = getWebpackConfig({}, { mode });
|
|
19
|
+
|
|
20
|
+
// D365-specific optimizations
|
|
21
|
+
const d365Config = {
|
|
22
|
+
...baseConfig,
|
|
23
|
+
mode,
|
|
24
|
+
optimization: {
|
|
25
|
+
// Disable code splitting for single file deployment
|
|
26
|
+
splitChunks: {
|
|
27
|
+
cacheGroups: {
|
|
28
|
+
default: false,
|
|
29
|
+
vendors: false,
|
|
30
|
+
},
|
|
31
|
+
},
|
|
32
|
+
// Disable runtime chunk
|
|
33
|
+
runtimeChunk: false,
|
|
34
|
+
// Control minimization based on mode
|
|
35
|
+
minimize: !isDev,
|
|
36
|
+
},
|
|
37
|
+
output: {
|
|
38
|
+
...baseConfig.output,
|
|
39
|
+
// Remove hashes for consistent D365 web resource naming
|
|
40
|
+
filename: '[name].js',
|
|
41
|
+
chunkFilename: '[name].chunk.js',
|
|
42
|
+
assetModuleFilename: '[name][ext]',
|
|
43
|
+
// Set public path for D365 context
|
|
44
|
+
publicPath: './',
|
|
45
|
+
},
|
|
46
|
+
// Add performance hints for large bundles
|
|
47
|
+
performance: {
|
|
48
|
+
hints: isDev ? false : 'warning',
|
|
49
|
+
maxEntrypointSize: 2000000, // 2MB - reasonable for D365
|
|
50
|
+
maxAssetSize: 2000000,
|
|
51
|
+
},
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
// Modify CSS handling for single file output
|
|
55
|
+
const rules = d365Config.module.rules.map((rule) => {
|
|
56
|
+
if (rule.test && rule.test.toString().includes('css')) {
|
|
57
|
+
return {
|
|
58
|
+
...rule,
|
|
59
|
+
use: [
|
|
60
|
+
'style-loader', // Inline CSS instead of separate files
|
|
61
|
+
'css-loader',
|
|
62
|
+
],
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
return rule;
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
d365Config.module.rules = rules;
|
|
69
|
+
|
|
70
|
+
// Modify HTML plugin for D365
|
|
71
|
+
const htmlPluginIndex = d365Config.plugins.findIndex(
|
|
72
|
+
(plugin) => plugin.constructor.name === 'HtmlWebpackPlugin'
|
|
73
|
+
);
|
|
74
|
+
|
|
75
|
+
if (htmlPluginIndex !== -1) {
|
|
76
|
+
d365Config.plugins[htmlPluginIndex] = new (require('html-webpack-plugin'))({
|
|
77
|
+
template: './public/index.html',
|
|
78
|
+
filename: 'index.html',
|
|
79
|
+
inject: 'body',
|
|
80
|
+
// Inline all assets for single-file deployment
|
|
81
|
+
inlineSource: isDev ? false : '.(js|css)$',
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// Add banner for D365 deployment info
|
|
86
|
+
d365Config.plugins.push(
|
|
87
|
+
new webpack.BannerPlugin({
|
|
88
|
+
banner: `
|
|
89
|
+
Dynamics 365 Custom Page Bundle
|
|
90
|
+
Built: ${new Date().toISOString()}
|
|
91
|
+
Mode: ${mode}
|
|
92
|
+
Environment: ${isDev ? 'Development' : 'Production'}
|
|
93
|
+
Generated with Dynamics UI Kit
|
|
94
|
+
`.trim(),
|
|
95
|
+
raw: false,
|
|
96
|
+
})
|
|
97
|
+
);
|
|
98
|
+
|
|
99
|
+
// Add define plugin for environment variables
|
|
100
|
+
d365Config.plugins.push(
|
|
101
|
+
new webpack.DefinePlugin({
|
|
102
|
+
'process.env.NODE_ENV': JSON.stringify(mode),
|
|
103
|
+
'process.env.D365_BUILD': JSON.stringify(true),
|
|
104
|
+
'process.env.BUILD_MODE': JSON.stringify(mode),
|
|
105
|
+
})
|
|
106
|
+
);
|
|
107
|
+
|
|
108
|
+
return d365Config;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// Build function
|
|
112
|
+
function build() {
|
|
113
|
+
const config = createD365WebpackConfig();
|
|
114
|
+
|
|
115
|
+
console.log('Starting D365-optimized build...');
|
|
116
|
+
console.log(`Output directory: ${config.output.path}`);
|
|
117
|
+
console.log(
|
|
118
|
+
`Bundle splitting: ${config.optimization.splitChunks ? 'enabled' : 'disabled'}`
|
|
119
|
+
);
|
|
120
|
+
console.log(`Minimization: ${config.optimization.minimize}`);
|
|
121
|
+
|
|
122
|
+
const compiler = webpack(config);
|
|
123
|
+
|
|
124
|
+
compiler.run((err, stats) => {
|
|
125
|
+
if (err) {
|
|
126
|
+
console.error('Build failed with error:', err);
|
|
127
|
+
process.exit(1);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
if (stats.hasErrors()) {
|
|
131
|
+
console.error('Build completed with errors:');
|
|
132
|
+
console.error(
|
|
133
|
+
stats.toString({
|
|
134
|
+
colors: true,
|
|
135
|
+
chunks: false,
|
|
136
|
+
modules: false,
|
|
137
|
+
errorDetails: true,
|
|
138
|
+
})
|
|
139
|
+
);
|
|
140
|
+
process.exit(1);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
if (stats.hasWarnings()) {
|
|
144
|
+
console.warn('Build completed with warnings:');
|
|
145
|
+
console.warn(
|
|
146
|
+
stats.toString({
|
|
147
|
+
colors: true,
|
|
148
|
+
chunks: false,
|
|
149
|
+
modules: false,
|
|
150
|
+
warningsFilter: /export.*was not found in/,
|
|
151
|
+
})
|
|
152
|
+
);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
console.log('Build completed successfully!');
|
|
156
|
+
console.log(
|
|
157
|
+
stats.toString({
|
|
158
|
+
colors: true,
|
|
159
|
+
chunks: false,
|
|
160
|
+
modules: false,
|
|
161
|
+
assets: true,
|
|
162
|
+
performance: true,
|
|
163
|
+
})
|
|
164
|
+
);
|
|
165
|
+
|
|
166
|
+
// Generate deployment info
|
|
167
|
+
generateDeploymentInfo(stats, config);
|
|
168
|
+
|
|
169
|
+
compiler.close((closeErr) => {
|
|
170
|
+
if (closeErr) {
|
|
171
|
+
console.error('Error closing compiler:', closeErr);
|
|
172
|
+
}
|
|
173
|
+
});
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// Generate deployment information file
|
|
178
|
+
function generateDeploymentInfo(stats, config) {
|
|
179
|
+
const distPath = config.output.path;
|
|
180
|
+
const deploymentInfo = {
|
|
181
|
+
buildTime: new Date().toISOString(),
|
|
182
|
+
mode: config.mode,
|
|
183
|
+
isDevelopment: isDev,
|
|
184
|
+
assets: [],
|
|
185
|
+
entrypoints: {},
|
|
186
|
+
performance: {
|
|
187
|
+
totalSize: 0,
|
|
188
|
+
maxAssetSize: config.performance?.maxAssetSize || 'unlimited',
|
|
189
|
+
maxEntrypointSize: config.performance?.maxEntrypointSize || 'unlimited',
|
|
190
|
+
},
|
|
191
|
+
d365Integration: {
|
|
192
|
+
singleFileDeployment: !config.optimization.splitChunks,
|
|
193
|
+
webResourceReady: true,
|
|
194
|
+
customPageReady: true,
|
|
195
|
+
pcfReady: true,
|
|
196
|
+
},
|
|
197
|
+
};
|
|
198
|
+
|
|
199
|
+
const compilation = stats.compilation;
|
|
200
|
+
|
|
201
|
+
// Collect asset information
|
|
202
|
+
Object.keys(compilation.assets).forEach((assetName) => {
|
|
203
|
+
const asset = compilation.assets[assetName];
|
|
204
|
+
const assetInfo = {
|
|
205
|
+
name: assetName,
|
|
206
|
+
size: asset.size(),
|
|
207
|
+
type: path.extname(assetName) || 'unknown',
|
|
208
|
+
};
|
|
209
|
+
deploymentInfo.assets.push(assetInfo);
|
|
210
|
+
deploymentInfo.performance.totalSize += assetInfo.size;
|
|
211
|
+
});
|
|
212
|
+
|
|
213
|
+
// Collect entrypoint information
|
|
214
|
+
if (compilation.entrypoints) {
|
|
215
|
+
compilation.entrypoints.forEach((entrypoint, entryName) => {
|
|
216
|
+
const files = entrypoint.getFiles ? entrypoint.getFiles() : [];
|
|
217
|
+
deploymentInfo.entrypoints[entryName] = {
|
|
218
|
+
assets: files,
|
|
219
|
+
size: files.reduce((total, fileName) => {
|
|
220
|
+
const asset = compilation.assets[fileName];
|
|
221
|
+
return total + (asset ? asset.size() : 0);
|
|
222
|
+
}, 0),
|
|
223
|
+
};
|
|
224
|
+
});
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
// Write deployment info file
|
|
228
|
+
const deploymentInfoPath = path.join(distPath, 'deployment-info.json');
|
|
229
|
+
fs.writeFileSync(deploymentInfoPath, JSON.stringify(deploymentInfo, null, 2));
|
|
230
|
+
|
|
231
|
+
console.log('\n📋 Deployment Information:');
|
|
232
|
+
console.log(
|
|
233
|
+
` Total bundle size: ${(deploymentInfo.performance.totalSize / 1024).toFixed(2)} KB`
|
|
234
|
+
);
|
|
235
|
+
console.log(` Assets generated: ${deploymentInfo.assets.length}`);
|
|
236
|
+
console.log(` Deployment info saved: ${deploymentInfoPath}`);
|
|
237
|
+
|
|
238
|
+
// D365 deployment recommendations
|
|
239
|
+
console.log('\n🚀 D365 Deployment Guidelines:');
|
|
240
|
+
console.log(' 1. Upload JS files as Script (JScript) web resources');
|
|
241
|
+
console.log(' 2. Upload CSS files as Style Sheet (CSS) web resources');
|
|
242
|
+
console.log(' 3. Upload HTML file as Web Page (HTML) web resource');
|
|
243
|
+
console.log(' 4. Set "Available for Dynamics 365 mobile" if needed');
|
|
244
|
+
console.log(' 5. Publish all web resources after upload');
|
|
245
|
+
|
|
246
|
+
if (deploymentInfo.performance.totalSize > 1000000) {
|
|
247
|
+
console.log('\n⚠️ Warning: Bundle size is large (>1MB). Consider:');
|
|
248
|
+
console.log(' - Using code splitting for better performance');
|
|
249
|
+
console.log(' - Removing unused dependencies');
|
|
250
|
+
console.log(' - Enabling compression in D365');
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
// Start the build
|
|
255
|
+
build();
|
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
# Client Project Architecture Template
|
|
2
|
+
|
|
3
|
+
This template provides a standardized structure for multi-client Dynamics 365 consulting projects.
|
|
4
|
+
|
|
5
|
+
## Directory Structure
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
client-project/
|
|
9
|
+
├── config/
|
|
10
|
+
│ ├── client.json # Client-specific configuration
|
|
11
|
+
│ ├── environments/ # Environment configurations
|
|
12
|
+
│ │ ├── dev.json
|
|
13
|
+
│ │ ├── test.json
|
|
14
|
+
│ │ └── prod.json
|
|
15
|
+
│ └── deployment.json # Deployment settings
|
|
16
|
+
├── src/
|
|
17
|
+
│ ├── branding/ # Client-specific branding
|
|
18
|
+
│ │ ├── theme.ts # Theme customization
|
|
19
|
+
│ │ ├── logos/ # Client logos and assets
|
|
20
|
+
│ │ └── styles.css # Client-specific styles
|
|
21
|
+
│ ├── entities/ # Client entity definitions
|
|
22
|
+
│ │ ├── custom/ # Custom entities
|
|
23
|
+
│ │ └── extensions/ # Standard entity extensions
|
|
24
|
+
│ ├── workflows/ # Business logic workflows
|
|
25
|
+
│ ├── integrations/ # External system integrations
|
|
26
|
+
│ └── reports/ # Custom reports and dashboards
|
|
27
|
+
├── deployment/
|
|
28
|
+
│ ├── scripts/ # Deployment automation
|
|
29
|
+
│ ├── solutions/ # Dynamics 365 solutions
|
|
30
|
+
│ └── documentation/ # Deployment guides
|
|
31
|
+
└── docs/
|
|
32
|
+
├── client-requirements.md # Client-specific requirements
|
|
33
|
+
├── technical-specifications.md
|
|
34
|
+
└── user-guides/
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## Configuration Files
|
|
38
|
+
|
|
39
|
+
### client.json
|
|
40
|
+
```json
|
|
41
|
+
{
|
|
42
|
+
"name": "Client Name",
|
|
43
|
+
"code": "CLI",
|
|
44
|
+
"industry": "Manufacturing",
|
|
45
|
+
"timezone": "America/New_York",
|
|
46
|
+
"locale": "en-US",
|
|
47
|
+
"branding": {
|
|
48
|
+
"primaryColor": "#0078d4",
|
|
49
|
+
"secondaryColor": "#106ebe",
|
|
50
|
+
"logoPath": "src/branding/logos/client-logo.png"
|
|
51
|
+
},
|
|
52
|
+
"features": {
|
|
53
|
+
"enableAdvancedLogging": true,
|
|
54
|
+
"enableCustomWorkflows": true,
|
|
55
|
+
"enableReporting": true
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
### environments/prod.json
|
|
61
|
+
```json
|
|
62
|
+
{
|
|
63
|
+
"name": "Production",
|
|
64
|
+
"dynamics365Url": "https://client.crm.dynamics.com",
|
|
65
|
+
"webApiUrl": "https://client.api.crm.dynamics.com/api/data/v9.2",
|
|
66
|
+
"tenantId": "client-tenant-id",
|
|
67
|
+
"clientId": "client-app-id",
|
|
68
|
+
"security": {
|
|
69
|
+
"enableAuditLogging": true,
|
|
70
|
+
"requireMFA": true,
|
|
71
|
+
"sessionTimeout": 480
|
|
72
|
+
},
|
|
73
|
+
"performance": {
|
|
74
|
+
"enableCaching": true,
|
|
75
|
+
"batchSize": 100,
|
|
76
|
+
"timeoutMs": 30000
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
## Usage
|
|
82
|
+
|
|
83
|
+
1. **Initialize Client Project**:
|
|
84
|
+
```bash
|
|
85
|
+
create-dynamics-app my-client-project --client-name "ACME Corp" --entities "opportunity,quote,invoice"
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
2. **Configure Client Settings**:
|
|
89
|
+
- Update `config/client.json` with client details
|
|
90
|
+
- Customize branding in `src/branding/`
|
|
91
|
+
- Configure environments in `config/environments/`
|
|
92
|
+
|
|
93
|
+
3. **Generate Custom Entities**:
|
|
94
|
+
```bash
|
|
95
|
+
npm run generate:entity -- --entity customopportunity --display-name "Custom Opportunity"
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
4. **Deploy to Environment**:
|
|
99
|
+
```bash
|
|
100
|
+
npm run deploy:prod
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
## Best Practices
|
|
104
|
+
|
|
105
|
+
### Multi-Tenant Considerations
|
|
106
|
+
- Use environment-specific configurations
|
|
107
|
+
- Implement client-specific theming
|
|
108
|
+
- Maintain separate deployment pipelines
|
|
109
|
+
- Use feature flags for client-specific functionality
|
|
110
|
+
|
|
111
|
+
### Security
|
|
112
|
+
- Store sensitive configuration in Azure Key Vault
|
|
113
|
+
- Use managed identities for authentication
|
|
114
|
+
- Implement proper access controls
|
|
115
|
+
- Enable audit logging
|
|
116
|
+
|
|
117
|
+
### Development Workflow
|
|
118
|
+
1. Create feature branch for client customization
|
|
119
|
+
2. Implement and test changes
|
|
120
|
+
3. Run quality checks: `npm run quality`
|
|
121
|
+
4. Deploy to test environment
|
|
122
|
+
5. Get client approval
|
|
123
|
+
6. Deploy to production
|
|
124
|
+
|
|
125
|
+
### Code Organization
|
|
126
|
+
- Keep client-specific code in dedicated directories
|
|
127
|
+
- Use dependency injection for client configurations
|
|
128
|
+
- Implement factory patterns for environment-specific services
|
|
129
|
+
- Document all customizations
|
|
130
|
+
|
|
131
|
+
## Deployment
|
|
132
|
+
|
|
133
|
+
### Automated Deployment
|
|
134
|
+
The template includes scripts for automated deployment:
|
|
135
|
+
|
|
136
|
+
```bash
|
|
137
|
+
# Deploy to specific environment
|
|
138
|
+
./scripts/deploy.sh dev
|
|
139
|
+
./scripts/deploy.sh test
|
|
140
|
+
./scripts/deploy.sh prod
|
|
141
|
+
|
|
142
|
+
# Deploy with client validation
|
|
143
|
+
./scripts/deploy-client.sh --client ACME --env prod
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
### Manual Deployment Checklist
|
|
147
|
+
- [ ] Update client configuration
|
|
148
|
+
- [ ] Build and test locally
|
|
149
|
+
- [ ] Deploy to test environment
|
|
150
|
+
- [ ] Run smoke tests
|
|
151
|
+
- [ ] Get client sign-off
|
|
152
|
+
- [ ] Deploy to production
|
|
153
|
+
- [ ] Verify deployment
|
|
154
|
+
- [ ] Update documentation
|
|
155
|
+
|
|
156
|
+
## Customization Examples
|
|
157
|
+
|
|
158
|
+
### Client Theming
|
|
159
|
+
```typescript
|
|
160
|
+
// src/branding/theme.ts
|
|
161
|
+
export const clientTheme = {
|
|
162
|
+
palette: {
|
|
163
|
+
themePrimary: '#0078d4',
|
|
164
|
+
themeSecondary: '#106ebe',
|
|
165
|
+
neutralPrimary: '#323130'
|
|
166
|
+
},
|
|
167
|
+
fonts: {
|
|
168
|
+
medium: {
|
|
169
|
+
fontFamily: 'Client Corporate Font, Segoe UI, sans-serif'
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
};
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
### Custom Entity Extensions
|
|
176
|
+
```typescript
|
|
177
|
+
// src/entities/extensions/OpportunityExtensions.ts
|
|
178
|
+
export class ClientOpportunity extends Opportunity {
|
|
179
|
+
public customField1: string = '';
|
|
180
|
+
public customField2: number = 0;
|
|
181
|
+
|
|
182
|
+
public validateClientSpecificRules(): ValidationResult {
|
|
183
|
+
// Client-specific validation logic
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
### Environment-Specific Services
|
|
189
|
+
```typescript
|
|
190
|
+
// src/services/ClientServiceFactory.ts
|
|
191
|
+
export class ClientServiceFactory {
|
|
192
|
+
public static createApiService(environment: string): IApiService {
|
|
193
|
+
const config = getEnvironmentConfig(environment);
|
|
194
|
+
|
|
195
|
+
if (config.enableMockServices) {
|
|
196
|
+
return new MockApiService();
|
|
197
|
+
} else {
|
|
198
|
+
return new XrmApiService(config);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
## Maintenance
|
|
205
|
+
|
|
206
|
+
### Regular Tasks
|
|
207
|
+
- Update client configurations as requirements change
|
|
208
|
+
- Monitor deployment success rates
|
|
209
|
+
- Review and update documentation
|
|
210
|
+
- Conduct security audits
|
|
211
|
+
- Performance monitoring and optimization
|
|
212
|
+
|
|
213
|
+
### Upgrade Path
|
|
214
|
+
1. Test new framework versions in dev environment
|
|
215
|
+
2. Update client projects incrementally
|
|
216
|
+
3. Maintain backward compatibility
|
|
217
|
+
4. Document breaking changes
|
|
218
|
+
5. Coordinate client upgrade schedules
|
|
219
|
+
|
|
220
|
+
## Support
|
|
221
|
+
|
|
222
|
+
For client project support:
|
|
223
|
+
1. Check project documentation in `docs/`
|
|
224
|
+
2. Review deployment logs
|
|
225
|
+
3. Contact development team with client context
|
|
226
|
+
4. Escalate to client success team if needed
|
|
227
|
+
|
|
228
|
+
## Templates Available
|
|
229
|
+
|
|
230
|
+
- **Standard CRM**: Contact, Account, Opportunity management
|
|
231
|
+
- **Sales Pipeline**: Quote, Order, Invoice workflow
|
|
232
|
+
- **Service Management**: Case, Knowledge base, SLA tracking
|
|
233
|
+
- **Project Management**: Project, Task, Resource allocation
|
|
234
|
+
- **Custom Industry**: Tailored for specific industry needs
|
package/templates/dynamics-365-starter/src/client-project-template/config/client.template.json
ADDED
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "{{clientName}}",
|
|
3
|
+
"code": "{{clientCode}}",
|
|
4
|
+
"industry": "{{industry}}",
|
|
5
|
+
"timezone": "{{timezone}}",
|
|
6
|
+
"locale": "{{locale}}",
|
|
7
|
+
"version": "1.0.0",
|
|
8
|
+
"created": "{{currentDate}}",
|
|
9
|
+
"lastUpdated": "{{currentDate}}",
|
|
10
|
+
"contact": {
|
|
11
|
+
"primaryContact": "{{primaryContact}}",
|
|
12
|
+
"email": "{{contactEmail}}",
|
|
13
|
+
"phone": "{{contactPhone}}"
|
|
14
|
+
},
|
|
15
|
+
"branding": {
|
|
16
|
+
"primaryColor": "{{primaryColor}}",
|
|
17
|
+
"secondaryColor": "{{secondaryColor}}",
|
|
18
|
+
"accentColor": "{{accentColor}}",
|
|
19
|
+
"logoPath": "src/branding/logos/{{clientCode}}-logo.png",
|
|
20
|
+
"faviconPath": "src/branding/logos/{{clientCode}}-favicon.ico",
|
|
21
|
+
"fontFamily": "{{fontFamily}}",
|
|
22
|
+
"customCss": "src/branding/{{clientCode}}-custom.css"
|
|
23
|
+
},
|
|
24
|
+
"features": {
|
|
25
|
+
"enableAdvancedLogging": true,
|
|
26
|
+
"enableCustomWorkflows": true,
|
|
27
|
+
"enableReporting": true,
|
|
28
|
+
"enableMobileOptimization": true,
|
|
29
|
+
"enableOfflineCapability": false,
|
|
30
|
+
"enableMultiLanguage": false,
|
|
31
|
+
"enableCustomDashboards": true,
|
|
32
|
+
"enableDataExport": true,
|
|
33
|
+
"enableBulkOperations": true,
|
|
34
|
+
"enableAdvancedSecurity": true
|
|
35
|
+
},
|
|
36
|
+
"customEntities": [
|
|
37
|
+
{{#each customEntities}}
|
|
38
|
+
{
|
|
39
|
+
"name": "{{name}}",
|
|
40
|
+
"displayName": "{{displayName}}",
|
|
41
|
+
"description": "{{description}}",
|
|
42
|
+
"enabled": true
|
|
43
|
+
}{{#unless @last}},{{/unless}}
|
|
44
|
+
{{/each}}
|
|
45
|
+
],
|
|
46
|
+
"integrations": {
|
|
47
|
+
"sharepoint": {
|
|
48
|
+
"enabled": false,
|
|
49
|
+
"siteUrl": ""
|
|
50
|
+
},
|
|
51
|
+
"teams": {
|
|
52
|
+
"enabled": false,
|
|
53
|
+
"appId": ""
|
|
54
|
+
},
|
|
55
|
+
"powerBI": {
|
|
56
|
+
"enabled": false,
|
|
57
|
+
"workspaceId": ""
|
|
58
|
+
},
|
|
59
|
+
"powerAutomate": {
|
|
60
|
+
"enabled": true
|
|
61
|
+
},
|
|
62
|
+
"externalAPIs": [
|
|
63
|
+
{{#each externalAPIs}}
|
|
64
|
+
{
|
|
65
|
+
"name": "{{name}}",
|
|
66
|
+
"endpoint": "{{endpoint}}",
|
|
67
|
+
"authType": "{{authType}}",
|
|
68
|
+
"enabled": {{enabled}}
|
|
69
|
+
}{{#unless @last}},{{/unless}}
|
|
70
|
+
{{/each}}
|
|
71
|
+
]
|
|
72
|
+
},
|
|
73
|
+
"compliance": {
|
|
74
|
+
"gdprCompliant": true,
|
|
75
|
+
"hipaaCompliant": false,
|
|
76
|
+
"soxCompliant": false,
|
|
77
|
+
"auditRetentionDays": 365,
|
|
78
|
+
"dataClassification": "Internal"
|
|
79
|
+
},
|
|
80
|
+
"deployment": {
|
|
81
|
+
"strategy": "blue-green",
|
|
82
|
+
"rollbackEnabled": true,
|
|
83
|
+
"approvalRequired": true,
|
|
84
|
+
"notificationEmail": "{{contactEmail}}",
|
|
85
|
+
"maintenanceWindow": {
|
|
86
|
+
"timezone": "{{timezone}}",
|
|
87
|
+
"startTime": "02:00",
|
|
88
|
+
"duration": 120
|
|
89
|
+
}
|
|
90
|
+
},
|
|
91
|
+
"support": {
|
|
92
|
+
"level": "Enterprise",
|
|
93
|
+
"hours": "24/7",
|
|
94
|
+
"escalationEmail": "{{supportEmail}}",
|
|
95
|
+
"slaTier": "Gold"
|
|
96
|
+
},
|
|
97
|
+
"customizations": {
|
|
98
|
+
"entities": {
|
|
99
|
+
"naming": "{{clientCode}}_",
|
|
100
|
+
"prefix": "{{clientCode}}",
|
|
101
|
+
"suffix": ""
|
|
102
|
+
},
|
|
103
|
+
"workflows": {
|
|
104
|
+
"customValidation": true,
|
|
105
|
+
"customBusinessLogic": true,
|
|
106
|
+
"customIntegrations": true
|
|
107
|
+
},
|
|
108
|
+
"ui": {
|
|
109
|
+
"customTheme": true,
|
|
110
|
+
"customComponents": true,
|
|
111
|
+
"customLayouts": true
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|