@salesforce/afv-skills 1.30.0 → 1.32.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/package.json +1 -1
- package/skills/agentforce-bot-upgrade/SKILL.md +217 -0
- package/skills/agentforce-bot-upgrade/references/extraction-blueprint.md +242 -0
- package/skills/agentforce-bot-upgrade/references/generate-agent-spec.md +128 -0
- package/skills/agentforce-bot-upgrade/references/handoff-output-format.md +208 -0
- package/skills/agentforce-bot-upgrade/references/input-contract.md +101 -0
- package/skills/agentforce-bot-upgrade/references/mapping-rules.md +113 -0
- package/skills/agentforce-bot-upgrade/references/planner-workflow-reference.md +78 -0
- package/skills/agentforce-bot-upgrade/references/post-conversion-enhancements-reference.md +67 -0
- package/skills/agentforce-bot-upgrade/references/quality-checklist.md +33 -0
- package/skills/agentforce-bot-upgrade/references/sf-cli-bot-reference.md +116 -0
- package/skills/data360-code-extension-generate/SKILL.md +15 -2
- package/skills/dx-devops-work-item-manage/SKILL.md +270 -0
- package/skills/dx-devops-work-item-manage/examples/common-workflows.md +479 -0
- package/skills/dx-devops-work-item-manage/references/cli-commands.md +476 -0
- package/skills/dx-org-manage/SKILL.md +8 -5
- package/skills/dx-org-trial-expiration-check/SKILL.md +239 -0
- package/skills/dx-org-trial-expiration-check/scripts/check_expiration.sh +588 -0
- package/skills/dx-pkg-post-install-configure/SKILL.md +184 -0
- package/skills/experience-ui-bundle-app-coordinate/SKILL.md +202 -35
- package/skills/experience-ui-bundle-app-coordinate/scripts/check-hosting-target.sh +26 -0
- package/skills/experience-ui-bundle-app-coordinate/scripts/check-sfdx-project.sh +15 -0
- package/skills/experience-ui-bundle-custom-app-generate/SKILL.md +29 -5
- package/skills/experience-ui-bundle-custom-app-generate/references/configure-metadata-custom-application.md +1 -1
- package/skills/experience-ui-bundle-custom-app-generate/scripts/resolve-uibundle-path.sh +30 -0
- package/skills/experience-ui-bundle-features-generate/SKILL.md +86 -11
- package/skills/experience-ui-bundle-features-generate/references/conflict-resolution-schema.json +20 -0
- package/skills/experience-ui-bundle-features-generate/scripts/verify-react-bundle.sh +14 -0
- package/skills/experience-ui-bundle-frontend-generate/SKILL.md +6 -1
- package/skills/experience-ui-bundle-frontend-generate/references/component.md +34 -1
- package/skills/experience-ui-bundle-frontend-generate/references/page.md +1 -1
- package/skills/experience-ui-bundle-metadata-generate/SKILL.md +19 -8
- package/skills/experience-ui-bundle-metadata-generate/references/csp-metadata-format.md +2 -2
- package/skills/experience-ui-bundle-metadata-generate/scripts/check-api-version.sh +30 -0
- package/skills/experience-ui-bundle-project-generate/SKILL.md +111 -0
- package/skills/experience-ui-bundle-project-generate/scripts/flatten-project.mjs +33 -0
- package/skills/platform-custom-field-generate/SKILL.md +12 -11
- package/skills/platform-custom-field-generate/references/advanced-picklists.md +17 -17
- package/skills/platform-custom-lightning-type-generate/SKILL.md +9 -14
- package/skills/platform-custom-lightning-type-generate/references/widget-rendition.md +27 -111
- package/skills/platform-custom-report-type-generate/SKILL.md +259 -0
- package/skills/platform-custom-report-type-generate/examples/AccountProjectsWithTasks.reportType-meta.xml +51 -0
- package/skills/platform-custom-report-type-generate/examples/AccountsWithIndustry.reportType-meta.xml +27 -0
- package/skills/platform-custom-report-type-generate/examples/AccountsWithProjects.reportType-meta.xml +44 -0
- package/skills/platform-custom-report-type-generate/references/category-values.md +32 -0
- package/skills/platform-custom-report-type-generate/references/errors-and-troubleshooting.md +24 -0
- package/skills/platform-dataspace-access-configure/SKILL.md +318 -0
- package/skills/platform-docs-get/SKILL.md +4 -0
- package/skills/platform-docs-get/scripts/extract_salesforce_doc.py +78 -13
- package/skills/platform-encryption-configure/SKILL.md +122 -0
- package/skills/platform-encryption-configure/assets/EncryptionKey.settings-meta.xml +17 -0
- package/skills/platform-encryption-configure/assets/PlatformEncryption.settings-meta.xml +15 -0
- package/skills/platform-encryption-configure/assets/encrypted-field.field-meta.xml +22 -0
- package/skills/platform-encryption-configure/examples/cache-only-keys.settings-meta.xml +11 -0
- package/skills/platform-encryption-configure/references/encryption-schemes.md +34 -0
- package/skills/platform-encryption-configure/references/key-models.md +34 -0
- package/skills/platform-encryption-configure/references/tenant-secret-lifecycle.md +23 -0
- package/skills/platform-encryption-configure/scripts/validate-encryption-metadata.sh +54 -0
- package/skills/platform-lightning-type-widget-coordinate/SKILL.md +214 -0
- package/skills/platform-lightning-type-widget-coordinate/examples/existing-lightning-type-with-widget-prompt.md +80 -0
- package/skills/platform-lightning-type-widget-coordinate/examples/new-lightning-type-with-widget-prompt.md +75 -0
- package/skills/platform-lightning-type-widget-coordinate/references/build-plan-format.md +67 -0
- package/skills/platform-lightning-type-widget-coordinate/references/lightning-type-discovery.md +124 -0
- package/skills/platform-lightning-type-widget-coordinate/references/validation-gates.md +130 -0
- package/skills/platform-metadata-api-context-get/SKILL.md +13 -10
- package/skills/platform-sharing-owd-configure/SKILL.md +142 -0
- package/skills/platform-sharing-owd-configure/examples/get_owd_output.md +38 -0
- package/skills/platform-sharing-owd-configure/examples/update_owd_output.md +44 -0
- package/skills/platform-sharing-owd-configure/references/access_levels.md +49 -0
- package/skills/platform-sharing-owd-configure/references/metadata_api_approach.md +69 -0
- package/skills/platform-sharing-rules-generate/SKILL.md +89 -19
- package/skills/platform-sharing-rules-generate/examples/test-cases.md +381 -0
- package/skills/platform-widget-generate/SKILL.md +241 -0
- package/skills/platform-widget-generate/examples/conditional.json +73 -0
- package/skills/platform-widget-generate/examples/list-with-foreach.json +66 -0
- package/skills/platform-widget-generate/examples/single-object.json +64 -0
- package/skills/platform-widget-generate/references/schema-from-lightning-type.md +76 -0
- package/skills/platform-widget-generate/references/widget-bundle-layout.md +116 -0
- package/skills/platform-widget-generate/references/widget-meta-directives.md +130 -0
- package/skills/sales-agentforce-pipeline-management-configure/SKILL.md +268 -0
- package/skills/sales-agentforce-pipeline-management-configure/assets/field-completion-template.genAiPromptTemplate-meta.xml +141 -0
- package/skills/sales-agentforce-pipeline-management-configure/assets/pipeline_management_flow.flow-meta.xml +548 -0
- package/skills/sales-agentforce-pipeline-management-configure/assets/sales_management_agent.agent +2938 -0
- package/skills/sales-agentforce-pipeline-management-configure/assets/sales_management_agent.bundle-meta.xml +4 -0
- package/skills/sales-agentforce-pipeline-management-configure/assets/sfdx-project.json +12 -0
- package/skills/sales-agentforce-pipeline-management-configure/assets/stage-descriptions/bant.txt +11 -0
- package/skills/sales-agentforce-pipeline-management-configure/assets/stage-descriptions/meddic.txt +11 -0
- package/skills/sales-agentforce-pipeline-management-configure/assets/stage-descriptions/spiced.txt +11 -0
- package/skills/sales-agentforce-pipeline-management-configure/examples/custom-prompt-instructions.md +317 -0
- package/skills/sales-agentforce-pipeline-management-configure/references/admin-communication.md +355 -0
- package/skills/sales-agentforce-pipeline-management-configure/references/agent-creation.md +383 -0
- package/skills/sales-agentforce-pipeline-management-configure/references/auth-and-cli.md +146 -0
- package/skills/sales-agentforce-pipeline-management-configure/references/automation-matrix.md +23 -0
- package/skills/sales-agentforce-pipeline-management-configure/references/autonomous-updates.md +215 -0
- package/skills/sales-agentforce-pipeline-management-configure/references/canonical-agent-path.md +75 -0
- package/skills/sales-agentforce-pipeline-management-configure/references/data-sources.md +155 -0
- package/skills/sales-agentforce-pipeline-management-configure/references/field-completion-prompt-template.md +120 -0
- package/skills/sales-agentforce-pipeline-management-configure/references/field-completion-prompts.md +149 -0
- package/skills/sales-agentforce-pipeline-management-configure/references/flags.md +13 -0
- package/skills/sales-agentforce-pipeline-management-configure/references/flow-clone-from-template.md +447 -0
- package/skills/sales-agentforce-pipeline-management-configure/references/metadata-inventory.md +330 -0
- package/skills/sales-agentforce-pipeline-management-configure/references/opportunity-stages.md +246 -0
- package/skills/sales-agentforce-pipeline-management-configure/references/repair-diagnostics.md +265 -0
- package/skills/sales-agentforce-pipeline-management-configure/references/setup-order.md +263 -0
- package/skills/sales-agentforce-pipeline-management-configure/references/soap-api-enablement.md +528 -0
- package/skills/sales-agentforce-pipeline-management-configure/scripts/CHANGES.md +180 -0
- package/skills/sales-agentforce-pipeline-management-configure/scripts/README.md +56 -0
- package/skills/sales-agentforce-pipeline-management-configure/scripts/add-field-suggestion.sh +679 -0
- package/skills/sales-agentforce-pipeline-management-configure/scripts/create-agent.sh +302 -0
- package/skills/sales-agentforce-pipeline-management-configure/scripts/create-flow.sh +250 -0
- package/skills/sales-agentforce-pipeline-management-configure/scripts/define-agent-access.sh +430 -0
- package/skills/sales-agentforce-pipeline-management-configure/scripts/deploy-settings.sh +77 -0
- package/skills/sales-agentforce-pipeline-management-configure/scripts/enable-deal-agent.sh +241 -0
- package/skills/sales-agentforce-pipeline-management-configure/scripts/enable-prerequisites.sh +538 -0
- package/skills/sales-agentforce-pipeline-management-configure/scripts/flow-debug-and-verify.sh +385 -0
- package/skills/sales-agentforce-pipeline-management-configure/scripts/retrieve-settings.sh +131 -0
- package/skills/sales-agentforce-pipeline-management-configure/scripts/setup-all.sh +2791 -0
- package/skills/sales-agentforce-pipeline-management-configure/scripts/shared/agent-bundle-publish.sh +189 -0
- package/skills/sales-agentforce-pipeline-management-configure/scripts/shared/agent-detection.sh +239 -0
- package/skills/sales-agentforce-pipeline-management-configure/scripts/shared/flow-builder.sh +238 -0
- package/skills/sales-agentforce-pipeline-management-configure/scripts/shared/psg.sh +48 -0
- package/skills/sales-agentforce-pipeline-management-configure/scripts/shared/soap.sh +140 -0
- package/skills/sales-agentforce-pipeline-management-configure/scripts/shared/stage-descriptions.sh +448 -0
- package/skills/sales-agentforce-pipeline-management-configure/scripts/shared/test-opp.sh +166 -0
- package/skills/sales-agentforce-pipeline-management-configure/scripts/verify-all.sh +636 -0
- package/skills/sales-agentforce-pipeline-management-configure/scripts/verify-prompt-generation.sh +346 -0
|
@@ -3,6 +3,16 @@ name: experience-ui-bundle-custom-app-generate
|
|
|
3
3
|
description: "MUST activate when the project contains a uiBundles/*/src/ directory and the task involves creating or configuring a Custom Application for hosting a UI bundle in Lightning Experience. Use this skill when creating a CustomApplication metadata record to surface the UI bundle in the App Launcher. Activate when files matching applications/*.app-meta.xml exist and need modification, or when the user wants to expose their app via the Lightning App Launcher without a Digital Experience Site. Do NOT use platform-custom-application-generate for this — UI bundle apps do not use tabs, action overrides, or flexipages."
|
|
4
4
|
metadata:
|
|
5
5
|
version: "1.0"
|
|
6
|
+
minApiVersion: "51.0"
|
|
7
|
+
relatedSkills:
|
|
8
|
+
- "platform-custom-application-generate"
|
|
9
|
+
cliTools:
|
|
10
|
+
- tool: ["sf"]
|
|
11
|
+
semver: ">=2.0.0"
|
|
12
|
+
mcpTools:
|
|
13
|
+
salesforce-api-context:
|
|
14
|
+
tools: ["get_metadata_type_fields"]
|
|
15
|
+
semver: ">=1.0.0"
|
|
6
16
|
---
|
|
7
17
|
|
|
8
18
|
# Custom Application for React UI Bundles
|
|
@@ -28,9 +38,9 @@ Determine values for all properties before constructing anything. Use the resolu
|
|
|
28
38
|
### Step 2: Query API Context (Version-Aware Field Discovery)
|
|
29
39
|
Call `salesforce-api-context` MCP tools to discover which fields exist for the target org's API version. This ensures the generated metadata is compatible with the user's Salesforce version.
|
|
30
40
|
|
|
31
|
-
**Required calls:**
|
|
32
|
-
1.
|
|
33
|
-
2.
|
|
41
|
+
**Required calls — use the `metadataType` parameter exactly as shown. Do not substitute a `detail` parameter or any other shape; `metadataType` is the only parameter this tool accepts:**
|
|
42
|
+
1. `get_metadata_type_fields({ "metadataType": "CustomApplication" })` — check whether the `uiBundle` field exists in the response's field list
|
|
43
|
+
2. `get_metadata_type_fields({ "metadataType": "UIBundle" })` — check whether the `target` field exists in the response's field list
|
|
34
44
|
|
|
35
45
|
**Field resolution based on API response:**
|
|
36
46
|
|
|
@@ -63,7 +73,20 @@ Use the default template in the doc below. Values in `{braces}` are resolved pro
|
|
|
63
73
|
- If Step 2 determined the older field names apply, substitute `<uiBundle>` with `<webApplication>` in the generated output.
|
|
64
74
|
|
|
65
75
|
### Step 5: Update UI Bundle Meta XML
|
|
66
|
-
|
|
76
|
+
This step edits an **existing** file — it never creates a new one. `UIBundle` is a bundle-style metadata type: its meta XML normally lives inside its own folder at `uiBundles/{appName}/{appName}.uibundle-meta.xml`, alongside the bundle's other source files (e.g. `index.html`, `src/`). Some older or hand-authored projects may instead have it at the flat path `uiBundles/{appName}.uibundle-meta.xml` (no subfolder).
|
|
77
|
+
|
|
78
|
+
Run `scripts/resolve-uibundle-path.sh "{appName}"` — it prints the path of the existing meta XML (preferring the nested layout, falling back to the flat layout). Edit that exact file in place; do not create a second file at the other path or migrate it to a different layout as part of this skill.
|
|
79
|
+
|
|
80
|
+
If Step 2 confirmed the `target` field exists on `UIBundle`, add `<target>CustomApplication</target>` inside the existing `<UIBundle>` element of that file, preserving every other existing element and value untouched (skip this step entirely if the field doesn't exist in the org's API version — do not create the file or add `<target>` in that case).
|
|
81
|
+
|
|
82
|
+
**Do NOT:**
|
|
83
|
+
- Create a new `.uibundle-meta.xml` file
|
|
84
|
+
- Create a second `.uibundle-meta.xml` file at a different path when one already exists (nested or flat) — edit the existing one in place, wherever it is
|
|
85
|
+
- Leave the original `uiBundles/{appName}/{appName}.uibundle-meta.xml` (or `uiBundles/{appName}.uibundle-meta.xml`, if that's the existing layout) unmodified while adding `<target>` somewhere else
|
|
86
|
+
|
|
87
|
+
The only files this skill produces or modifies are `applications/{appName}.app-meta.xml` (new) and the existing `{appName}.uibundle-meta.xml` (edited in place, only if `<target>` applies). Any other UI-bundle-related file appearing in the output is a bug.
|
|
88
|
+
|
|
89
|
+
Example of the fully updated file (at `uiBundles/{appName}/{appName}.uibundle-meta.xml`, or the flat path if that's the existing layout) — this illustrates the end state of the existing file, not a new file to create:
|
|
67
90
|
|
|
68
91
|
```xml
|
|
69
92
|
<?xml version="1.0" encoding="UTF-8"?>
|
|
@@ -86,7 +109,8 @@ Before deploying, confirm:
|
|
|
86
109
|
- [ ] API context was queried to determine available fields (Step 2)
|
|
87
110
|
- [ ] `applications/{appName}.app-meta.xml` exists with correct content
|
|
88
111
|
- [ ] The bundle reference field matches the org's API version (`<uiBundle>` or `<webApplication>`)
|
|
89
|
-
- [ ] If `target` field is supported:
|
|
112
|
+
- [ ] If `target` field is supported: the **existing** `{appName}.uibundle-meta.xml` (nested at `uiBundles/{appName}/`, or flat at `uiBundles/`, whichever already existed) has `<target>CustomApplication</target>`
|
|
113
|
+
- [ ] No extra `.uibundle-meta.xml` file was created — exactly one `{appName}.uibundle-meta.xml` exists, at whichever path it already lived at
|
|
90
114
|
- [ ] Deployment validates successfully:
|
|
91
115
|
```bash
|
|
92
116
|
sf project deploy validate --metadata CustomApplication UIBundle --target-org ${usernameOrAlias}
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
This configuration file creates a **net-new, default** CustomApplication metadata record for a Lightning Experience app that hosts a React UI bundle. It is not intended to edit or modify an existing CustomApplication record. Use this template only when provisioning a brand-new Custom Application for a UI bundle.
|
|
5
5
|
|
|
6
6
|
## File Location
|
|
7
|
-
```
|
|
7
|
+
```xml
|
|
8
8
|
<sourceDir>/applications/{appName}.app-meta.xml
|
|
9
9
|
```
|
|
10
10
|
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Resolve the existing path of a UIBundle's meta XML file.
|
|
3
|
+
#
|
|
4
|
+
# UIBundle metadata may live at either the nested bundle-style path
|
|
5
|
+
# (uiBundles/{appName}/{appName}.uibundle-meta.xml) or, in older/hand-authored
|
|
6
|
+
# projects, the flat path (uiBundles/{appName}.uibundle-meta.xml). This script
|
|
7
|
+
# performs the deterministic file-existence check and prints whichever path
|
|
8
|
+
# already exists, preferring the nested layout.
|
|
9
|
+
#
|
|
10
|
+
# Usage: scripts/resolve-uibundle-path.sh <appName>
|
|
11
|
+
|
|
12
|
+
set -euo pipefail
|
|
13
|
+
|
|
14
|
+
APP="${1:-}"
|
|
15
|
+
if [ -z "$APP" ]; then
|
|
16
|
+
echo "ERROR: appName argument is required" >&2
|
|
17
|
+
exit 1
|
|
18
|
+
fi
|
|
19
|
+
|
|
20
|
+
NESTED="uiBundles/${APP}/${APP}.uibundle-meta.xml"
|
|
21
|
+
FLAT="uiBundles/${APP}.uibundle-meta.xml"
|
|
22
|
+
|
|
23
|
+
if [ -f "$NESTED" ]; then
|
|
24
|
+
echo "$NESTED"
|
|
25
|
+
elif [ -f "$FLAT" ]; then
|
|
26
|
+
echo "$FLAT"
|
|
27
|
+
else
|
|
28
|
+
echo "ERROR: no .uibundle-meta.xml found for $APP" >&2
|
|
29
|
+
exit 1
|
|
30
|
+
fi
|
|
@@ -1,18 +1,37 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: experience-ui-bundle-features-generate
|
|
3
|
-
description: "MUST activate when the project contains a uiBundles/*/src/ directory and the user wants to add
|
|
3
|
+
description: "MUST activate when the project contains a uiBundles/*/src/ directory and the user wants to add a pre-built feature — such as authentication (login, logout, protected routes, session management) or search (global search across pages and content) — instead of building it from scratch. Always run list first to see the current feature catalog, since it can include more than authentication and search. Always use this skill for installing pre-built features rather than hand-building them. DO NOT TRIGGER for Agentforce conversational client or file-upload features — use experience-ui-bundle-agentforce-client-generate and experience-ui-bundle-file-upload-generate respectively."
|
|
4
4
|
metadata:
|
|
5
|
-
version: "1.
|
|
5
|
+
version: "1.1"
|
|
6
|
+
relatedSkills: ["experience-ui-bundle-agentforce-client-generate", "experience-ui-bundle-file-upload-generate"]
|
|
7
|
+
cliTools:
|
|
8
|
+
- tool: ["npx"]
|
|
9
|
+
semver: ">=7.0.0"
|
|
10
|
+
- tool: ["npm"]
|
|
11
|
+
semver: ">=7.0.0"
|
|
12
|
+
accessCheck:
|
|
13
|
+
- type: "license"
|
|
14
|
+
value: "Experience Cloud (Customer Community / Customer Community Plus)"
|
|
15
|
+
- type: "orgPref"
|
|
16
|
+
value: "Sites"
|
|
6
17
|
---
|
|
7
18
|
|
|
8
19
|
# UI Bundle Features
|
|
9
20
|
|
|
10
21
|
## Installing Pre-built Features
|
|
11
22
|
|
|
12
|
-
Always check for an existing feature before building something from scratch. The features CLI installs pre-built, tested packages into Salesforce UI bundles — from foundational UI libraries (shadcn/ui) to full-stack capabilities
|
|
23
|
+
Always check for an existing feature before building something from scratch. The features CLI installs pre-built, tested packages into Salesforce UI bundles — from foundational UI libraries (shadcn/ui) to full-stack capabilities. Authentication and search are the most commonly used features today; run `list --verbose` for the full current catalog, since it can grow over time.
|
|
24
|
+
|
|
25
|
+
> **Ownership note:** Agentforce AI conversation clients and file-upload are owned by separate skills (`experience-ui-bundle-agentforce-client-generate`, `experience-ui-bundle-file-upload-generate`). If the catalog also lists an Agentforce or file-upload entry, do not install it from both places — confirm with the user which delivery path they want, and never install the same capability twice in one bundle.
|
|
26
|
+
|
|
27
|
+
> **Package name:** `@salesforce/ui-bundle-features` is the canonical package name. Some older templates/samples still reference the deprecated `@salesforce/ui-bundle-features-experimental` name — never use the `-experimental` suffix. If a command fails to resolve, confirm the published version with `npm view @salesforce/ui-bundle-features version` before assuming the package name is wrong.
|
|
13
28
|
|
|
14
29
|
### Workflow
|
|
15
30
|
|
|
31
|
+
0. **Confirm this is a React UI bundle** — this CLI copies into `src/features/` and expects `npm run build` to work. Non-React bundles are not supported and will fail late in the install.
|
|
32
|
+
|
|
33
|
+
Run `scripts/verify-react-bundle.sh`. If it exits non-zero, stop — the bundle is not React-based and this skill cannot proceed.
|
|
34
|
+
|
|
16
35
|
1. **Search project code first** — check `src/` for existing implementations before installing anything. Scope searches to `src/` to avoid matching `node_modules/` or `dist/`.
|
|
17
36
|
|
|
18
37
|
2. **Search available features** — use `npx @salesforce/ui-bundle-features list` with `--search <query>` to filter by keyword. Use `--verbose` for full descriptions.
|
|
@@ -24,24 +43,80 @@ Always check for an existing feature before building something from scratch. The
|
|
|
24
43
|
- `--yes` for non-interactive mode (skips conflicts)
|
|
25
44
|
- `--on-conflict error` to detect conflicts, then `--conflict-resolution <file>` to resolve them
|
|
26
45
|
|
|
46
|
+
Install features **before** doing custom frontend/layout work in this bundle — features may rewrite `appLayout.tsx`/`routes.tsx`, and installing after hand-built layout changes risks collisions.
|
|
47
|
+
|
|
27
48
|
If no matching feature is found, ask the user before building a custom implementation — a relevant feature may exist under a different name.
|
|
28
49
|
|
|
29
50
|
### Conflict Handling
|
|
30
51
|
|
|
31
|
-
In non-interactive environments, use the two-pass approach:
|
|
52
|
+
In non-interactive environments, use the two-pass approach:
|
|
32
53
|
|
|
33
|
-
|
|
54
|
+
1. Run install with `--on-conflict error` to detect conflicts without applying them.
|
|
55
|
+
2. Before writing the resolution file, read `references/conflict-resolution-schema.json` for the allowed keys and enum values.
|
|
56
|
+
3. Write a resolution file at `<ui-bundle-dir>/conflict-resolution.json` (path is relative to the UI bundle directory being installed into, not the repo root). Key it by the exact paths the CLI printed as conflicts in pass 1, verbatim:
|
|
57
|
+
```json
|
|
58
|
+
{
|
|
59
|
+
"src/appLayout.tsx": "overwrite",
|
|
60
|
+
"src/routes.tsx": "skip"
|
|
61
|
+
}
|
|
62
|
+
```
|
|
63
|
+
Any conflicting path *not* listed in this file defaults to `skip` — the CLI will not overwrite a file you didn't explicitly mark `overwrite`.
|
|
64
|
+
4. Re-run install with `--conflict-resolution <path-to-that-file>`.
|
|
34
65
|
|
|
35
|
-
|
|
66
|
+
### Post-install: Integrating Example Files
|
|
36
67
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
68
|
+
Features may include example files under an `__examples__/` directory (plural) showing integration patterns. These are often full, working pages with concrete names (e.g. `AccountSearch.tsx`), not bare placeholder templates. For each:
|
|
69
|
+
|
|
70
|
+
1. Read the example file to understand the pattern — treat it as a working reference implementation, not necessarily a stub.
|
|
71
|
+
2. Read the target file (shown in `describe` output).
|
|
72
|
+
3. Apply the pattern from the example into the target.
|
|
73
|
+
4. **CRITICAL — verify before deleting:**
|
|
74
|
+
```bash
|
|
75
|
+
# Verify the build passes with the integrated pattern
|
|
76
|
+
npm run build || {
|
|
77
|
+
echo "ERROR: Build failed after integration - do NOT delete __examples__/"
|
|
78
|
+
exit 1
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
# Verify the pattern from the example is actually present in the target
|
|
82
|
+
# (adjust grep pattern to match a key symbol/import/component from the example)
|
|
83
|
+
# Example: for SearchInput pattern integrated into AccountSearch.tsx
|
|
84
|
+
grep -q "SearchInput\|useSearch" src/pages/*.tsx src/components/*.tsx 2>/dev/null || {
|
|
85
|
+
echo "ERROR: Pattern from example not found in target files - integration incomplete"
|
|
86
|
+
echo "Do NOT delete __examples__/ until the pattern is confirmed present"
|
|
87
|
+
exit 1
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
# Only delete after both checks pass
|
|
91
|
+
rm -rf __examples__/
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
If either check fails, **do NOT delete `__examples__/`** — the integration is incomplete. Fix the integration first, then re-run the verification.
|
|
41
95
|
|
|
42
96
|
### Hint Placeholders
|
|
43
97
|
|
|
44
|
-
Some copy paths use `<descriptive-name>` placeholders (e.g., `<desired-page-with-search-input>`) that the CLI does not resolve. After installation, rename or relocate these files to the intended target, or integrate their patterns into an existing file.
|
|
98
|
+
Some copy paths use `<descriptive-name>` placeholders (e.g., `<desired-page-with-search-input>`) that the CLI does not resolve. After installation, rename or relocate these files to the intended target, or integrate their patterns into an existing file. This is separate from the `__examples__/` convention above — a single copy path can use either mechanism.
|
|
99
|
+
|
|
100
|
+
### Auth Feature: Org-Side Prerequisites
|
|
101
|
+
|
|
102
|
+
Installing the authentication feature only copies files — it does not configure the org. Before telling the user auth is done, flag that these org-side steps still need to happen (outside this skill's scope, but required for the feature to actually work):
|
|
103
|
+
|
|
104
|
+
- Digital Experiences (Experience Cloud) must be enabled, with Customer Community / Customer Community Plus licenses assigned to the relevant users, and Salesforce Sites enabled.
|
|
105
|
+
- The community and guest profiles need explicit Apex class access granted for the auth utility, login/registration, and password-reset classes — the CLI does not grant this automatically.
|
|
106
|
+
- Guest-profile sharing rules / org-wide defaults for any objects the auth flow touches.
|
|
107
|
+
- **Known limitation:** logout has a documented CSRF-handling gap (tracked as W-21253864) — call this out to the user rather than presenting logout as fully solved.
|
|
108
|
+
|
|
109
|
+
### CRITICAL: Resolve `<sfdxRoot>` After Every Install
|
|
110
|
+
|
|
111
|
+
The CLI may copy files under a literal `<sfdxRoot>` folder — an unresolved placeholder for this project's Salesforce DX metadata root (from `sfdx-project.json`'s `packageDirectories[].path`, e.g. `force-app/main/default`). Files left there are undeployable.
|
|
112
|
+
|
|
113
|
+
**After every install:**
|
|
114
|
+
```bash
|
|
115
|
+
find uiBundles/<AppName> -type d -regex '.*/<[^/]+>$'
|
|
116
|
+
```
|
|
117
|
+
If found, move each file to `<metadata-root>/<same-relative-subpath>` (keep `-meta.xml` sidecars attached) and delete the emptied placeholder dir(s).
|
|
45
118
|
|
|
119
|
+
**Verification:**
|
|
120
|
+
- [ ] Re-run `find uiBundles/<AppName> -type d -regex '.*/<[^/]+>$'` — output must be empty before proceeding.
|
|
46
121
|
|
|
47
122
|
|
package/skills/experience-ui-bundle-features-generate/references/conflict-resolution-schema.json
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"title": "UI Bundle Features Conflict Resolution",
|
|
4
|
+
"description": "Schema for conflict-resolution.json used by @salesforce/ui-bundle-features CLI",
|
|
5
|
+
"type": "object",
|
|
6
|
+
"patternProperties": {
|
|
7
|
+
"^.+$": {
|
|
8
|
+
"type": "string",
|
|
9
|
+
"enum": ["overwrite", "skip"],
|
|
10
|
+
"description": "Resolution strategy for a conflicting file path. 'overwrite' replaces the existing file, 'skip' keeps the existing file."
|
|
11
|
+
}
|
|
12
|
+
},
|
|
13
|
+
"additionalProperties": false,
|
|
14
|
+
"examples": [
|
|
15
|
+
{
|
|
16
|
+
"src/appLayout.tsx": "overwrite",
|
|
17
|
+
"src/routes.tsx": "skip"
|
|
18
|
+
}
|
|
19
|
+
]
|
|
20
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Verify that the project contains a React-based UI bundle
|
|
3
|
+
# Exit 0 if React is found, exit 1 otherwise
|
|
4
|
+
|
|
5
|
+
set -euo pipefail
|
|
6
|
+
|
|
7
|
+
if ! grep -q '"react"' uiBundles/*/package.json 2>/dev/null; then
|
|
8
|
+
echo "ERROR: Not a React bundle - @salesforce/ui-bundle-features requires React"
|
|
9
|
+
echo "Found bundle type: $(grep '"type"' uiBundles/*/package.json 2>/dev/null || echo 'unknown')"
|
|
10
|
+
exit 1
|
|
11
|
+
fi
|
|
12
|
+
|
|
13
|
+
echo "React bundle detected"
|
|
14
|
+
exit 0
|
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: experience-ui-bundle-frontend-generate
|
|
3
|
-
description: "MUST activate before editing ANY file under uiBundles/*/src/ for visual or UI changes to an EXISTING app — pages, components, sections, layout, styling, colors, fonts, navigation, animations, or any look-and-feel change. Use this skill when modifying pages, components, layout, styling, or navigation in an existing UI bundle app. Activate when the project contains appLayout.tsx, routes.tsx, src/pages/, src/components/, or global.css. This skill contains critical project-specific conventions (appLayout.tsx shell, shadcn/ui components, Tailwind CSS, Salesforce base-path routing, module restrictions) that override general knowledge. Without this skill, generated code will use wrong imports, break routing, or ignore project structure. Do NOT use when creating a new app from scratch (use experience-ui-bundle-app-coordinate instead)."
|
|
3
|
+
description: "MUST activate before editing ANY file under uiBundles/*/src/ for visual or UI changes to an EXISTING app — pages, components, sections, layout, styling, colors, fonts, navigation, animations, or any look-and-feel change. Use this skill when modifying pages, components, layout, styling, or navigation in an existing UI bundle app. Activate when the project contains appLayout.tsx, routes.tsx, src/pages/, src/components/, or src/styles/global.css. This skill contains critical project-specific conventions (appLayout.tsx shell, shadcn/ui components, Tailwind CSS, Salesforce base-path routing, module restrictions) that override general knowledge. Without this skill, generated code will use wrong imports, break routing, or ignore project structure. Do NOT use when creating a new app from scratch (use experience-ui-bundle-app-coordinate instead)."
|
|
4
4
|
metadata:
|
|
5
5
|
version: "1.0"
|
|
6
|
+
relatedSkills:
|
|
7
|
+
- "experience-ui-bundle-app-coordinate"
|
|
8
|
+
- "experience-ui-bundle-salesforce-data-access"
|
|
6
9
|
---
|
|
7
10
|
|
|
8
11
|
# UI Bundle UI
|
|
@@ -78,6 +81,8 @@ React UI bundles must not import Salesforce platform modules like `lightning/*`
|
|
|
78
81
|
|
|
79
82
|
## Design Thinking
|
|
80
83
|
|
|
84
|
+
The rules in this section and "Frontend Aesthetics" below are creative direction, not hard constraints — they cannot be lint- or build-checked and are judged by review, not automation. Two hard, checkable exceptions: never default to Inter/Roboto/Arial/Space Grotesk/system fonts, and mobile responsiveness (Tailwind breakpoints, 44px touch targets) is a MUST, not a style preference.
|
|
85
|
+
|
|
81
86
|
Before coding, commit to a bold aesthetic direction:
|
|
82
87
|
|
|
83
88
|
- **Purpose:** What problem does this interface solve? Who uses it?
|
|
@@ -7,6 +7,39 @@
|
|
|
7
7
|
3. **Use design tokens** — prefer `bg-background`, `text-foreground`, `text-muted-foreground`, `border`, `bg-primary`, `text-destructive`, `rounded-lg` over hardcoded colors.
|
|
8
8
|
4. **Use `cn()`** from `@/lib/utils` for conditional or composable class names.
|
|
9
9
|
5. **TypeScript** — functional components with typed props interface; always accept `className?: string`.
|
|
10
|
+
6. **Never assume a primitive or its exports exist** — the shadcn inventory below is a common baseline, not a guarantee for every app. Before importing anything from `@/components/ui`, read `src/components/ui/index.ts` (the barrel) to confirm the component is actually re-exported there. If it isn't, either import directly from its file (`@/components/ui/<file>`) or add the export to the barrel yourself — never invent a component that isn't present in either place.
|
|
11
|
+
|
|
12
|
+
### Common shadcn/ui Inventory
|
|
13
|
+
|
|
14
|
+
Apps scaffolded from the standard template typically ship these primitives under `src/components/ui/`. Treat this as a starting checklist, not a source of truth — always verify against the actual files and the barrel (`index.ts`) in the current project, since apps diverge (custom primitives get added, unused ones get removed, and not every file is necessarily re-exported from the barrel).
|
|
15
|
+
|
|
16
|
+
| Primitive | Typical file | Notes |
|
|
17
|
+
|---|---|---|
|
|
18
|
+
| Alert | `alert.tsx` | `Alert`, `AlertTitle`, `AlertDescription` |
|
|
19
|
+
| Avatar | `avatar.tsx` | `Avatar`, `AvatarImage`, `AvatarFallback` |
|
|
20
|
+
| Badge | `badge.tsx` | Often exists as a file but may not be barrel-exported — check first |
|
|
21
|
+
| Breadcrumb | `breadcrumb.tsx` | |
|
|
22
|
+
| Button | `button.tsx` | `Button`, `buttonVariants` |
|
|
23
|
+
| Calendar | `calendar.tsx` | |
|
|
24
|
+
| Card | `card.tsx` | `Card`, `CardHeader`, `CardTitle`, `CardContent`, `CardFooter` |
|
|
25
|
+
| Checkbox | `checkbox.tsx` | |
|
|
26
|
+
| Collapsible | `collapsible.tsx` | |
|
|
27
|
+
| Date Picker | `datePicker.tsx` | |
|
|
28
|
+
| Dialog | `dialog.tsx` | `Dialog`, `DialogContent`, `DialogHeader`, `DialogTitle`, `DialogTrigger` |
|
|
29
|
+
| Dropdown Menu | `dropdown-menu.tsx` | |
|
|
30
|
+
| Field | `field.tsx` | Composable form-field wrapper (label + error + description) |
|
|
31
|
+
| Input | `input.tsx` | |
|
|
32
|
+
| Label | `label.tsx` | |
|
|
33
|
+
| Pagination | `pagination.tsx` | |
|
|
34
|
+
| Popover | `popover.tsx` | |
|
|
35
|
+
| Select | `select.tsx` | |
|
|
36
|
+
| Separator | `separator.tsx` | |
|
|
37
|
+
| Skeleton | `skeleton.tsx` | |
|
|
38
|
+
| Spinner | `spinner.tsx` | |
|
|
39
|
+
| Table | `table.tsx` | `Table`, `TableHeader`, `TableBody`, `TableRow`, `TableCell` |
|
|
40
|
+
| Tabs | `tabs.tsx` | `Tabs`, `TabsList`, `TabsTrigger`, `TabsContent` |
|
|
41
|
+
|
|
42
|
+
**Not part of this baseline** — do not assume these exist without checking: `Sheet`, `Combobox`, `Accordion`, `Toast`/`Sonner`, `Slider`, `Switch`, `RadioGroup`, `Command`, `Menubar`, `NavigationMenu`, `Tooltip`, `Progress`, `Carousel`, `Drawer`. If the task needs one of these, check `src/components/ui/` first; if it's genuinely missing, either compose it from an existing primitive or tell the user it needs to be added rather than fabricating an import.
|
|
10
43
|
|
|
11
44
|
### File Location — Component
|
|
12
45
|
|
|
@@ -69,7 +102,7 @@ export default function HomePage() {
|
|
|
69
102
|
- **Icons:** `lucide-react`; add `aria-hidden="true"` on decorative icons
|
|
70
103
|
- **Focus styles:** use `focus-visible:` variants
|
|
71
104
|
- **Multiple visual variants:** use CVA (`cva`) and `VariantProps`
|
|
72
|
-
- **shadcn import barrel:** `import { Button, Card, Input } from "@/components/ui"`
|
|
105
|
+
- **shadcn import barrel:** `import { Button, Card, Input } from "@/components/ui"` — only for components confirmed present in `index.ts`; see rule 6 above
|
|
73
106
|
|
|
74
107
|
### Confirm — Component
|
|
75
108
|
|
|
@@ -82,7 +82,7 @@ Use `ROUTES.*` constants from `@/utils/authenticationConfig` for auth-related pa
|
|
|
82
82
|
|
|
83
83
|
- **Local state:** `useState`, `useReducer`, `useRef` inside the page component
|
|
84
84
|
- **Shared or complex state:** extract to `src/hooks/` with a `use` prefix (e.g., `useContacts`)
|
|
85
|
-
- **Data fetching:**
|
|
85
|
+
- **Data fetching:** any Salesforce record access — GraphQL or REST — goes through the `@salesforce/platform-sdk` Data SDK (`createDataSDK()`, then `sdk.graphql`/`sdk.fetch`); consult the `experience-ui-bundle-salesforce-data-access` skill before writing this code, do not call `fetch`/`axios` directly or invent a different data API. Place client/query modules in `src/api/`; place shared data logic (loading, error, caching state) in `src/hooks/`
|
|
86
86
|
- **Auth context:** `useAuth()` from `@/context/AuthContext` when current user is needed — only valid under `AuthProvider`
|
|
87
87
|
|
|
88
88
|
### Confirm — Page
|
|
@@ -1,8 +1,18 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: experience-ui-bundle-metadata-generate
|
|
3
|
-
description: "
|
|
3
|
+
description: "Use this skill when adding a front-end React UI bundle to an existing project or configuring UI bundle metadata and config files. TRIGGER when: adding or scaffolding a new UI bundle inside a project that already exists; running sf template generate ui-bundle; editing ui-bundle.json routing, headers, or output directory; working with *.uibundle-meta.xml files; or registering CSP Trusted Sites, resolving blocked images or fonts or external API calls, or editing cspTrustedSites/*.cspTrustedSite-meta.xml files. DO NOT TRIGGER when: creating a brand-new Salesforce project from scratch, where the whole SFDX starter project (UI bundle plus Experience Site metadata and toolchain) is generated together (use experience-ui-bundle-project-generate)."
|
|
4
4
|
metadata:
|
|
5
5
|
version: "1.0"
|
|
6
|
+
minApiVersion: "51.0"
|
|
7
|
+
relatedSkills:
|
|
8
|
+
- "experience-ui-bundle-frontend-generate"
|
|
9
|
+
- "experience-ui-bundle-custom-app-generate"
|
|
10
|
+
- "experience-ui-bundle-site-generate"
|
|
11
|
+
cliTools:
|
|
12
|
+
- tool: ["sf"]
|
|
13
|
+
semver: ">=2.0.0"
|
|
14
|
+
- tool: ["jq"]
|
|
15
|
+
semver: ">=1.6"
|
|
6
16
|
---
|
|
7
17
|
|
|
8
18
|
# UI Bundle Metadata
|
|
@@ -11,9 +21,9 @@ metadata:
|
|
|
11
21
|
|
|
12
22
|
Use `sf template generate ui-bundle` to create new apps — not create-react-app, Vite, or other generic scaffolds.
|
|
13
23
|
|
|
14
|
-
**Always pass `--template reactbasic`** to scaffold a React-based bundle.
|
|
15
|
-
|
|
16
|
-
|
|
24
|
+
- **Always pass `--template reactbasic`** to scaffold a React-based bundle.
|
|
25
|
+
- **UI bundle name (`-n`):** Alphanumerical only — no spaces, hyphens, underscores, or special characters.
|
|
26
|
+
- Pass `--output-dir` to use a different location for template generation.
|
|
17
27
|
|
|
18
28
|
**Example:**
|
|
19
29
|
```bash
|
|
@@ -21,10 +31,11 @@ sf template generate ui-bundle -n CoffeeBoutique --template reactbasic
|
|
|
21
31
|
```
|
|
22
32
|
|
|
23
33
|
After generation:
|
|
24
|
-
1.
|
|
25
|
-
2.
|
|
26
|
-
3.
|
|
27
|
-
4.
|
|
34
|
+
1. **Verify API version** — run `bash <skill_dir>/scripts/check-api-version.sh` from the project root to ensure `sourceApiVersion` in `sfdx-project.json` is 67.0 or higher. The script will automatically update it if needed.
|
|
35
|
+
2. Replace all default boilerplate — "React App", "Vite + React", default `<title>`, placeholder text
|
|
36
|
+
3. Populate the home page with real content (landing section, banners, hero, navigation)
|
|
37
|
+
4. Update navigation and placeholders (see the `experience-ui-bundle-frontend-generate` skill)
|
|
38
|
+
5. **Configure a hosting target** — a UI bundle without a `<target>` in its meta XML will not be visible in the org. Use `experience-ui-bundle-custom-app-generate` for internal (App Launcher) apps or `experience-ui-bundle-site-generate` for external (Experience Site) apps.
|
|
28
39
|
|
|
29
40
|
Always install dependencies before running any scripts in the UI bundle directory.
|
|
30
41
|
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
## File location
|
|
4
4
|
|
|
5
|
-
```
|
|
5
|
+
```text
|
|
6
6
|
force-app/main/default/cspTrustedSites/{Name}.cspTrustedSite-meta.xml
|
|
7
7
|
```
|
|
8
8
|
|
|
@@ -256,7 +256,7 @@ Some services split resources across multiple subdomains. Create one CSP Trusted
|
|
|
256
256
|
|
|
257
257
|
If the browser console shows a CSP error like:
|
|
258
258
|
|
|
259
|
-
```
|
|
259
|
+
```text
|
|
260
260
|
Refused to load the image 'https://example.com/image.png' because it violates
|
|
261
261
|
the following Content Security Policy directive: "img-src 'self' ..."
|
|
262
262
|
```
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# Checks that sourceApiVersion in sfdx-project.json is 67.0 or higher.
|
|
3
|
+
# If lower, updates it to "67.0".
|
|
4
|
+
|
|
5
|
+
set -e
|
|
6
|
+
|
|
7
|
+
PROJECT_FILE="sfdx-project.json"
|
|
8
|
+
|
|
9
|
+
if [[ ! -f "$PROJECT_FILE" ]]; then
|
|
10
|
+
echo "ERROR: $PROJECT_FILE not found in current directory"
|
|
11
|
+
exit 1
|
|
12
|
+
fi
|
|
13
|
+
|
|
14
|
+
# Extract sourceApiVersion and check if it's below 67.0
|
|
15
|
+
version=$(jq -r '.sourceApiVersion // "0"' "$PROJECT_FILE")
|
|
16
|
+
is_below=$(jq --arg v "$version" -n '($v | split(".") | .[0] | tonumber) < 67')
|
|
17
|
+
|
|
18
|
+
if [[ "$is_below" == "true" ]]; then
|
|
19
|
+
echo "WARNING: sourceApiVersion is $version (< 67.0)"
|
|
20
|
+
echo "Updating $PROJECT_FILE to set sourceApiVersion to \"67.0\""
|
|
21
|
+
|
|
22
|
+
# Update the file
|
|
23
|
+
jq '.sourceApiVersion = "67.0"' "$PROJECT_FILE" > "$PROJECT_FILE.tmp"
|
|
24
|
+
mv "$PROJECT_FILE.tmp" "$PROJECT_FILE"
|
|
25
|
+
|
|
26
|
+
echo "OK: Updated sourceApiVersion to 67.0"
|
|
27
|
+
exit 0
|
|
28
|
+
fi
|
|
29
|
+
|
|
30
|
+
echo "OK: sourceApiVersion is $version (>= 67.0)"
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: experience-ui-bundle-project-generate
|
|
3
|
+
description: "Generates a minimal, ready-to-develop SFDX starter project from template instead of hand-scaffolding files. Use this skill when starting a brand-new Salesforce React UI bundle app and the initial project must be scaffolded — trigger phrases include create, start, or scaffold a new React UI bundle app, generate a starter project, or use a prebuilt/starter template. DO NOT TRIGGER when: editing, styling, or adding pages or components to an EXISTING app (use experience-ui-bundle-frontend-generate); configuring ui-bundle.json or metadata files (use experience-ui-bundle-metadata-generate); deploying to an org (use experience-ui-bundle-deploy); or when the user explicitly says they want to hand-scaffold from scratch."
|
|
4
|
+
metadata:
|
|
5
|
+
version: "1.1"
|
|
6
|
+
relatedSkills:
|
|
7
|
+
- "experience-ui-bundle-app-coordinate"
|
|
8
|
+
- "experience-ui-bundle-metadata-generate"
|
|
9
|
+
- "experience-ui-bundle-frontend-generate"
|
|
10
|
+
- "experience-ui-bundle-salesforce-data-access"
|
|
11
|
+
- "experience-ui-bundle-deploy"
|
|
12
|
+
cliTools:
|
|
13
|
+
- tool: ["sf"]
|
|
14
|
+
semver: ">=2.0.0"
|
|
15
|
+
- tool: ["npm"]
|
|
16
|
+
semver: ">=7.0.0"
|
|
17
|
+
- tool: ["node"]
|
|
18
|
+
semver: ">=16.7.0"
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
# Using a UI Bundle Template
|
|
22
|
+
|
|
23
|
+
Before building a Salesforce React UI bundle app from scratch, offer the user a **prebuilt starter template**. The Salesforce CLI generates these — a complete, deployable SFDX project (React UI bundle + toolchain + an `npm run setup` automation) — in one command. Starting from a starter is faster and less error-prone than hand-scaffolding.
|
|
24
|
+
|
|
25
|
+
The CLI command is `sf template generate project`.
|
|
26
|
+
|
|
27
|
+
## Step 1: Offer the choice
|
|
28
|
+
|
|
29
|
+
The following are the templates. Ask the user which one fits, or whether they want to start from scratch.
|
|
30
|
+
|
|
31
|
+
| Template | `--template` flag | Best for |
|
|
32
|
+
|----------|-------------------|----------|
|
|
33
|
+
| Internal starter | `reactinternalapp` | Starter for internal, employee-facing Salesforce apps (e.g. support consoles, ops dashboards, internal admin apps) — users are already-authenticated employees. Includes Agentforce chat. No login flow or public. |
|
|
34
|
+
| External starter | `reactexternalapp` | Starter for customer/partner-facing Salesforce apps/sites (e.g. portals, communities, storefront, public sites). Full auth support (login, registration, reset, profile) -- external users sign in with their own accounts. |
|
|
35
|
+
|
|
36
|
+
**If the user prefers to start from scratch** (or neither fits), stop here and let `experience-ui-bundle-app-coordinate` scaffold a new project. This skill is opt-in — do not force a template.
|
|
37
|
+
|
|
38
|
+
## Step 2: Generate the project into the target root
|
|
39
|
+
|
|
40
|
+
The project contents must land **directly at the target root `$DEST`** — so `sfdx-project.json` sits at `$DEST/sfdx-project.json`, with no extra wrapper subfolder. `sf template generate project` always nests its output under a `--name` subfolder, so generate into the `$DEST` dir, then move the contents from the subfolder up into `$DEST`, overwriting anything already there on conflict. Remove the empty subfolder at the end.
|
|
41
|
+
|
|
42
|
+
- `<SKILL_DIR>` = the absolute path to **this skill's own directory** — the folder containing this `SKILL.md`; resolve it from the skill path in context
|
|
43
|
+
- **`$NAME`** — the project name (alphanumerical only — no spaces, hyphens, underscores, or special characters). Ask the user for it. It also names the UI bundle, so it shows up inside the project.
|
|
44
|
+
- **`$DEST`** — the target root directory the contents land in (use `.` for the current directory).
|
|
45
|
+
|
|
46
|
+
```sh
|
|
47
|
+
NAME=MyApp # project name the user chose; also names the UI bundle
|
|
48
|
+
DEST=. # target root directory (the contents land directly here, no NAME/ wrapper)
|
|
49
|
+
|
|
50
|
+
# choose ONE template flag based on the user's pick from Step 1
|
|
51
|
+
TEMPLATE=reactinternalapp # or reactexternalapp
|
|
52
|
+
|
|
53
|
+
mkdir -p "$DEST"
|
|
54
|
+
sf template generate project --name "$NAME" --template "$TEMPLATE" --output-dir "$DEST"
|
|
55
|
+
|
|
56
|
+
# Flatten the generated $DEST/$NAME contents up into $DEST (see <SKILL_DIR>/scripts/flatten-project.mjs).
|
|
57
|
+
# Use the absolute skill-dir path — a relative ./scripts/ would resolve against $DEST, not the skill.
|
|
58
|
+
node "<SKILL_DIR>/scripts/flatten-project.mjs" "$DEST/$NAME" "$DEST"
|
|
59
|
+
rm -rf "$DEST/$NAME"
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
> `<SKILL_DIR>/scripts/flatten-project.mjs` moves every generated entry (incl. dotfiles) into `$DEST`, overwriting any existing file/dir of any type on conflict while preserving unrelated files the user already had in `$DEST`. The per-entry `rmSync` + `renameSync` is what guarantees the template's files win on conflict (including a file-vs-directory type mismatch).
|
|
63
|
+
|
|
64
|
+
### Verify
|
|
65
|
+
|
|
66
|
+
After generation, confirm the contents landed at the root (not in a `$NAME/` subfolder):
|
|
67
|
+
|
|
68
|
+
```sh
|
|
69
|
+
test -f "$DEST/sfdx-project.json" && echo "OK: project root landed" || echo "FAILED"
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
`sfdx-project.json` must sit at `$DEST/sfdx-project.json`. The project also contains `package.json`, `force-app/main/default/uiBundles/$NAME/` (the React/Vite bundle), `scripts/`, `config/`, and `README.md`. If `sfdx-project.json` is missing or is one level down in `$DEST/$NAME/`, the flatten did not run — re-check before continuing.
|
|
73
|
+
|
|
74
|
+
## Step 3: Install dependencies (you do this — do NOT hand off uninstalled)
|
|
75
|
+
|
|
76
|
+
If the generated project ships **without** `node_modules`, **install dependencies yourself before handing the project back** — a fresh template is not runnable (preview/build/lint all fail) until deps are present. The user should receive a ready-to-develop project.
|
|
77
|
+
|
|
78
|
+
There are **multiple** `package.json` files, each needing its own install:
|
|
79
|
+
- the **project root** (`$DEST/package.json`), and
|
|
80
|
+
- the **UI bundle** dir under `$DEST/force-app/main/default/uiBundles/$NAME/` — this holds the toolchain the preview server loads, so it must have `node_modules` too.
|
|
81
|
+
|
|
82
|
+
```sh
|
|
83
|
+
# 1. project root ($DEST was set in Step 2)
|
|
84
|
+
( cd "$DEST" && npm install )
|
|
85
|
+
|
|
86
|
+
# 2. each UI bundle
|
|
87
|
+
for b in "$DEST"/force-app/main/default/uiBundles/*/; do
|
|
88
|
+
[ -f "$b/package.json" ] && ( cd "$b" && npm install )
|
|
89
|
+
done
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
> First-run install of the bundle is the heavy step (tailwind, radix-ui, recharts, vite, etc.); expect a short wait. If an install fails, surface it — don't hand off a half-installed project.
|
|
93
|
+
|
|
94
|
+
## Step 4: Confirm and hand off
|
|
95
|
+
|
|
96
|
+
Verify the project landed and is installed:
|
|
97
|
+
|
|
98
|
+
```sh
|
|
99
|
+
ls "$DEST" # sfdx-project.json, package.json, force-app/, scripts/, README.md ...
|
|
100
|
+
ls "$DEST"/force-app/main/default/uiBundles/*/node_modules >/dev/null && echo "bundle deps installed"
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
The project is now ready to develop and deploy. If there's a `README.md` in the template, take a look at it to see if there is any extra step or guidance for the user.
|
|
104
|
+
|
|
105
|
+
From here, continue development with the other ui-bundle skills (`experience-ui-bundle-frontend-generate`, `experience-ui-bundle-salesforce-data-access`, `experience-ui-bundle-deploy`, etc.) against the now-scaffolded project — scaffolding and dependency install are already done.
|
|
106
|
+
|
|
107
|
+
## Notes
|
|
108
|
+
|
|
109
|
+
- The starters are **minimal** — no seeded sample data or custom objects. Build the rest with the other ui-bundle skills.
|
|
110
|
+
- These templates use the `uiBundles` metadata convention. The UI bundle directory and meta XML are named after the project name you pass to `--name`.
|
|
111
|
+
- `sf template generate project --help` lists all available templates if the flag names ever change.
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// Flatten a `sf template generate project` result into the target root.
|
|
3
|
+
//
|
|
4
|
+
// Usage: node <skill_dir>/scripts/flatten-project.mjs <srcDir> <destDir>
|
|
5
|
+
// <srcDir> — the generated project dir (the `$STAGE/$NAME` subfolder the CLI nests output under)
|
|
6
|
+
// <destDir> — the target root the contents should land in (so sfdx-project.json sits at <destDir>/sfdx-project.json)
|
|
7
|
+
//
|
|
8
|
+
// Moves every generated entry (incl. dotfiles) from <srcDir> up into <destDir>, overwriting any
|
|
9
|
+
// existing file/dir of any type on conflict. Unrelated files already in <destDir> are left untouched
|
|
10
|
+
// — only the paths the template ships get replaced. The per-entry rmSync + renameSync is what
|
|
11
|
+
// guarantees the template's files win on conflict (including a file-vs-directory type mismatch).
|
|
12
|
+
// Requires Node ≥ 16.7 for rmSync.
|
|
13
|
+
|
|
14
|
+
import fs from "node:fs";
|
|
15
|
+
import path from "node:path";
|
|
16
|
+
|
|
17
|
+
const [src, dest] = process.argv.slice(2);
|
|
18
|
+
|
|
19
|
+
if (!src || !dest) {
|
|
20
|
+
console.error("usage: node <skill_dir>/scripts/flatten-project.mjs <srcDir> <destDir>");
|
|
21
|
+
process.exit(1);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
if (!fs.existsSync(path.join(src, "sfdx-project.json"))) {
|
|
25
|
+
console.error("generated project has no sfdx-project.json: " + src);
|
|
26
|
+
process.exit(1);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
for (const entry of fs.readdirSync(src)) {
|
|
30
|
+
const target = path.join(dest, entry);
|
|
31
|
+
fs.rmSync(target, { recursive: true, force: true });
|
|
32
|
+
fs.renameSync(path.join(src, entry), target);
|
|
33
|
+
}
|