Creates, updates, and deploys Power Apps generative pages for model-driven apps using React v17, TypeScript, and Fluent UI V9. Completes workflow from requirements to deployment. Uses PAC CLI to deploy the page code. Use it when user asks to build, retrieve, or update a page in an existing Microsoft Power Apps model-driven app. Use it when user mentions "generative page", "page in a model-driven", or "genux".
Install with Tessl CLI
npx tessl i github:microsoft/power-platform-skills --skill genpage92
Quality
92%
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Triggers: genpage, generative page, create genpage, genux page, build genux, power apps page, model page Keywords: power apps, generative pages, genux, model-driven, dataverse, react, fluent ui, pac cli Aliases: /genpage, /gen-page, /genux
@fluentui/react-components exclusively (DatePicker from @fluentui/react-datepicker-compat, TimePicker from @fluentui/react-timepicker-compat).tsx file100vh/100vwFollow these steps in order for every /genpage invocation.
Run these checks (first invocation per session only). Run each command separately — do not chain with &&:
node --versionpac helppac help output includes the version number. Verify the version is >= 2.3.1. If the version is older, instruct the user to update: dotnet tool update --global Microsoft.PowerApps.CLI.Tool.
If either command fails, inform the user and provide installation instructions. Do NOT proceed until prerequisites are met. See troubleshooting.md if issues arise.
Check PAC CLI authentication:
pac auth listIf no profiles: Ask user to authenticate:
pac auth create --environment https://your-env.crm.dynamics.comWait for user to complete browser sign-in, then re-verify.
If one profile: Confirm it's active (has * marker). If not, activate it:
pac auth select --index 1If multiple profiles: Show the list, ask which environment to use, then:
pac auth select --index <user-chosen-index>Report: "Working with environment: [name]" and proceed.
Ask these questions one at a time:
AskUserQuestion)
pac model genpage download --app-id <app-id> --page-id <page-id> --output-directory ./output-dir, then ask what changes to makeAskUserQuestion) — present two example descriptions as options and let the user type their own via the "Other" option:
AskUserQuestion)
AskUserQuestion) — styling, features (search, filtering, sorting), accessibility, responsive behavior, interactionsIf the user provided a description with the /genpage command, acknowledge it and skip question 2. If the selected description already specifies a data source (e.g., Option 1 mentions Account table, Option 2 mentions Task records), skip question 3 as well.
Present a clear plan:
I'll create a [page type] with:
- Data: [entities or mock data with specifics]
- Features: [list key features]
- Components: [Fluent UI components to use]
- Layout: [responsive design approach]
Does this plan look good? Any changes needed?Wait for confirmation before proceeding. If changes requested, revise and re-confirm.
CRITICAL — DO THIS BEFORE WRITING ANY CODE. Column name hallucination is the #1 source of runtime errors. Never guess column names.
If the page uses Dataverse entities, generate the TypeScript schema NOW:
pac model genpage generate-types --data-sources "entity1,entity2" --output-file RuntimeTypes.tsWindows + Bash: Always use forward slashes in file paths (e.g.,
D:/temp/RuntimeTypes.ts). Backslashes like\tor\Rare consumed as escape sequences by bash, producing wrong paths.
After generating, read the RuntimeTypes.ts file and:
NEVER guess or assume column names. Custom entities (e.g.,
cr69c_candidate) have unpredictable column names (e.g.,cr69c_fullnamenotcr69c_name). The only way to know the real names is to read them from the generated schema.
If schema generation fails, see troubleshooting.md. Do NOT generate code with guessed column names.
For mock data pages: Skip this step.
Before generating code, read the comprehensive rules reference:
genpage-rules-reference.md — Full code generation rules, DataAPI types, layout patterns, common errors.
Also read a relevant sample for reference:
| Sample | Use When |
|---|---|
| 1-account-grid.tsx | DataGrid with Dataverse entities |
| 2-wizard-multi-step.tsx | Multi-step wizard flow |
| 3-poa-revocation-wizard.tsx | Complex wizard with forms |
| 4-account-crud-dataverse.tsx | Full CRUD operations |
| 5-file-upload.tsx | File upload pattern |
| 6-navigation-sidebar.tsx | Sidebar navigation layout |
| 7-comprehensive-form.tsx | Complex form with validation |
| 8-responsive-cards.tsx | Card-based responsive layout |
Generate complete TypeScript following ALL rules in genpage-rules-reference.md. For Dataverse pages, use ONLY the column names verified from RuntimeTypes.ts in Step 5. Output in this format:
Agent Thoughts: Step-by-step reasoning and approach Summary: Non-technical bulleted list of what was built Final Code: Complete, ready-to-run TypeScript (no placeholders)
Save the code to a .tsx file (e.g., account-dashboard.tsx).
import {useEffect, useState} from 'react';
import type {
TableRow,
DataColumnValue,
RowKeyDataColumnValue,
QueryTableOptions,
ReadableTableRow,
ExtractFields,
GeneratedComponentProps
} from "./RuntimeTypes";
// Additional imports: @fluentui/react-components, @fluentui/react-icons, d3, etc.
// Utility functions as separate top-level functions
// Sub-components as separate top-level functions
const GeneratedComponent = (props: GeneratedComponentProps) => {
const { dataApi } = props;
// Component implementation
}
export default GeneratedComponent;// Query with pagination
const result = await dataApi.queryTable("account", {
select: ["name", "revenue"],
filter: `contains(name,'test')`,
orderBy: `name asc`,
pageSize: 50
});
// Load more rows
if (result.hasMoreRows && result.loadMoreRows) {
const nextPage = await result.loadMoreRows();
}
// Create, Update, Retrieve
await dataApi.createRow("account", { name: "New Account" });
await dataApi.updateRow("account", "record-id", { name: "Updated" });
const row = await dataApi.retrieveRow("account", { id: "record-id", select: ["name"] });
// Access formatted values (for enums, lookups, dates, etc.)
const formatted = row["status@OData.Community.Display.V1.FormattedValue"];
// Lookup fields: raw value is a GUID — use formatted value for display name
const contactGuid = row._primarycontactid_value; // GUID
const contactName = row["_primarycontactid_value@OData.Community.Display.V1.FormattedValue"]; // Display name
// Get enum choices
const choices = await dataApi.getChoices("account-statecode");DataAPI Rules:
dataApi when TableRegistrations are provided — never assume tables/fields exist_primarycontactid_value) return a GUID. Always use the @OData.Community.Display.V1.FormattedValue annotation for display"account")dataApi calls in try-catchcreateTableColumn, enable sorting by defaultSee genpage-rules-reference.md for full DataAPI type definitions and examples.
After showing code, ALWAYS ask:
"Would you like to publish this page to Power Apps?"
If yes, follow this deployment workflow. Copy the upload commands below exactly — --app-id, --code-file, --prompt, --agent-message are all required and must use these exact flag names.
For Dataverse entity pages (schema already generated in Step 5):
pac model listCRITICAL: Ask the user: "Which app would you like to publish this page to? Please provide the app-id or app name from the list above."
pac model list to look up the corresponding app-idpac model genpage upload `
--app-id <user-provided-app-id-or-name> `
--code-file page-name.tsx `
--name "Page Display Name" `
--data-sources "entity1,entity2" `
--prompt "User's original request summary" `
--model "<current-model-id>" `
--agent-message "The agent's response message describing what was built and any relevant details" `
--add-to-sitemapFor mock data pages (skip schema generation):
pac model list
# Ask user for app selection, then:
pac model genpage upload `
--app-id <user-provided-app-id-or-name> `
--code-file page-name.tsx `
--name "Page Display Name" `
--prompt "User's original request summary" `
--model "<current-model-id>" `
--agent-message "The agent's response message describing what was built and any relevant details" `
--add-to-sitemapFor updating existing pages (use --page-id, omit --add-to-sitemap):
pac model genpage upload `
--app-id <app-id-or-name> `
--page-id <page-id> `
--code-file page-name.tsx `
--data-sources "entity1,entity2" `
--prompt "User's original request summary" `
--model "<current-model-id>" `
--agent-message "The agent's response message describing what was built and any relevant details"After successful deployment, ask the user (use AskUserQuestion):
"Would you like to verify the page in the browser using Playwright? This will open the page and test interactive elements."
Options: Yes, verify in browser / Skip verification
If the user chooses to skip, go directly to Step 10.
If the user chooses to verify, open the page in the browser using Playwright to verify it works and interactive elements function correctly.
Construct the URL from the environment base URL, app-id, and page-id returned by the upload command:
https://<env>.crm.dynamics.com/main.aspx?appid=<app-id>&pagetype=genux&id=<page-id>browser_navigate to open the constructed URLbrowser_snapshot to capture the page state. Always snapshot before any clicks — stale refs cause "Ref not found" errorsbrowser_click on the sign-in option, then browser_wait_for for the page to loadbrowser_wait_for to wait for the genux page content to render (may take a few seconds)Use browser_snapshot to take an accessibility snapshot and verify the expected DOM elements are present based on the page type built:
| Page Type | Expected Elements |
|---|---|
| Data Grid | Table/grid element with column headers and data rows |
| Form / Wizard | Form fields (inputs, dropdowns) and Next/Back buttons |
| CRUD | Data grid + action buttons (Add, Edit, Delete) |
| Dashboard | Multiple sections/panels with headings |
| Card Layout | Card containers with content |
| File Upload | File input or drop zone element |
| Navigation Sidebar | Nav element with menu items |
If expected elements are missing, note the issue for the fix step (9.5).
Test functional interactions based on the page type. Always take a fresh browser_snapshot before each click to get current element refs. Move on after 2 failed attempts per interaction.
All page types:
Page-type-specific tests:
| Page Type | Test Action | Expected Result |
|---|---|---|
| Data Grid | Click a column header | Sort order changes (arrow indicator appears or flips) |
| Form / Wizard | Click Next button | Step advances to next section |
| Form / Wizard | Click Back button | Returns to previous section |
| CRUD | Click Add/New button | Form or dialog appears |
| Dashboard | Click a tab or section toggle | Content area updates |
| Card Layout | Click an action button on a card | Card responds (expand, navigate, etc.) |
| Navigation Sidebar | Click a menu item | Content area updates to show selected section |
What NOT to test (skip these):
Use browser_take_screenshot to capture a final screenshot for the deployment summary. This screenshot should show the page in its final verified state.
If structural or interactive issues are found:
Common Playwright issues:
browser_snapshot before clicking any elementAfter deployment and verification, provide:
8ccaae8
If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.