@khester/create-dynamics-app 2.10.0 → 3.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/README.md +28 -3
- package/dist/artifacts/registry.d.ts +7 -5
- package/dist/artifacts/registry.d.ts.map +1 -1
- package/dist/artifacts/registry.js +82 -27
- package/dist/artifacts/registry.js.map +1 -1
- package/dist/artifacts/types.d.ts +15 -8
- package/dist/artifacts/types.d.ts.map +1 -1
- package/dist/index.js +7 -5
- package/dist/index.js.map +1 -1
- package/dist/scaffold.d.ts.map +1 -1
- package/dist/scaffold.js +9 -4
- package/dist/scaffold.js.map +1 -1
- package/dist/templatePlan.d.ts.map +1 -1
- package/dist/templatePlan.js +20 -3
- package/dist/templatePlan.js.map +1 -1
- package/dist/utils/copyTemplate.d.ts +1 -1
- package/dist/utils/copyTemplate.d.ts.map +1 -1
- package/dist/utils/copyTemplate.js +5 -1
- package/dist/utils/copyTemplate.js.map +1 -1
- package/package.json +1 -1
- package/templates/_shared/dataverse-seam/XrmApiService.ts +26 -5
- package/templates/host-swap/README.md +57 -2
- package/templates/host-swap/_variants/host.custom-page/src/App.tsx +9 -5
- package/templates/host-swap/_variants/host.pcf/ControlManifest.Input.xml +26 -2
- package/templates/host-swap/_variants/host.pcf/gitignore +7 -0
- package/templates/host-swap/_variants/host.pcf/index.ts +21 -3
- package/templates/host-swap/_variants/host.pcf/package.json +20 -4
- package/templates/host-swap/_variants/host.pcf/{{componentName}}.pcfproj +67 -0
- package/templates/host-swap/_variants/host.web-resource/src/App.tsx +5 -1
- package/templates/host-swap/src/Component.tsx +54 -7
- package/templates/host-swap/src/useHostWidth.ts +53 -0
- package/templates/pcf-dataset/dev/harness/dataverse.ts +82 -0
- package/templates/pcf-dataset/dev/index.html +20 -0
- package/templates/pcf-dataset/dev/main.tsx +190 -0
- package/templates/pcf-dataset/dev/vite-env.d.ts +1 -0
- package/templates/pcf-dataset/env.local.example +24 -0
- package/templates/pcf-dataset/eslintrc.json +11 -0
- package/templates/pcf-dataset/gitignore +4 -0
- package/templates/pcf-dataset/package.json +18 -8
- package/templates/pcf-dataset/pcfconfig.json +3 -0
- package/templates/pcf-dataset/tsconfig.dev.json +15 -0
- package/templates/pcf-dataset/tsconfig.json +11 -2
- package/templates/pcf-dataset/vite.config.ts +63 -0
- package/templates/pcf-dataset/{{componentName}}/ControlManifest.Input.xml +45 -0
- package/templates/pcf-dataset/{{componentName}}/{{componentName}}App.tsx +64 -0
- package/templates/pcf-dataset/{{{componentName}}Component.tsx → {{componentName}}/{{componentName}}Component.tsx} +9 -46
- package/templates/pcf-field/eslintrc.json +11 -0
- package/templates/pcf-field/package.json +1 -0
- package/templates/pcf-field/pcfconfig.json +3 -0
- package/templates/pcf-field/{{componentName}}/ControlManifest.Input.xml +42 -0
- package/templates/power-pages-island/README.md +93 -0
- package/templates/power-pages-island/package.json +27 -0
- package/templates/power-pages-island/public/index.html +13 -0
- package/templates/power-pages-island/src/App.tsx +37 -0
- package/templates/power-pages-island/src/Component.tsx +136 -0
- package/templates/power-pages-island/src/core/services/MockApiService.ts +58 -0
- package/templates/power-pages-island/src/core/services/portalSeam.assert.ts +14 -0
- package/templates/power-pages-island/src/island-env.d.ts +12 -0
- package/templates/power-pages-island/src/islands.tsx +38 -0
- package/templates/power-pages-island/src/useHostWidth.ts +53 -0
- package/templates/power-pages-island/tsconfig.json +15 -0
- package/templates/power-pages-island/webpack.config.js +22 -0
- package/templates/react-custom-page/tools/deploy/deploy-webresource.cjs +8 -2
- package/templates/pcf-dataset/ControlManifest.Input.xml +0 -16
- package/templates/pcf-field/ControlManifest.Input.xml +0 -17
- package/templates/power-pages-starter/.env.example +0 -6
- package/templates/power-pages-starter/README.md +0 -95
- package/templates/power-pages-starter/package.json +0 -43
- package/templates/power-pages-starter/public/index.html +0 -15
- package/templates/power-pages-starter/src/components/ContactForm.css +0 -84
- package/templates/power-pages-starter/src/components/ContactForm.tsx +0 -258
- package/templates/power-pages-starter/src/index.tsx +0 -32
- package/templates/power-pages-starter/src/providers/PowerPagesProvider.tsx +0 -162
- package/templates/power-pages-starter/src/styles/index.css +0 -76
- package/templates/power-pages-starter/tsconfig.json +0 -20
- package/templates/power-pages-starter/webpack.config.js +0 -57
- package/templates/pcf-dataset/{index.ts → {{componentName}}/index.ts} +0 -0
- package/templates/pcf-dataset/{strings → {{componentName}}/strings}/{{componentName}}.1033.resx +0 -0
- package/templates/pcf-field/{index.ts → {{componentName}}/index.ts} +0 -0
- package/templates/pcf-field/{strings → {{componentName}}/strings}/{{componentName}}.1033.resx +0 -0
- package/templates/pcf-field/{{{componentName}}Component.tsx → {{componentName}}/{{componentName}}Component.tsx} +0 -0
- package/templates/{power-pages-starter → power-pages-island}/gitignore +1 -1
|
@@ -1,162 +0,0 @@
|
|
|
1
|
-
import React, { createContext, useContext, useState, useEffect } from 'react';
|
|
2
|
-
import { PowerPagesApiService } from '@khester/dynamics-ui-api-client';
|
|
3
|
-
|
|
4
|
-
interface PowerPagesContextType {
|
|
5
|
-
apiService: PowerPagesApiService | null;
|
|
6
|
-
isAuthenticated: boolean;
|
|
7
|
-
createRecord: (entityName: string, data: any) => Promise<any>;
|
|
8
|
-
retrieveRecord: (
|
|
9
|
-
entityName: string,
|
|
10
|
-
id: string,
|
|
11
|
-
select?: string
|
|
12
|
-
) => Promise<any>;
|
|
13
|
-
updateRecord: (entityName: string, id: string, data: any) => Promise<any>;
|
|
14
|
-
deleteRecord: (entityName: string, id: string) => Promise<void>;
|
|
15
|
-
retrieveMultiple: (entityName: string, query?: string) => Promise<any>;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
const PowerPagesContext = createContext<PowerPagesContextType | undefined>(
|
|
19
|
-
undefined
|
|
20
|
-
);
|
|
21
|
-
|
|
22
|
-
interface PowerPagesProviderProps {
|
|
23
|
-
children: React.ReactNode;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
export const PowerPagesProvider: React.FC<PowerPagesProviderProps> = ({
|
|
27
|
-
children,
|
|
28
|
-
}) => {
|
|
29
|
-
const [apiService, setApiService] = useState<PowerPagesApiService | null>(
|
|
30
|
-
null
|
|
31
|
-
);
|
|
32
|
-
const [isAuthenticated, setIsAuthenticated] = useState(false);
|
|
33
|
-
|
|
34
|
-
useEffect(() => {
|
|
35
|
-
// Initialize the API service
|
|
36
|
-
const portalUrl = window.location.origin;
|
|
37
|
-
|
|
38
|
-
// CSRF token function for Power Pages authentication
|
|
39
|
-
const getCsrfToken = async (): Promise<string> => {
|
|
40
|
-
// In a real Power Pages implementation, you would fetch the CSRF token
|
|
41
|
-
// For demo purposes, return empty string
|
|
42
|
-
return '';
|
|
43
|
-
};
|
|
44
|
-
|
|
45
|
-
const service = new PowerPagesApiService(portalUrl, getCsrfToken);
|
|
46
|
-
|
|
47
|
-
setApiService(service);
|
|
48
|
-
|
|
49
|
-
// Check authentication status
|
|
50
|
-
// In a real implementation, you would check if the user is logged in to the portal
|
|
51
|
-
// For demo purposes, we'll assume they are authenticated
|
|
52
|
-
setIsAuthenticated(true);
|
|
53
|
-
}, []);
|
|
54
|
-
|
|
55
|
-
const createRecord = async (entityName: string, data: any) => {
|
|
56
|
-
if (!apiService) throw new Error('API service not initialized');
|
|
57
|
-
return await apiService.createRecord(entityName, data);
|
|
58
|
-
};
|
|
59
|
-
|
|
60
|
-
const retrieveRecord = async (
|
|
61
|
-
entityName: string,
|
|
62
|
-
id: string,
|
|
63
|
-
select?: string
|
|
64
|
-
) => {
|
|
65
|
-
if (!apiService) throw new Error('API service not initialized');
|
|
66
|
-
// Use retrieveMultipleRecords with FetchXML to get a single record
|
|
67
|
-
const selectAttributes = select
|
|
68
|
-
? select.split(',').map((attr) => attr.trim())
|
|
69
|
-
: ['*'];
|
|
70
|
-
const attributes = selectAttributes
|
|
71
|
-
.map((attr) => (attr === '*' ? '' : `<attribute name="${attr}" />`))
|
|
72
|
-
.join('');
|
|
73
|
-
const fetchXml = `
|
|
74
|
-
<fetch top="1">
|
|
75
|
-
<entity name="${entityName}">
|
|
76
|
-
${attributes}
|
|
77
|
-
<filter>
|
|
78
|
-
<condition attribute="${entityName}id" operator="eq" value="${id}" />
|
|
79
|
-
</filter>
|
|
80
|
-
</entity>
|
|
81
|
-
</fetch>
|
|
82
|
-
`;
|
|
83
|
-
const result = await apiService.retrieveMultipleRecords(
|
|
84
|
-
entityName,
|
|
85
|
-
fetchXml
|
|
86
|
-
);
|
|
87
|
-
return result.entities.length > 0 ? result.entities[0] : null;
|
|
88
|
-
};
|
|
89
|
-
|
|
90
|
-
const updateRecord = async (entityName: string, id: string, data: any) => {
|
|
91
|
-
if (!apiService) throw new Error('API service not initialized');
|
|
92
|
-
return await apiService.updateRecord(entityName, id, data);
|
|
93
|
-
};
|
|
94
|
-
|
|
95
|
-
const deleteRecord = async (entityName: string, id: string) => {
|
|
96
|
-
if (!apiService) throw new Error('API service not initialized');
|
|
97
|
-
return await apiService.deleteRecord(entityName, id);
|
|
98
|
-
};
|
|
99
|
-
|
|
100
|
-
const retrieveMultiple = async (entityName: string, query?: string) => {
|
|
101
|
-
if (!apiService) throw new Error('API service not initialized');
|
|
102
|
-
// Convert OData-style query to FetchXML
|
|
103
|
-
let fetchXml = `<fetch>`;
|
|
104
|
-
|
|
105
|
-
if (query) {
|
|
106
|
-
// Parse basic OData query parameters
|
|
107
|
-
const selectMatch = query.match(/\$select=([^&]*)/i);
|
|
108
|
-
const orderByMatch = query.match(/\$orderby=([^&]*)/i);
|
|
109
|
-
const topMatch = query.match(/\$top=(\d+)/i);
|
|
110
|
-
|
|
111
|
-
if (topMatch) {
|
|
112
|
-
fetchXml = `<fetch top="${topMatch[1]}">`;
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
fetchXml += `<entity name="${entityName}">`;
|
|
116
|
-
|
|
117
|
-
if (selectMatch) {
|
|
118
|
-
const attributes = selectMatch[1].split(',').map((attr) => attr.trim());
|
|
119
|
-
attributes.forEach((attr) => {
|
|
120
|
-
fetchXml += `<attribute name="${attr}" />`;
|
|
121
|
-
});
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
if (orderByMatch) {
|
|
125
|
-
const [field, direction] = orderByMatch[1].split(' ');
|
|
126
|
-
fetchXml += `<order attribute="${field.trim()}" descending="${direction?.toLowerCase() === 'desc'}" />`;
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
fetchXml += `</entity></fetch>`;
|
|
130
|
-
} else {
|
|
131
|
-
fetchXml = `<fetch><entity name="${entityName}"></entity></fetch>`;
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
return await apiService.retrieveMultipleRecords(entityName, fetchXml);
|
|
135
|
-
};
|
|
136
|
-
|
|
137
|
-
const value: PowerPagesContextType = {
|
|
138
|
-
apiService,
|
|
139
|
-
isAuthenticated,
|
|
140
|
-
createRecord,
|
|
141
|
-
retrieveRecord,
|
|
142
|
-
updateRecord,
|
|
143
|
-
deleteRecord,
|
|
144
|
-
retrieveMultiple,
|
|
145
|
-
};
|
|
146
|
-
|
|
147
|
-
return (
|
|
148
|
-
<PowerPagesContext.Provider value={value}>
|
|
149
|
-
{children}
|
|
150
|
-
</PowerPagesContext.Provider>
|
|
151
|
-
);
|
|
152
|
-
};
|
|
153
|
-
|
|
154
|
-
export const usePowerPagesApi = (): PowerPagesContextType => {
|
|
155
|
-
const context = useContext(PowerPagesContext);
|
|
156
|
-
if (context === undefined) {
|
|
157
|
-
throw new Error(
|
|
158
|
-
'usePowerPagesApi must be used within a PowerPagesProvider'
|
|
159
|
-
);
|
|
160
|
-
}
|
|
161
|
-
return context;
|
|
162
|
-
};
|
|
@@ -1,76 +0,0 @@
|
|
|
1
|
-
/* Global Styles */
|
|
2
|
-
* {
|
|
3
|
-
box-sizing: border-box;
|
|
4
|
-
}
|
|
5
|
-
|
|
6
|
-
body {
|
|
7
|
-
margin: 0;
|
|
8
|
-
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
|
|
9
|
-
'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
|
|
10
|
-
sans-serif;
|
|
11
|
-
-webkit-font-smoothing: antialiased;
|
|
12
|
-
-moz-osx-font-smoothing: grayscale;
|
|
13
|
-
background-color: #f5f5f5;
|
|
14
|
-
color: #323130;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
.app {
|
|
18
|
-
min-height: 100vh;
|
|
19
|
-
display: flex;
|
|
20
|
-
flex-direction: column;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
.app-header {
|
|
24
|
-
background: linear-gradient(135deg, #0078d4 0%, #106ebe 100%);
|
|
25
|
-
color: white;
|
|
26
|
-
padding: 24px;
|
|
27
|
-
text-align: center;
|
|
28
|
-
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
.app-header h1 {
|
|
32
|
-
margin: 0 0 8px 0;
|
|
33
|
-
font-size: 28px;
|
|
34
|
-
font-weight: 600;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
.app-header p {
|
|
38
|
-
margin: 0;
|
|
39
|
-
font-size: 16px;
|
|
40
|
-
opacity: 0.9;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
.app-main {
|
|
44
|
-
flex: 1;
|
|
45
|
-
padding: 32px 16px;
|
|
46
|
-
max-width: 1200px;
|
|
47
|
-
margin: 0 auto;
|
|
48
|
-
width: 100%;
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
.app-footer {
|
|
52
|
-
background-color: #f3f2f1;
|
|
53
|
-
border-top: 1px solid #edebe9;
|
|
54
|
-
padding: 16px;
|
|
55
|
-
text-align: center;
|
|
56
|
-
color: #605e5c;
|
|
57
|
-
font-size: 14px;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
.app-footer p {
|
|
61
|
-
margin: 0;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
@media (max-width: 768px) {
|
|
65
|
-
.app-header {
|
|
66
|
-
padding: 16px;
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
.app-header h1 {
|
|
70
|
-
font-size: 24px;
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
.app-main {
|
|
74
|
-
padding: 16px 8px;
|
|
75
|
-
}
|
|
76
|
-
}
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"compilerOptions": {
|
|
3
|
-
"target": "es5",
|
|
4
|
-
"lib": ["dom", "dom.iterable", "es6"],
|
|
5
|
-
"allowJs": true,
|
|
6
|
-
"skipLibCheck": true,
|
|
7
|
-
"esModuleInterop": true,
|
|
8
|
-
"allowSyntheticDefaultImports": true,
|
|
9
|
-
"strict": true,
|
|
10
|
-
"forceConsistentCasingInFileNames": true,
|
|
11
|
-
"noFallthroughCasesInSwitch": true,
|
|
12
|
-
"module": "esnext",
|
|
13
|
-
"moduleResolution": "node",
|
|
14
|
-
"resolveJsonModule": true,
|
|
15
|
-
"isolatedModules": true,
|
|
16
|
-
"noEmit": true,
|
|
17
|
-
"jsx": "react-jsx"
|
|
18
|
-
},
|
|
19
|
-
"include": ["src"]
|
|
20
|
-
}
|
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
const path = require('path');
|
|
2
|
-
const HtmlWebpackPlugin = require('html-webpack-plugin');
|
|
3
|
-
|
|
4
|
-
module.exports = (env, argv) => {
|
|
5
|
-
const isProduction = argv.mode === 'production';
|
|
6
|
-
|
|
7
|
-
return {
|
|
8
|
-
entry: './src/index.tsx',
|
|
9
|
-
output: {
|
|
10
|
-
path: path.resolve(__dirname, 'dist'),
|
|
11
|
-
filename: isProduction ? '[name].[contenthash].js' : '[name].js',
|
|
12
|
-
clean: true,
|
|
13
|
-
publicPath: '/',
|
|
14
|
-
},
|
|
15
|
-
resolve: {
|
|
16
|
-
extensions: ['.tsx', '.ts', '.js', '.jsx'],
|
|
17
|
-
},
|
|
18
|
-
module: {
|
|
19
|
-
rules: [
|
|
20
|
-
{
|
|
21
|
-
test: /\.tsx?$/,
|
|
22
|
-
use: {
|
|
23
|
-
loader: 'ts-loader',
|
|
24
|
-
options: {
|
|
25
|
-
transpileOnly: true,
|
|
26
|
-
},
|
|
27
|
-
},
|
|
28
|
-
exclude: /node_modules/,
|
|
29
|
-
},
|
|
30
|
-
{
|
|
31
|
-
test: /\.css$/i,
|
|
32
|
-
use: ['style-loader', 'css-loader'],
|
|
33
|
-
},
|
|
34
|
-
],
|
|
35
|
-
},
|
|
36
|
-
plugins: [
|
|
37
|
-
new HtmlWebpackPlugin({
|
|
38
|
-
template: './public/index.html',
|
|
39
|
-
filename: 'index.html',
|
|
40
|
-
}),
|
|
41
|
-
],
|
|
42
|
-
devServer: {
|
|
43
|
-
static: {
|
|
44
|
-
directory: path.join(__dirname, 'public'),
|
|
45
|
-
},
|
|
46
|
-
port: 3000,
|
|
47
|
-
open: true,
|
|
48
|
-
hot: true,
|
|
49
|
-
historyApiFallback: true,
|
|
50
|
-
},
|
|
51
|
-
optimization: {
|
|
52
|
-
splitChunks: {
|
|
53
|
-
chunks: 'all',
|
|
54
|
-
},
|
|
55
|
-
},
|
|
56
|
-
};
|
|
57
|
-
};
|
|
File without changes
|
package/templates/pcf-dataset/{strings → {{componentName}}/strings}/{{componentName}}.1033.resx
RENAMED
|
File without changes
|
|
File without changes
|
package/templates/pcf-field/{strings → {{componentName}}/strings}/{{componentName}}.1033.resx
RENAMED
|
File without changes
|
|
File without changes
|