@khester/create-dynamics-app 1.1.0 → 2.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 +74 -0
- package/dist/artifacts/registry.d.ts +18 -0
- package/dist/artifacts/registry.d.ts.map +1 -0
- package/dist/artifacts/registry.js +340 -0
- package/dist/artifacts/registry.js.map +1 -0
- package/dist/artifacts/types.d.ts +122 -0
- package/dist/artifacts/types.d.ts.map +1 -0
- package/dist/artifacts/types.js +7 -0
- package/dist/artifacts/types.js.map +1 -0
- package/dist/artifacts/validators.d.ts +16 -0
- package/dist/artifacts/validators.d.ts.map +1 -0
- package/dist/artifacts/validators.js +45 -0
- package/dist/artifacts/validators.js.map +1 -0
- package/dist/fromDesign.d.ts +5 -0
- package/dist/fromDesign.d.ts.map +1 -0
- package/dist/fromDesign.js +98 -0
- package/dist/fromDesign.js.map +1 -0
- package/dist/index.js +129 -177
- package/dist/index.js.map +1 -1
- package/dist/injectDevTools.d.ts +28 -0
- package/dist/injectDevTools.d.ts.map +1 -0
- package/dist/injectDevTools.js +148 -0
- package/dist/injectDevTools.js.map +1 -0
- package/dist/scaffold.d.ts +48 -0
- package/dist/scaffold.d.ts.map +1 -0
- package/dist/scaffold.js +180 -0
- package/dist/scaffold.js.map +1 -0
- package/dist/templatePlan.d.ts +3 -0
- package/dist/templatePlan.d.ts.map +1 -0
- package/dist/templatePlan.js +43 -0
- package/dist/templatePlan.js.map +1 -0
- package/dist/utils/copyTemplate.d.ts +13 -1
- package/dist/utils/copyTemplate.d.ts.map +1 -1
- package/dist/utils/copyTemplate.js +98 -4
- package/dist/utils/copyTemplate.js.map +1 -1
- package/dist/utils/updatePackageJson.d.ts +11 -1
- package/dist/utils/updatePackageJson.d.ts.map +1 -1
- package/dist/utils/updatePackageJson.js +12 -10
- package/dist/utils/updatePackageJson.js.map +1 -1
- package/package.json +10 -7
- package/templates/_shared/dev-tools/auth/get-token.js +72 -0
- package/templates/_shared/dev-tools/dev/mock-xrm.js +42 -0
- package/templates/_shared/dev-tools/metadata-sync/index.js +152 -0
- package/templates/_shared/dev-tools/smoke/test-retrieve.js +44 -0
- package/templates/dialog-form/README.md +27 -0
- package/templates/dialog-form/_variants/App.v8.tsx +39 -0
- package/templates/dialog-form/_variants/App.v9.tsx +41 -0
- package/templates/dialog-form/gitignore +5 -0
- package/templates/dialog-form/package.json +27 -0
- package/templates/dialog-form/public/index.html +11 -0
- package/templates/dialog-form/src/index.tsx +10 -0
- package/templates/dialog-form/src/services/dataverse.ts +30 -0
- package/templates/dialog-form/tsconfig.json +15 -0
- package/templates/dialog-form/webpack.config.js +17 -0
- package/templates/grid-customizer/README.md +28 -0
- package/templates/grid-customizer/gitignore +4 -0
- package/templates/grid-customizer/package.json +25 -0
- package/templates/grid-customizer/src/GridCustomizer.ts +28 -0
- package/templates/grid-customizer/src/cell-renderers.tsx +35 -0
- package/templates/grid-customizer/src/index.ts +4 -0
- package/templates/grid-customizer/src/types/grid-types.ts +30 -0
- package/templates/grid-customizer/src/utils/color-utils.ts +24 -0
- package/templates/grid-customizer/tsconfig.json +15 -0
- package/templates/grid-customizer/webpack.config.js +17 -0
- package/templates/pcf-dataset/ControlManifest.Input.xml +16 -0
- package/templates/pcf-dataset/README.md +21 -0
- package/templates/pcf-dataset/gitignore +5 -0
- package/templates/pcf-dataset/index.ts +39 -0
- package/templates/pcf-dataset/package.json +30 -0
- package/templates/pcf-dataset/strings/{{componentName}}.1033.resx +47 -0
- package/templates/pcf-dataset/tsconfig.json +8 -0
- package/templates/pcf-dataset/{{componentName}}Component.tsx +39 -0
- package/templates/pcf-field/ControlManifest.Input.xml +17 -0
- package/templates/pcf-field/README.md +95 -0
- package/templates/pcf-field/_variants/ValueInput.boolean.tsx +24 -0
- package/templates/pcf-field/_variants/ValueInput.date.tsx +27 -0
- package/templates/pcf-field/_variants/ValueInput.number.tsx +35 -0
- package/templates/pcf-field/_variants/ValueInput.text.tsx +27 -0
- package/templates/pcf-field/gitignore +5 -0
- package/templates/pcf-field/index.ts +61 -0
- package/templates/pcf-field/package.json +30 -0
- package/templates/pcf-field/strings/{{componentName}}.1033.resx +47 -0
- package/templates/pcf-field/tsconfig.json +8 -0
- package/templates/pcf-field/{{componentName}}Component.tsx +35 -0
- package/templates/power-pages-starter/gitignore +5 -0
- package/templates/react-custom-page/gitignore +5 -0
- package/templates/{dynamics-365-starter → react-custom-page}/package.json +3 -3
- package/templates/react-custom-page/tools/metadata-sync/index.js +152 -0
- package/templates/static-web-app/README.md +36 -0
- package/templates/static-web-app/_variants/App.v8.tsx +32 -0
- package/templates/static-web-app/_variants/App.v9.tsx +31 -0
- package/templates/static-web-app/api/host.json +12 -0
- package/templates/static-web-app/api/package.json +19 -0
- package/templates/static-web-app/api/src/functions/hello.ts +16 -0
- package/templates/static-web-app/api/tsconfig.json +14 -0
- package/templates/static-web-app/frontend/index.html +12 -0
- package/templates/static-web-app/frontend/package.json +23 -0
- package/templates/static-web-app/frontend/src/index.tsx +8 -0
- package/templates/static-web-app/frontend/tsconfig.json +16 -0
- package/templates/static-web-app/frontend/vite.config.ts +13 -0
- package/templates/static-web-app/gitignore +8 -0
- package/templates/static-web-app/package.json +15 -0
- package/templates/static-web-app/staticwebapp.config.json +7 -0
- package/templates/teams-app/README.md +27 -0
- package/templates/teams-app/_variants/graph.off.ts +7 -0
- package/templates/teams-app/_variants/graph.on.ts +22 -0
- package/templates/teams-app/appPackage/manifest.json +26 -0
- package/templates/teams-app/gitignore +5 -0
- package/templates/teams-app/index.html +12 -0
- package/templates/teams-app/package.json +26 -0
- package/templates/teams-app/src/App.tsx +25 -0
- package/templates/teams-app/src/index.tsx +8 -0
- package/templates/teams-app/tsconfig.json +16 -0
- package/templates/teams-app/vite.config.ts +9 -0
- package/templates/web-resource/README.md +39 -0
- package/templates/web-resource/_variants/App.v8.tsx +29 -0
- package/templates/web-resource/_variants/App.v9.tsx +28 -0
- package/templates/web-resource/gitignore +5 -0
- package/templates/web-resource/package.json +27 -0
- package/templates/web-resource/public/index.html +11 -0
- package/templates/web-resource/src/index.tsx +10 -0
- package/templates/web-resource/src/services/dataverse.ts +30 -0
- package/templates/web-resource/tsconfig.json +15 -0
- package/templates/web-resource/webpack.config.js +17 -0
- package/dist/utils/consultingHelpers.d.ts +0 -13
- package/dist/utils/consultingHelpers.d.ts.map +0 -1
- package/dist/utils/consultingHelpers.js +0 -569
- package/dist/utils/consultingHelpers.js.map +0 -1
- package/templates/dynamics-365-starter/INTEGRATION_TEST_RESULTS.md +0 -302
- package/templates/dynamics-365-starter/PHASE_4_COMPLETION_SUMMARY.md +0 -305
- package/templates/dynamics-365-starter/deployment/QUICKSTART-MAC.md +0 -507
- package/templates/dynamics-365-starter/deployment/QUICKSTART-WINDOWS.md +0 -372
- package/templates/dynamics-365-starter/deployment/pipelines/README.md +0 -375
- package/templates/dynamics-365-starter/deployment/pipelines/azure-pipelines.yml +0 -330
- package/templates/dynamics-365-starter/deployment/pipelines/github-actions.yml +0 -422
- package/templates/dynamics-365-starter/deployment/pipelines/jenkins.groovy +0 -636
- package/templates/dynamics-365-starter/deployment/scripts/deploy.ps1 +0 -417
- package/templates/dynamics-365-starter/deployment/scripts/deploy.sh +0 -582
- package/templates/dynamics-365-starter/deployment/scripts/team-onboarding.ps1 +0 -486
- package/templates/dynamics-365-starter/deployment/scripts/team-onboarding.sh +0 -567
- package/templates/dynamics-365-starter/deployment/scripts/validate-setup.ps1 +0 -703
- package/templates/dynamics-365-starter/deployment/scripts/validate-setup.sh +0 -671
- package/templates/dynamics-365-starter/docs/team-standards/README.md +0 -273
- package/templates/dynamics-365-starter/docs/team-standards/client-onboarding.md +0 -577
- package/templates/dynamics-365-starter/docs/team-standards/code-review-checklist.md +0 -359
- package/templates/dynamics-365-starter/docs/team-standards/coding-standards.md +0 -700
- package/templates/dynamics-365-starter/docs/team-standards/cross-platform-team-guide.md +0 -736
- package/templates/dynamics-365-starter/docs/team-standards/development-workflows.md +0 -727
- package/templates/dynamics-365-starter/docs/troubleshooting/common-errors.md +0 -758
- package/templates/dynamics-365-starter/docs/troubleshooting/platform-specific-issues.md +0 -878
- package/templates/dynamics-365-starter/src/client-project-template/README.md +0 -234
- package/templates/dynamics-365-starter/src/client-project-template/config/client.template.json +0 -114
- package/templates/dynamics-365-starter/src/client-project-template/config/environments/template.json +0 -186
- package/templates/dynamics-365-starter/src/client-project-template/scripts/client-setup.js +0 -667
- package/templates/dynamics-365-starter/src/examples/README.md +0 -52
- package/templates/dynamics-365-starter/src/examples/component-examples/opportunity-management.tsx +0 -625
- package/templates/dynamics-365-starter/src/examples/entity-examples/opportunity-model.ts +0 -545
- package/templates/dynamics-365-starter/src/examples/integration-examples/custom-pcf-wrapper.tsx +0 -722
- package/templates/dynamics-365-starter/src/examples/workflow-examples/sales-workflow.ts +0 -662
- package/templates/dynamics-365-starter/src/page-templates/EntityDashboard.tsx +0 -519
- package/templates/dynamics-365-starter/src/page-templates/EntityDetailPage.tsx +0 -456
- package/templates/dynamics-365-starter/src/page-templates/EntityListPage.tsx +0 -406
- package/templates/dynamics-365-starter/src/page-templates/RelatedEntitiesPage.tsx +0 -578
- package/templates/dynamics-365-starter/src/page-templates/SearchPage.tsx +0 -629
- package/templates/dynamics-365-starter/tools/entity-generator/index.js +0 -168
- package/templates/dynamics-365-starter/tools/entity-generator/templates/constants.template.ts +0 -124
- package/templates/dynamics-365-starter/tools/entity-generator/templates/form.template.css +0 -283
- package/templates/dynamics-365-starter/tools/entity-generator/templates/form.template.tsx +0 -275
- package/templates/dynamics-365-starter/tools/entity-generator/templates/management.template.css +0 -204
- package/templates/dynamics-365-starter/tools/entity-generator/templates/management.template.tsx +0 -413
- package/templates/dynamics-365-starter/tools/entity-generator/templates/model.template.ts +0 -250
- package/templates/dynamics-365-starter/tools/metadata-sync/d365-client.js +0 -410
- package/templates/dynamics-365-starter/tools/metadata-sync/index.js +0 -512
- package/templates/dynamics-365-starter/tools/metadata-sync/type-generator.js +0 -675
- /package/templates/{dynamics-365-starter → react-custom-page}/README.md +0 -0
- /package/templates/{dynamics-365-starter → react-custom-page}/deployment/README.md +0 -0
- /package/templates/{dynamics-365-starter → react-custom-page}/docs/ARCHITECTURE_OVERVIEW.md +0 -0
- /package/templates/{dynamics-365-starter → react-custom-page}/docs/BEST_PRACTICES.md +0 -0
- /package/templates/{dynamics-365-starter → react-custom-page}/docs/MIGRATION_GUIDE.md +0 -0
- /package/templates/{dynamics-365-starter → react-custom-page}/public/index.html +0 -0
- /package/templates/{dynamics-365-starter → react-custom-page}/scripts/custom-build.js +0 -0
- /package/templates/{dynamics-365-starter → react-custom-page}/src/components/AccountForm.css +0 -0
- /package/templates/{dynamics-365-starter → react-custom-page}/src/components/AccountForm.tsx +0 -0
- /package/templates/{dynamics-365-starter → react-custom-page}/src/components/AccountManagement.css +0 -0
- /package/templates/{dynamics-365-starter → react-custom-page}/src/components/AccountManagement.tsx +0 -0
- /package/templates/{dynamics-365-starter → react-custom-page}/src/components/ContactForm.css +0 -0
- /package/templates/{dynamics-365-starter → react-custom-page}/src/components/ContactForm.tsx +0 -0
- /package/templates/{dynamics-365-starter → react-custom-page}/src/components/ContactManagement.css +0 -0
- /package/templates/{dynamics-365-starter → react-custom-page}/src/components/ContactManagement.tsx +0 -0
- /package/templates/{dynamics-365-starter → react-custom-page}/src/components/Logging/LogDialog.tsx +0 -0
- /package/templates/{dynamics-365-starter → react-custom-page}/src/components/Logging/LoggingContext.tsx +0 -0
- /package/templates/{dynamics-365-starter → react-custom-page}/src/components/Logging/LoggingDebugPanel.css +0 -0
- /package/templates/{dynamics-365-starter → react-custom-page}/src/components/Logging/LoggingDebugPanel.tsx +0 -0
- /package/templates/{dynamics-365-starter → react-custom-page}/src/components/Logging/LoggingProvider.tsx +0 -0
- /package/templates/{dynamics-365-starter → react-custom-page}/src/components/Logging/logger.ts +0 -0
- /package/templates/{dynamics-365-starter → react-custom-page}/src/constants/account.ts +0 -0
- /package/templates/{dynamics-365-starter → react-custom-page}/src/constants/contact.ts +0 -0
- /package/templates/{dynamics-365-starter → react-custom-page}/src/index.tsx +0 -0
- /package/templates/{dynamics-365-starter → react-custom-page}/src/models/Account.ts +0 -0
- /package/templates/{dynamics-365-starter → react-custom-page}/src/models/BaseEntity.ts +0 -0
- /package/templates/{dynamics-365-starter → react-custom-page}/src/models/Contact.ts +0 -0
- /package/templates/{dynamics-365-starter → react-custom-page}/src/pcf/ContactControlWrapper.tsx +0 -0
- /package/templates/{dynamics-365-starter → react-custom-page}/src/pcf/MultiEntityControlWrapper.tsx +0 -0
- /package/templates/{dynamics-365-starter → react-custom-page}/src/providers/DynamicsProvider.tsx +0 -0
- /package/templates/{dynamics-365-starter → react-custom-page}/src/services/MockApiService.ts +0 -0
- /package/templates/{dynamics-365-starter → react-custom-page}/src/services/ServiceFactory.ts +0 -0
- /package/templates/{dynamics-365-starter → react-custom-page}/src/services/XrmApiService.ts +0 -0
- /package/templates/{dynamics-365-starter → react-custom-page}/src/styles/index.css +0 -0
- /package/templates/{dynamics-365-starter → react-custom-page}/tsconfig.json +0 -0
- /package/templates/{dynamics-365-starter → react-custom-page}/webpack.config.js +0 -0
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# {{projectName}}
|
|
2
|
+
|
|
3
|
+
A **Microsoft Teams tab** — React + Fluent UI v9 + `@microsoft/teams-js`.
|
|
4
|
+
|
|
5
|
+
## Develop
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install
|
|
9
|
+
npm run dev # vite on http://localhost:3000 (serve over HTTPS for Teams)
|
|
10
|
+
npm run build # production bundle → dist/
|
|
11
|
+
npm run typecheck # tsc --noEmit
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
`src/App.tsx` initializes the Teams SDK and shows the signed-in user. Edit `appPackage/manifest.json`
|
|
15
|
+
(and add `color.png` / `outline.png`) before sideloading.
|
|
16
|
+
|
|
17
|
+
## Microsoft Graph
|
|
18
|
+
|
|
19
|
+
`src/services/graph.ts` is generated based on the Graph option you chose at scaffold time:
|
|
20
|
+
|
|
21
|
+
- **enabled** → a `createGraphClient(getToken)` wrapper (`@microsoft/microsoft-graph-client` is added
|
|
22
|
+
to dependencies).
|
|
23
|
+
- **disabled** → a stub that throws until you re-scaffold with Graph enabled.
|
|
24
|
+
|
|
25
|
+
## Package & sideload
|
|
26
|
+
|
|
27
|
+
Zip `appPackage/` (manifest + icons) and upload it to Teams (Apps → Manage your apps → Upload a custom app).
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Microsoft Graph integration is disabled for this app. Re-scaffold with Graph
|
|
3
|
+
* enabled (answer "yes" to the Graph prompt, or pass --graph) to wire it up.
|
|
4
|
+
*/
|
|
5
|
+
export function createGraphClient(): never {
|
|
6
|
+
throw new Error('Graph integration is disabled. Re-scaffold with Graph enabled to use it.');
|
|
7
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { Client } from '@microsoft/microsoft-graph-client';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Create a Microsoft Graph client. Supply a token getter (e.g. Teams SSO via
|
|
5
|
+
* `authentication.getAuthToken()` exchanged for a Graph token server-side).
|
|
6
|
+
*/
|
|
7
|
+
export function createGraphClient(getToken: () => Promise<string>): Client {
|
|
8
|
+
return Client.init({
|
|
9
|
+
authProvider: async (done) => {
|
|
10
|
+
try {
|
|
11
|
+
done(null, await getToken());
|
|
12
|
+
} catch (e) {
|
|
13
|
+
done(e as Error, null);
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/** Convenience: the signed-in user's profile. */
|
|
20
|
+
export async function getMe(client: Client): Promise<unknown> {
|
|
21
|
+
return client.api('/me').get();
|
|
22
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://developer.microsoft.com/en-us/json-schemas/teams/v1.16/MicrosoftTeams.schema.json",
|
|
3
|
+
"manifestVersion": "1.16",
|
|
4
|
+
"id": "00000000-0000-0000-0000-000000000000",
|
|
5
|
+
"version": "1.0.0",
|
|
6
|
+
"developer": {
|
|
7
|
+
"name": "Contoso",
|
|
8
|
+
"websiteUrl": "https://example.com",
|
|
9
|
+
"privacyUrl": "https://example.com/privacy",
|
|
10
|
+
"termsOfUseUrl": "https://example.com/terms"
|
|
11
|
+
},
|
|
12
|
+
"name": { "short": "{{projectName}}", "full": "{{projectName}}" },
|
|
13
|
+
"description": { "short": "{{projectName}} tab", "full": "{{projectName}} Microsoft Teams tab" },
|
|
14
|
+
"icons": { "color": "color.png", "outline": "outline.png" },
|
|
15
|
+
"accentColor": "#6264A7",
|
|
16
|
+
"staticTabs": [
|
|
17
|
+
{
|
|
18
|
+
"entityId": "home",
|
|
19
|
+
"name": "{{projectName}}",
|
|
20
|
+
"contentUrl": "https://localhost:3000/",
|
|
21
|
+
"scopes": ["personal"]
|
|
22
|
+
}
|
|
23
|
+
],
|
|
24
|
+
"permissions": ["identity"],
|
|
25
|
+
"validDomains": ["localhost"]
|
|
26
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8" />
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
6
|
+
<title>{{projectName}}</title>
|
|
7
|
+
</head>
|
|
8
|
+
<body>
|
|
9
|
+
<div id="root"></div>
|
|
10
|
+
<script type="module" src="/src/index.tsx"></script>
|
|
11
|
+
</body>
|
|
12
|
+
</html>
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "{{projectName}}",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"private": true,
|
|
5
|
+
"type": "module",
|
|
6
|
+
"description": "{{projectName}} — Microsoft Teams tab (React, Fluent v9)",
|
|
7
|
+
"scripts": {
|
|
8
|
+
"dev": "vite",
|
|
9
|
+
"build": "tsc && vite build",
|
|
10
|
+
"preview": "vite preview",
|
|
11
|
+
"typecheck": "tsc --noEmit"
|
|
12
|
+
},
|
|
13
|
+
"dependencies": {
|
|
14
|
+
"react": "^18.2.0",
|
|
15
|
+
"react-dom": "^18.2.0",
|
|
16
|
+
"@fluentui/react-components": "^9.46.2",
|
|
17
|
+
"@microsoft/teams-js": "^2.19.0"
|
|
18
|
+
},
|
|
19
|
+
"devDependencies": {
|
|
20
|
+
"@types/react": "^18.2.0",
|
|
21
|
+
"@types/react-dom": "^18.2.0",
|
|
22
|
+
"@vitejs/plugin-react": "^4.2.1",
|
|
23
|
+
"typescript": "^5.3.3",
|
|
24
|
+
"vite": "^5.1.4"
|
|
25
|
+
}
|
|
26
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { FluentProvider, teamsLightTheme, Text, Spinner } from '@fluentui/react-components';
|
|
3
|
+
import { app } from '@microsoft/teams-js';
|
|
4
|
+
|
|
5
|
+
export const App: React.FC = () => {
|
|
6
|
+
const [status, setStatus] = React.useState<string | null>(null);
|
|
7
|
+
|
|
8
|
+
React.useEffect(() => {
|
|
9
|
+
app
|
|
10
|
+
.initialize()
|
|
11
|
+
.then(() => app.getContext())
|
|
12
|
+
.then((ctx) => setStatus(ctx.user?.userPrincipalName ?? 'unknown user'))
|
|
13
|
+
.catch((e) => setStatus(`Not running in Teams: ${String(e)}`));
|
|
14
|
+
}, []);
|
|
15
|
+
|
|
16
|
+
return (
|
|
17
|
+
<FluentProvider theme={teamsLightTheme}>
|
|
18
|
+
<div style={{ display: 'flex', flexDirection: 'column', gap: 12, padding: 16 }}>
|
|
19
|
+
<Text size={600} weight="semibold">{{projectName}}</Text>
|
|
20
|
+
<Text>Microsoft Teams tab — Fluent UI v9.</Text>
|
|
21
|
+
{status === null ? <Spinner label="Initializing Teams…" /> : <Text>Signed in as: {status}</Text>}
|
|
22
|
+
</div>
|
|
23
|
+
</FluentProvider>
|
|
24
|
+
);
|
|
25
|
+
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2020",
|
|
4
|
+
"useDefineForClassFields": true,
|
|
5
|
+
"lib": ["ES2020", "DOM", "DOM.Iterable"],
|
|
6
|
+
"module": "ESNext",
|
|
7
|
+
"moduleResolution": "bundler",
|
|
8
|
+
"jsx": "react-jsx",
|
|
9
|
+
"strict": true,
|
|
10
|
+
"esModuleInterop": true,
|
|
11
|
+
"skipLibCheck": true,
|
|
12
|
+
"noEmit": true,
|
|
13
|
+
"isolatedModules": true
|
|
14
|
+
},
|
|
15
|
+
"include": ["src"]
|
|
16
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { defineConfig } from 'vite';
|
|
2
|
+
import react from '@vitejs/plugin-react';
|
|
3
|
+
|
|
4
|
+
export default defineConfig({
|
|
5
|
+
plugins: [react()],
|
|
6
|
+
// Teams tabs must be served over HTTPS; `vite --https` or a tunnel in dev.
|
|
7
|
+
server: { port: 3000 },
|
|
8
|
+
build: { outDir: 'dist' },
|
|
9
|
+
});
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# {{projectName}}
|
|
2
|
+
|
|
3
|
+
A Dynamics 365 **web resource** built with React + Fluent UI ({{componentLibrary}}), bundled to a
|
|
4
|
+
single JS file you can upload as a web resource.
|
|
5
|
+
|
|
6
|
+
## Develop
|
|
7
|
+
|
|
8
|
+
```bash
|
|
9
|
+
npm install
|
|
10
|
+
npm run dev # webpack dev server on http://localhost:8080
|
|
11
|
+
npm run build # production bundle → dist/{{projectName}}.js
|
|
12
|
+
npm run typecheck # tsc --noEmit
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Local data access
|
|
16
|
+
|
|
17
|
+
`src/services/dataverse.ts` wraps `Xrm.WebApi`. Outside a model-driven host (e.g. `npm run dev`),
|
|
18
|
+
stub it with the `serve` dev-tool's mock:
|
|
19
|
+
|
|
20
|
+
```ts
|
|
21
|
+
import { installMockXrm } from '../tools/dev/mock-xrm.js';
|
|
22
|
+
if (location.hostname === 'localhost') installMockXrm();
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Acquire a token (for codegen / live calls)
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
npm run auth:token -- --url https://YOUR_ORG.crm.dynamics.com
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Generate typed entities from a live org
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
npm run metadata:pull -- --entities account,contact
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## Deploy
|
|
38
|
+
|
|
39
|
+
Upload `dist/{{projectName}}.js` (and the bundled HTML if needed) as a web resource in your solution.
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { ThemeProvider } from '@fluentui/react/lib/Theme';
|
|
3
|
+
import { Stack } from '@fluentui/react/lib/Stack';
|
|
4
|
+
import { Text } from '@fluentui/react/lib/Text';
|
|
5
|
+
import { PrimaryButton } from '@fluentui/react/lib/Button';
|
|
6
|
+
import { retrieveMultiple } from './services/dataverse';
|
|
7
|
+
|
|
8
|
+
export const App: React.FC = () => {
|
|
9
|
+
const onClick = async () => {
|
|
10
|
+
try {
|
|
11
|
+
const rows = await retrieveMultiple('account', '?$select=name&$top=5');
|
|
12
|
+
alert(`Retrieved ${rows.length} account(s).`);
|
|
13
|
+
} catch (e) {
|
|
14
|
+
alert(`Xrm.WebApi not available here: ${String(e)}`);
|
|
15
|
+
}
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
return (
|
|
19
|
+
<ThemeProvider>
|
|
20
|
+
<Stack tokens={{ childrenGap: 12, padding: 16 }}>
|
|
21
|
+
<Text variant="xLarge">{{projectName}}</Text>
|
|
22
|
+
<Text>Dynamics 365 web resource — Fluent UI v8.</Text>
|
|
23
|
+
<Stack.Item>
|
|
24
|
+
<PrimaryButton text="Retrieve accounts" onClick={onClick} />
|
|
25
|
+
</Stack.Item>
|
|
26
|
+
</Stack>
|
|
27
|
+
</ThemeProvider>
|
|
28
|
+
);
|
|
29
|
+
};
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { FluentProvider, webLightTheme, Text, Button } from '@fluentui/react-components';
|
|
3
|
+
import { retrieveMultiple } from './services/dataverse';
|
|
4
|
+
|
|
5
|
+
export const App: React.FC = () => {
|
|
6
|
+
const onClick = async () => {
|
|
7
|
+
try {
|
|
8
|
+
const rows = await retrieveMultiple('account', '?$select=name&$top=5');
|
|
9
|
+
alert(`Retrieved ${rows.length} account(s).`);
|
|
10
|
+
} catch (e) {
|
|
11
|
+
alert(`Xrm.WebApi not available here: ${String(e)}`);
|
|
12
|
+
}
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
return (
|
|
16
|
+
<FluentProvider theme={webLightTheme}>
|
|
17
|
+
<div style={{ display: 'flex', flexDirection: 'column', gap: 12, padding: 16 }}>
|
|
18
|
+
<Text size={600} weight="semibold">{{projectName}}</Text>
|
|
19
|
+
<Text>Dynamics 365 web resource — Fluent UI v9.</Text>
|
|
20
|
+
<div>
|
|
21
|
+
<Button appearance="primary" onClick={onClick}>
|
|
22
|
+
Retrieve accounts
|
|
23
|
+
</Button>
|
|
24
|
+
</div>
|
|
25
|
+
</div>
|
|
26
|
+
</FluentProvider>
|
|
27
|
+
);
|
|
28
|
+
};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "{{projectName}}",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "{{projectName}} — Dynamics 365 web resource (React, Fluent {{componentLibrary}})",
|
|
5
|
+
"private": true,
|
|
6
|
+
"scripts": {
|
|
7
|
+
"dev": "webpack serve --mode development",
|
|
8
|
+
"build": "webpack --mode production",
|
|
9
|
+
"typecheck": "tsc --noEmit",
|
|
10
|
+
"lint": "eslint src --ext .ts,.tsx"
|
|
11
|
+
},
|
|
12
|
+
"dependencies": {
|
|
13
|
+
"react": "^18.2.0",
|
|
14
|
+
"react-dom": "^18.2.0"
|
|
15
|
+
},
|
|
16
|
+
"devDependencies": {
|
|
17
|
+
"@types/react": "^18.2.0",
|
|
18
|
+
"@types/react-dom": "^18.2.0",
|
|
19
|
+
"@types/xrm": "^9.0.74",
|
|
20
|
+
"html-webpack-plugin": "^5.5.3",
|
|
21
|
+
"ts-loader": "^9.5.1",
|
|
22
|
+
"typescript": "^5.3.3",
|
|
23
|
+
"webpack": "^5.89.0",
|
|
24
|
+
"webpack-cli": "^5.1.4",
|
|
25
|
+
"webpack-dev-server": "^4.15.1"
|
|
26
|
+
}
|
|
27
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { createRoot } from 'react-dom/client';
|
|
3
|
+
import { App } from './App';
|
|
4
|
+
|
|
5
|
+
// On localhost, `tools/dev/mock-xrm.js` (from the `serve` dev-tool) can be loaded
|
|
6
|
+
// to stub the Xrm global so this resource runs outside a model-driven host.
|
|
7
|
+
const container = document.getElementById('root');
|
|
8
|
+
if (container) {
|
|
9
|
+
createRoot(container).render(<App />);
|
|
10
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Thin wrapper over Xrm.WebApi for this web resource's data access. The Xrm global
|
|
3
|
+
* is typed via @types/xrm; on localhost, stub it with tools/dev/mock-xrm.js.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
export type DataverseRecord = Record<string, unknown>;
|
|
7
|
+
|
|
8
|
+
export async function retrieveMultiple(
|
|
9
|
+
entityLogicalName: string,
|
|
10
|
+
options = ''
|
|
11
|
+
): Promise<DataverseRecord[]> {
|
|
12
|
+
const result = await Xrm.WebApi.retrieveMultipleRecords(entityLogicalName, options);
|
|
13
|
+
return result.entities;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export async function retrieveRecord(
|
|
17
|
+
entityLogicalName: string,
|
|
18
|
+
id: string,
|
|
19
|
+
options = ''
|
|
20
|
+
): Promise<DataverseRecord> {
|
|
21
|
+
return Xrm.WebApi.retrieveRecord(entityLogicalName, id, options);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export async function createRecord(
|
|
25
|
+
entityLogicalName: string,
|
|
26
|
+
data: Record<string, unknown>
|
|
27
|
+
): Promise<string> {
|
|
28
|
+
const res = await Xrm.WebApi.createRecord(entityLogicalName, data);
|
|
29
|
+
return res.id;
|
|
30
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2018",
|
|
4
|
+
"module": "ESNext",
|
|
5
|
+
"moduleResolution": "node",
|
|
6
|
+
"jsx": "react-jsx",
|
|
7
|
+
"strict": true,
|
|
8
|
+
"esModuleInterop": true,
|
|
9
|
+
"forceConsistentCasingInFileNames": true,
|
|
10
|
+
"skipLibCheck": true,
|
|
11
|
+
"lib": ["DOM", "DOM.Iterable", "ES2018"],
|
|
12
|
+
"types": ["xrm"]
|
|
13
|
+
},
|
|
14
|
+
"include": ["src"]
|
|
15
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
const path = require('path');
|
|
2
|
+
const HtmlWebpackPlugin = require('html-webpack-plugin');
|
|
3
|
+
|
|
4
|
+
module.exports = {
|
|
5
|
+
entry: './src/index.tsx',
|
|
6
|
+
output: {
|
|
7
|
+
path: path.resolve(__dirname, 'dist'),
|
|
8
|
+
filename: '{{projectName}}.js',
|
|
9
|
+
clean: true,
|
|
10
|
+
},
|
|
11
|
+
resolve: { extensions: ['.ts', '.tsx', '.js'] },
|
|
12
|
+
module: {
|
|
13
|
+
rules: [{ test: /\.tsx?$/, use: 'ts-loader', exclude: /node_modules/ }],
|
|
14
|
+
},
|
|
15
|
+
plugins: [new HtmlWebpackPlugin({ template: './public/index.html' })],
|
|
16
|
+
devServer: { static: './dist', port: 8080, hot: true },
|
|
17
|
+
};
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Generate entities using the entity generator
|
|
3
|
-
*/
|
|
4
|
-
export declare function generateEntities(projectPath: string, entities?: string, generateSample?: boolean): Promise<void>;
|
|
5
|
-
/**
|
|
6
|
-
* Generate page templates based on selection
|
|
7
|
-
*/
|
|
8
|
-
export declare function generatePageTemplates(projectPath: string, pageType: string, entities?: string, generateSample?: boolean): Promise<void>;
|
|
9
|
-
/**
|
|
10
|
-
* Customize project for deployment target
|
|
11
|
-
*/
|
|
12
|
-
export declare function customizeForDeployment(projectPath: string, deploymentTarget: string): Promise<void>;
|
|
13
|
-
//# sourceMappingURL=consultingHelpers.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"consultingHelpers.d.ts","sourceRoot":"","sources":["../../src/utils/consultingHelpers.ts"],"names":[],"mappings":"AAQA;;GAEG;AACH,wBAAsB,gBAAgB,CACpC,WAAW,EAAE,MAAM,EACnB,QAAQ,CAAC,EAAE,MAAM,EACjB,cAAc,CAAC,EAAE,OAAO,GACvB,OAAO,CAAC,IAAI,CAAC,CAgDf;AAED;;GAEG;AACH,wBAAsB,qBAAqB,CACzC,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,MAAM,EAChB,QAAQ,CAAC,EAAE,MAAM,EACjB,cAAc,CAAC,EAAE,OAAO,GACvB,OAAO,CAAC,IAAI,CAAC,CA0Bf;AAED;;GAEG;AACH,wBAAsB,sBAAsB,CAC1C,WAAW,EAAE,MAAM,EACnB,gBAAgB,EAAE,MAAM,GACvB,OAAO,CAAC,IAAI,CAAC,CA4Cf"}
|