add-table-to-offline-profile
Internal mobile-app workflow read and executed only by mobile orchestrators to add one Dataverse table to an existing Mobile Offline Profile.
git clone --depth 1 https://github.com/microsoft/power-platform-skills /tmp/add-table-to-offline-profile && cp -r /tmp/add-table-to-offline-profile/plugins/mobile-apps/skills/add-table-to-offline-profile ~/.claude/skills/add-table-to-offline-profileSKILL.md
**Shared instructions: [shared-instructions.md](${PLUGIN_ROOT}/shared/shared-instructions.md)** — read first.
**References:**
- [dataverse-offline-api.md](${PLUGIN_ROOT}/shared/references/dataverse-offline-api.md) §4 + §7 — POST item + PATCH selectedcolumns
- [offline-profile-reconciliation.md](${PLUGIN_ROOT}/shared/references/offline-profile-reconciliation.md) — the `schemaColumns` baseline written in Step 7
# Add Table to Offline Profile
Add a single table to an existing Mobile Offline Profile. Most common flow: user ran `/add-dataverse` to add a new table to their app, now wants that table available offline too.
Equivalent to running `/setup-offline-profile` and seeing the existing profile (extend-mode), but skips the per-table questionnaire for the tables already in the profile — only configures the new one.
## Workflow
1. Verify project + locate profile → 2. Resolve target table → 3. Prereq check (auto-enable if needed) → 4. Scope picker (single question) → 5. POST item + PATCH selectedcolumns → 6. Publish → 7. Update artifacts → 8. Summary
---
### Step 1 — Verify project + locate profile
```bash
test -f power.config.json
node "${PLUGIN_ROOT}/scripts/resolve-environment.js" "$(node -e \"console.log(require('./power.config.json').environmentId)\")"
```
Manifest path (dual-location):
```bash
MANIFEST=$(test -f .datamodel-manifest.json && echo ".datamodel-manifest.json" || \
(test -f docs/plan-artifacts/.datamodel-manifest.json && echo "docs/plan-artifacts/.datamodel-manifest.json"))
test -n "$MANIFEST" && echo "✓ manifest at $MANIFEST"
```
Profile ID resolution (same as `/edit-offline-profile`).
STOP if no profile exists. Recommend: `Run /setup-offline-profile first to create the profile.`
### Step 2 — Resolve target table
`$ARGUMENTS` parsing:
| Flag | Effect |
|---|---|
| `--table <logical-name>` | Explicit target |
| `--all-new` | Add ALL tables in the manifest that aren't already in the profile (bulk mode) |
| (no flags) | Interactive: list tables in manifest NOT yet in profile via `AskUserQuestion` (max 4); if more than 4 candidates, prompt user to specify by name in next message |
For bulk `--all-new` mode, loop through Steps 3-6 for each missing table; each runs sequentially because Dataverse profile-item POSTs serialize.
### Step 3 — Prereq check (auto-enable if needed)
Query the target table's `EntityMetadata`:
```bash
node "${PLUGIN_ROOT}/scripts/dataverse-request.js" <envUrl> GET \
"EntityDefinitions(LogicalName='<table>')?\$select=IsAvailableOffline,ChangeTrackingEnabled,OwnershipType,IsCustomizable"
```
| Flags state | Action |
|---|---|
| Both already `true` | Skip to Step 4 |
| Either `false` AND IsCustomizable | Auto-enable via `update-entity-offline-flags.js` (no prompt — the user already opted into "offline this table" by invoking this skill) |
| `IsCustomizable.Value = false` | STOP with `BLOCKED: <table> is system-managed and cannot be flagged for offline. Use a different table or accept this row is read-only-offline.` |
After auto-enable, single `POST PublishAllXml`.
### Step 4 — Scope picker (single question)
Pull from manifest the target table's `lookups[]` to inform defaults. Run a quick row-count probe to inform reference-data classification.
`AskUserQuestion` with 4 options reflecting the architect's priority cascade:
| Option label | Maps to |
|---|---|
| `Organization rows — User's rows only (Recommended for most tables)` | `recorddistributioncriteria: 2`, `recordsownedbyme: true` |
| `All records (for small reference data)` | `recorddistributioncriteria: 1` |
| `Related rows only (for pure child tables)` | `recorddistributioncriteria: 0` |
| `Custom — specify exact flags in next message` | Prompt user with text |
Recommendation in the question body should be derived from the architect's heuristics for the table being added (use the same priority cascade from `offline-profile-architect.md` Step 4 inline). The user can override.
### Step 5 — POST item + associations + PATCH selectedcolumns
#### Step 5a — POST profile item
```bash
node "${PLUGIN_ROOT}/scripts/dataverse-request.js" <envUrl> POST \
"mobileofflineprofileitems" \
--body '{
"name": "<DisplayName>",
"regardingobjectid@odata.bind": "/mobileofflineprofiles(<profileId>)",
"selectedentitytypecode": "<table>",
"recorddistributioncriteria": <0|1|2>,
"recordsownedbyme": <bool>,
"recordsownedbymyteam": false,
"recordsownedbymybusinessunit": false,
"getrelatedentityrecords": true,
"syncintervalinminutes": 10
}' \
--include-headers
```
Capture `itemId` from `OData-EntityId` response header.
#### Step 5b — POST associations for the new table's relationships
After the new item is created, walk the new table's relationships (from the manifest's `lookups[]` + a `EntityDefinitions(LogicalName='<table>')/ManyToOneRelationships` query) and POST one `mobileofflineprofileitemassociation` per relationship whose target is ALREADY in the profile.
Recipe per [shared/references/dataverse-offline-api.md §5–§6](${PLUGIN_ROOT}/shared/references/dataverse-offline-api.md):
```bash
node "${PLUGIN_ROOT}/scripts/dataverse-request.js" <envUrl> POST \
"mobileofflineprofileitemassociations" \
--body '{
"name": "<relationshipSchemaName>",
"relationshipdisplayname": "<relationshipSchemaName>",
"relationshipid": "<MetadataId-from-EntityDefinitions>",
"regardingobjectid@odata.bind": "/mobileofflineprofileitems(<newItemId>)"
}' \
--include-headers
```
**Critical**: do NOT include `selectedrelationshipsschema` in the body — server fills it in (empirical 2026-05-24).
For new tables that are `recorddistributioncriteria: 0` (Related rows only), at least ONE inbound relationship MUST be included or the table will sync zero rows. The skill should validate this and warn if no associations are being created for a Related-only-scoped table.
#### Step 5c — PATCH selectedcolumns
Build `selectedcolumns` using the deterministic unGuide the user to add a data source, connection, or API connector to a Canvas App via Power Apps Studio, then verify and continue. USE WHEN the user asks to add a data source, add a connection, add an API, add a connector, connect to SharePoint / Dataverse / SQL / Excel / OneDrive / Teams / Office 365, or any similar request to make new data available to the app. DO NOT USE WHEN the user is asking to list or describe existing data sources — call list_data_sources or list_apis directly instead.
Creates or edits a Power Apps Canvas App through the Canvas Authoring MCP coauthoring session. Handles new app generation, direct targeted edits, complex multi-screen changes, responsive layout, per-screen self-QA, and compile-error convergence. Trigger on requests to create, build, generate, modify, update, change, fix, or edit a Canvas App or .pa.yaml files.
Configure the Canvas Authoring MCP server for the current coauthoring session. USE WHEN "configure MCP", "set up MCP server", "MCP not working", "connect Canvas Apps MCP", "canvas-authoring not available", "MCP not configured", "set up canvas apps".
[DEPRECATED — use canvas-app instead] Generate a complete Power Apps canvas app.
>
Adds Azure DevOps connector to a Power Apps code app. Use when querying work items, creating bugs, managing pipelines, or making ADO API calls.
Use when adding a Power Platform connector to an Expo/React Native Power Apps mobile app and no dedicated mobile connector skill exists.
Use when adding an unspecified data source to an Expo/React Native Power Apps mobile app; routes to Dataverse, SharePoint, or another connector.