@salesforce/ui-bundle-template-app-react-template-b2e 1.117.2
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/LICENSE.txt +82 -0
- package/README.md +52 -0
- package/dist/.forceignore +15 -0
- package/dist/.husky/pre-commit +4 -0
- package/dist/.prettierignore +11 -0
- package/dist/.prettierrc +17 -0
- package/dist/AGENT.md +193 -0
- package/dist/CHANGELOG.md +2128 -0
- package/dist/README.md +52 -0
- package/dist/config/project-scratch-def.json +13 -0
- package/dist/eslint.config.js +7 -0
- package/dist/force-app/main/default/uiBundles/reactinternalapp/.forceignore +15 -0
- package/dist/force-app/main/default/uiBundles/reactinternalapp/.graphqlrc.yml +2 -0
- package/dist/force-app/main/default/uiBundles/reactinternalapp/.prettierignore +9 -0
- package/dist/force-app/main/default/uiBundles/reactinternalapp/.prettierrc +11 -0
- package/dist/force-app/main/default/uiBundles/reactinternalapp/CHANGELOG.md +10 -0
- package/dist/force-app/main/default/uiBundles/reactinternalapp/README.md +35 -0
- package/dist/force-app/main/default/uiBundles/reactinternalapp/codegen.yml +95 -0
- package/dist/force-app/main/default/uiBundles/reactinternalapp/components.json +18 -0
- package/dist/force-app/main/default/uiBundles/reactinternalapp/e2e/app.spec.ts +17 -0
- package/dist/force-app/main/default/uiBundles/reactinternalapp/eslint.config.js +169 -0
- package/dist/force-app/main/default/uiBundles/reactinternalapp/index.html +12 -0
- package/dist/force-app/main/default/uiBundles/reactinternalapp/package.json +69 -0
- package/dist/force-app/main/default/uiBundles/reactinternalapp/playwright.config.ts +24 -0
- package/dist/force-app/main/default/uiBundles/reactinternalapp/reactinternalapp.uibundle-meta.xml +7 -0
- package/dist/force-app/main/default/uiBundles/reactinternalapp/scripts/get-graphql-schema.mjs +68 -0
- package/dist/force-app/main/default/uiBundles/reactinternalapp/scripts/rewrite-e2e-assets.mjs +23 -0
- package/dist/force-app/main/default/uiBundles/reactinternalapp/src/api/account/accountSearchService.ts +46 -0
- package/dist/force-app/main/default/uiBundles/reactinternalapp/src/api/account/query/distinctAccountIndustries.graphql +19 -0
- package/dist/force-app/main/default/uiBundles/reactinternalapp/src/api/account/query/distinctAccountTypes.graphql +19 -0
- package/dist/force-app/main/default/uiBundles/reactinternalapp/src/api/account/query/getAccountDetail.graphql +121 -0
- package/dist/force-app/main/default/uiBundles/reactinternalapp/src/api/account/query/searchAccounts.graphql +51 -0
- package/dist/force-app/main/default/uiBundles/reactinternalapp/src/api/graphql-operations-types.ts +11260 -0
- package/dist/force-app/main/default/uiBundles/reactinternalapp/src/api/graphqlClient.ts +25 -0
- package/dist/force-app/main/default/uiBundles/reactinternalapp/src/app.tsx +17 -0
- package/dist/force-app/main/default/uiBundles/reactinternalapp/src/appLayout.tsx +85 -0
- package/dist/force-app/main/default/uiBundles/reactinternalapp/src/assets/icons/book.svg +3 -0
- package/dist/force-app/main/default/uiBundles/reactinternalapp/src/assets/icons/copy.svg +4 -0
- package/dist/force-app/main/default/uiBundles/reactinternalapp/src/assets/icons/rocket.svg +3 -0
- package/dist/force-app/main/default/uiBundles/reactinternalapp/src/assets/icons/star.svg +3 -0
- package/dist/force-app/main/default/uiBundles/reactinternalapp/src/assets/images/codey-1.png +0 -0
- package/dist/force-app/main/default/uiBundles/reactinternalapp/src/assets/images/codey-2.png +0 -0
- package/dist/force-app/main/default/uiBundles/reactinternalapp/src/assets/images/codey-3.png +0 -0
- package/dist/force-app/main/default/uiBundles/reactinternalapp/src/assets/images/vibe-codey.svg +194 -0
- package/dist/force-app/main/default/uiBundles/reactinternalapp/src/components/AgentforceConversationClient.tsx +168 -0
- package/dist/force-app/main/default/uiBundles/reactinternalapp/src/components/__inherit_AgentforceConversationClient.tsx +3 -0
- package/dist/force-app/main/default/uiBundles/reactinternalapp/src/components/alerts/status-alert.tsx +49 -0
- package/dist/force-app/main/default/uiBundles/reactinternalapp/src/components/layouts/card-layout.tsx +29 -0
- package/dist/force-app/main/default/uiBundles/reactinternalapp/src/components/ui/alert.tsx +76 -0
- package/dist/force-app/main/default/uiBundles/reactinternalapp/src/components/ui/badge.tsx +48 -0
- package/dist/force-app/main/default/uiBundles/reactinternalapp/src/components/ui/breadcrumb.tsx +109 -0
- package/dist/force-app/main/default/uiBundles/reactinternalapp/src/components/ui/button.tsx +67 -0
- package/dist/force-app/main/default/uiBundles/reactinternalapp/src/components/ui/calendar.tsx +232 -0
- package/dist/force-app/main/default/uiBundles/reactinternalapp/src/components/ui/card.tsx +103 -0
- package/dist/force-app/main/default/uiBundles/reactinternalapp/src/components/ui/checkbox.tsx +32 -0
- package/dist/force-app/main/default/uiBundles/reactinternalapp/src/components/ui/collapsible.tsx +33 -0
- package/dist/force-app/main/default/uiBundles/reactinternalapp/src/components/ui/datePicker.tsx +127 -0
- package/dist/force-app/main/default/uiBundles/reactinternalapp/src/components/ui/dialog.tsx +162 -0
- package/dist/force-app/main/default/uiBundles/reactinternalapp/src/components/ui/field.tsx +237 -0
- package/dist/force-app/main/default/uiBundles/reactinternalapp/src/components/ui/index.ts +84 -0
- package/dist/force-app/main/default/uiBundles/reactinternalapp/src/components/ui/input.tsx +19 -0
- package/dist/force-app/main/default/uiBundles/reactinternalapp/src/components/ui/label.tsx +22 -0
- package/dist/force-app/main/default/uiBundles/reactinternalapp/src/components/ui/pagination.tsx +132 -0
- package/dist/force-app/main/default/uiBundles/reactinternalapp/src/components/ui/popover.tsx +89 -0
- package/dist/force-app/main/default/uiBundles/reactinternalapp/src/components/ui/select.tsx +193 -0
- package/dist/force-app/main/default/uiBundles/reactinternalapp/src/components/ui/separator.tsx +26 -0
- package/dist/force-app/main/default/uiBundles/reactinternalapp/src/components/ui/skeleton.tsx +14 -0
- package/dist/force-app/main/default/uiBundles/reactinternalapp/src/components/ui/sonner.tsx +20 -0
- package/dist/force-app/main/default/uiBundles/reactinternalapp/src/components/ui/spinner.tsx +16 -0
- package/dist/force-app/main/default/uiBundles/reactinternalapp/src/components/ui/table.tsx +114 -0
- package/dist/force-app/main/default/uiBundles/reactinternalapp/src/components/ui/tabs.tsx +88 -0
- package/dist/force-app/main/default/uiBundles/reactinternalapp/src/features/object-search/__examples__/api/accountSearchService.ts +46 -0
- package/dist/force-app/main/default/uiBundles/reactinternalapp/src/features/object-search/__examples__/api/query/distinctAccountIndustries.graphql +19 -0
- package/dist/force-app/main/default/uiBundles/reactinternalapp/src/features/object-search/__examples__/api/query/distinctAccountTypes.graphql +19 -0
- package/dist/force-app/main/default/uiBundles/reactinternalapp/src/features/object-search/__examples__/api/query/getAccountDetail.graphql +121 -0
- package/dist/force-app/main/default/uiBundles/reactinternalapp/src/features/object-search/__examples__/api/query/searchAccounts.graphql +51 -0
- package/dist/force-app/main/default/uiBundles/reactinternalapp/src/features/object-search/__examples__/pages/AccountObjectDetailPage.tsx +357 -0
- package/dist/force-app/main/default/uiBundles/reactinternalapp/src/features/object-search/__examples__/pages/AccountSearch.tsx +312 -0
- package/dist/force-app/main/default/uiBundles/reactinternalapp/src/features/object-search/__examples__/pages/Home.tsx +34 -0
- package/dist/force-app/main/default/uiBundles/reactinternalapp/src/features/object-search/api/objectSearchService.ts +84 -0
- package/dist/force-app/main/default/uiBundles/reactinternalapp/src/features/object-search/components/ActiveFilters.tsx +89 -0
- package/dist/force-app/main/default/uiBundles/reactinternalapp/src/features/object-search/components/FilterContext.tsx +83 -0
- package/dist/force-app/main/default/uiBundles/reactinternalapp/src/features/object-search/components/ObjectBreadcrumb.tsx +66 -0
- package/dist/force-app/main/default/uiBundles/reactinternalapp/src/features/object-search/components/PaginationControls.tsx +109 -0
- package/dist/force-app/main/default/uiBundles/reactinternalapp/src/features/object-search/components/SearchBar.tsx +41 -0
- package/dist/force-app/main/default/uiBundles/reactinternalapp/src/features/object-search/components/SortControl.tsx +143 -0
- package/dist/force-app/main/default/uiBundles/reactinternalapp/src/features/object-search/components/filters/BooleanFilter.tsx +78 -0
- package/dist/force-app/main/default/uiBundles/reactinternalapp/src/features/object-search/components/filters/DateFilter.tsx +128 -0
- package/dist/force-app/main/default/uiBundles/reactinternalapp/src/features/object-search/components/filters/DateRangeFilter.tsx +70 -0
- package/dist/force-app/main/default/uiBundles/reactinternalapp/src/features/object-search/components/filters/FilterFieldWrapper.tsx +33 -0
- package/dist/force-app/main/default/uiBundles/reactinternalapp/src/features/object-search/components/filters/MultiSelectFilter.tsx +97 -0
- package/dist/force-app/main/default/uiBundles/reactinternalapp/src/features/object-search/components/filters/NumericRangeFilter.tsx +163 -0
- package/dist/force-app/main/default/uiBundles/reactinternalapp/src/features/object-search/components/filters/SearchFilter.tsx +50 -0
- package/dist/force-app/main/default/uiBundles/reactinternalapp/src/features/object-search/components/filters/SelectFilter.tsx +97 -0
- package/dist/force-app/main/default/uiBundles/reactinternalapp/src/features/object-search/components/filters/TextFilter.tsx +91 -0
- package/dist/force-app/main/default/uiBundles/reactinternalapp/src/features/object-search/hooks/useAsyncData.ts +54 -0
- package/dist/force-app/main/default/uiBundles/reactinternalapp/src/features/object-search/hooks/useCachedAsyncData.ts +184 -0
- package/dist/force-app/main/default/uiBundles/reactinternalapp/src/features/object-search/hooks/useDebouncedCallback.ts +34 -0
- package/dist/force-app/main/default/uiBundles/reactinternalapp/src/features/object-search/hooks/useObjectSearchParams.ts +252 -0
- package/dist/force-app/main/default/uiBundles/reactinternalapp/src/features/object-search/utils/debounce.ts +25 -0
- package/dist/force-app/main/default/uiBundles/reactinternalapp/src/features/object-search/utils/fieldUtils.ts +29 -0
- package/dist/force-app/main/default/uiBundles/reactinternalapp/src/features/object-search/utils/filterUtils.ts +395 -0
- package/dist/force-app/main/default/uiBundles/reactinternalapp/src/features/object-search/utils/sortUtils.ts +38 -0
- package/dist/force-app/main/default/uiBundles/reactinternalapp/src/index.ts +6 -0
- package/dist/force-app/main/default/uiBundles/reactinternalapp/src/lib/utils.ts +6 -0
- package/dist/force-app/main/default/uiBundles/reactinternalapp/src/navigationMenu.tsx +80 -0
- package/dist/force-app/main/default/uiBundles/reactinternalapp/src/pages/AccountObjectDetailPage.tsx +361 -0
- package/dist/force-app/main/default/uiBundles/reactinternalapp/src/pages/AccountSearch.tsx +305 -0
- package/dist/force-app/main/default/uiBundles/reactinternalapp/src/pages/Home.tsx +34 -0
- package/dist/force-app/main/default/uiBundles/reactinternalapp/src/pages/NotFound.tsx +18 -0
- package/dist/force-app/main/default/uiBundles/reactinternalapp/src/router-utils.tsx +35 -0
- package/dist/force-app/main/default/uiBundles/reactinternalapp/src/routes.tsx +32 -0
- package/dist/force-app/main/default/uiBundles/reactinternalapp/src/styles/global.css +135 -0
- package/dist/force-app/main/default/uiBundles/reactinternalapp/src/types/conversation.ts +33 -0
- package/dist/force-app/main/default/uiBundles/reactinternalapp/tsconfig.json +42 -0
- package/dist/force-app/main/default/uiBundles/reactinternalapp/tsconfig.node.json +13 -0
- package/dist/force-app/main/default/uiBundles/reactinternalapp/ui-bundle.json +7 -0
- package/dist/force-app/main/default/uiBundles/reactinternalapp/vite-env.d.ts +1 -0
- package/dist/force-app/main/default/uiBundles/reactinternalapp/vite.config.ts +106 -0
- package/dist/force-app/main/default/uiBundles/reactinternalapp/vitest-env.d.ts +2 -0
- package/dist/force-app/main/default/uiBundles/reactinternalapp/vitest.config.ts +11 -0
- package/dist/force-app/main/default/uiBundles/reactinternalapp/vitest.setup.ts +1 -0
- package/dist/jest.config.js +6 -0
- package/dist/package-lock.json +9995 -0
- package/dist/package.json +40 -0
- package/dist/scripts/apex/hello.apex +10 -0
- package/dist/scripts/graphql-search.sh +191 -0
- package/dist/scripts/prepare-import-unique-fields.js +122 -0
- package/dist/scripts/setup-cli.mjs +563 -0
- package/dist/scripts/sf-project-setup.mjs +66 -0
- package/dist/scripts/soql/account.soql +6 -0
- package/dist/sfdx-project.json +12 -0
- package/package.json +40 -0
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@salesforce/ui-bundle-template-base-sfdx-project",
|
|
3
|
+
"version": "1.117.2",
|
|
4
|
+
"description": "Base SFDX project template",
|
|
5
|
+
"license": "SEE LICENSE IN LICENSE.txt",
|
|
6
|
+
"publishConfig": {
|
|
7
|
+
"access": "public"
|
|
8
|
+
},
|
|
9
|
+
"scripts": {
|
|
10
|
+
"sf-project-setup": "node scripts/sf-project-setup.mjs",
|
|
11
|
+
"build": "echo 'No build required for base-sfdx-project'",
|
|
12
|
+
"clean": "echo 'No clean required for base-sfdx-project'",
|
|
13
|
+
"lint": "eslint --no-error-on-unmatched-pattern **/{aura,lwc}/**/*.js",
|
|
14
|
+
"test": "npm run test:unit",
|
|
15
|
+
"test:coverage": "npm run test",
|
|
16
|
+
"test:unit": "sfdx-lwc-jest -- --passWithNoTests",
|
|
17
|
+
"test:unit:watch": "sfdx-lwc-jest --watch",
|
|
18
|
+
"test:unit:debug": "sfdx-lwc-jest --debug",
|
|
19
|
+
"test:unit:coverage": "sfdx-lwc-jest --coverage",
|
|
20
|
+
"prettier": "prettier --write \"**/*.{cls,cmp,component,css,html,js,json,md,page,trigger,xml,yaml,yml}\"",
|
|
21
|
+
"prettier:verify": "prettier --check \"**/*.{cls,cmp,component,css,html,js,json,md,page,trigger,xml,yaml,yml}\"",
|
|
22
|
+
"precommit": "lint-staged",
|
|
23
|
+
"setup": "node scripts/setup-cli.mjs"
|
|
24
|
+
},
|
|
25
|
+
"devDependencies": {
|
|
26
|
+
"@lwc/eslint-plugin-lwc": "^3.3.0",
|
|
27
|
+
"@prettier/plugin-xml": "^3.2.2",
|
|
28
|
+
"@salesforce/eslint-config-lwc": "^4.1.0",
|
|
29
|
+
"@salesforce/eslint-plugin-aura": "^3.0.0",
|
|
30
|
+
"@salesforce/eslint-plugin-lightning": "^2.0.0",
|
|
31
|
+
"@salesforce/sfdx-lwc-jest": "^7.0.1",
|
|
32
|
+
"eslint": "^9.39.0",
|
|
33
|
+
"eslint-plugin-import": "^2.25.4",
|
|
34
|
+
"eslint-plugin-jest": "^28.8.1",
|
|
35
|
+
"husky": "^9.1.5",
|
|
36
|
+
"lint-staged": "^15.1.0",
|
|
37
|
+
"prettier": "^3.1.0",
|
|
38
|
+
"prettier-plugin-apex": "^2.0.1"
|
|
39
|
+
}
|
|
40
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
// Use .apex files to store anonymous Apex.
|
|
2
|
+
// You can execute anonymous Apex in VS Code by selecting the
|
|
3
|
+
// apex text and running the command:
|
|
4
|
+
// SFDX: Execute Anonymous Apex with Currently Selected Text
|
|
5
|
+
// You can also execute the entire file by running the command:
|
|
6
|
+
// SFDX: Execute Anonymous Apex with Editor Contents
|
|
7
|
+
|
|
8
|
+
string tempvar = 'Enter_your_name_here';
|
|
9
|
+
System.debug('Hello World!');
|
|
10
|
+
System.debug('My name is ' + tempvar);
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -euo pipefail # exit on error (-e), undefined vars (-u), and propagate pipeline failures (-o pipefail)
|
|
3
|
+
# graphql-search.sh — Look up one or more Salesforce entities in schema.graphql.
|
|
4
|
+
#
|
|
5
|
+
# Run from the SFDX project root (where schema.graphql lives):
|
|
6
|
+
# bash scripts/graphql-search.sh Account
|
|
7
|
+
# bash scripts/graphql-search.sh Account Contact Opportunity
|
|
8
|
+
#
|
|
9
|
+
# Pass a custom schema path with -s / --schema:
|
|
10
|
+
# bash scripts/graphql-search.sh -s /path/to/schema.graphql Account
|
|
11
|
+
# bash scripts/graphql-search.sh --schema ./other/schema.graphql Account Contact
|
|
12
|
+
#
|
|
13
|
+
# Output sections per entity:
|
|
14
|
+
# 1. Type definition — all fields and relationships
|
|
15
|
+
# 2. Filter options — <Entity>_Filter input (for `where:`)
|
|
16
|
+
# 3. Sort options — <Entity>_OrderBy input (for `orderBy:`)
|
|
17
|
+
# 4. Create mutation wrapper — <Entity>CreateInput
|
|
18
|
+
# 5. Create mutation fields — <Entity>CreateRepresentation (for create mutations)
|
|
19
|
+
# 6. Update mutation wrapper — <Entity>UpdateInput
|
|
20
|
+
# 7. Update mutation fields — <Entity>UpdateRepresentation (for update mutations)
|
|
21
|
+
|
|
22
|
+
SCHEMA="./schema.graphql"
|
|
23
|
+
|
|
24
|
+
# ── Argument parsing ─────────────────────────────────────────────────────────
|
|
25
|
+
|
|
26
|
+
while [[ $# -gt 0 ]]; do
|
|
27
|
+
case "$1" in
|
|
28
|
+
-s|--schema)
|
|
29
|
+
if [[ -z "${2-}" || "$2" == -* ]]; then
|
|
30
|
+
echo "ERROR: --schema requires a file path argument"
|
|
31
|
+
exit 1
|
|
32
|
+
fi
|
|
33
|
+
SCHEMA="$2"
|
|
34
|
+
shift 2
|
|
35
|
+
;;
|
|
36
|
+
--)
|
|
37
|
+
shift
|
|
38
|
+
break
|
|
39
|
+
;;
|
|
40
|
+
-*)
|
|
41
|
+
echo "ERROR: Unknown option: $1"
|
|
42
|
+
echo "Usage: bash $0 [-s <schema-path>] <EntityName> [EntityName2 ...]"
|
|
43
|
+
exit 1
|
|
44
|
+
;;
|
|
45
|
+
*)
|
|
46
|
+
break
|
|
47
|
+
;;
|
|
48
|
+
esac
|
|
49
|
+
done
|
|
50
|
+
|
|
51
|
+
if [ $# -eq 0 ]; then
|
|
52
|
+
echo "Usage: bash $0 [-s <schema-path>] <EntityName> [EntityName2 ...]"
|
|
53
|
+
echo "Example: bash $0 Account"
|
|
54
|
+
echo "Example: bash $0 Account Contact Opportunity"
|
|
55
|
+
echo "Example: bash $0 --schema /path/to/schema.graphql Account"
|
|
56
|
+
exit 1
|
|
57
|
+
fi
|
|
58
|
+
|
|
59
|
+
if [ ! -f "$SCHEMA" ]; then
|
|
60
|
+
echo "ERROR: schema.graphql not found at $SCHEMA"
|
|
61
|
+
echo " Make sure you are running from the SFDX project root, or pass the path explicitly:"
|
|
62
|
+
echo " bash $0 --schema <path/to/schema.graphql> <EntityName>"
|
|
63
|
+
echo " If the file is missing entirely, generate it from the webapp dir:"
|
|
64
|
+
echo " cd force-app/main/default/webapplications/<app-name> && npm run graphql:schema"
|
|
65
|
+
exit 1
|
|
66
|
+
fi
|
|
67
|
+
|
|
68
|
+
if [ ! -r "$SCHEMA" ]; then
|
|
69
|
+
echo "ERROR: schema.graphql is not readable at $SCHEMA"
|
|
70
|
+
echo " Check file permissions: ls -la $SCHEMA"
|
|
71
|
+
exit 1
|
|
72
|
+
fi
|
|
73
|
+
|
|
74
|
+
if [ ! -s "$SCHEMA" ]; then
|
|
75
|
+
echo "ERROR: schema.graphql is empty at $SCHEMA"
|
|
76
|
+
echo " Regenerate it from the webapp dir:"
|
|
77
|
+
echo " cd force-app/main/default/webapplications/<app-name> && npm run graphql:schema"
|
|
78
|
+
exit 1
|
|
79
|
+
fi
|
|
80
|
+
|
|
81
|
+
# ── Helper: extract lines from a grep match through the closing brace ────────
|
|
82
|
+
# Prints up to MAX_LINES lines after (and including) the first match of PATTERN.
|
|
83
|
+
# Uses a generous line count — blocks are always closed by a "}" line.
|
|
84
|
+
|
|
85
|
+
extract_block() {
|
|
86
|
+
local label="$1"
|
|
87
|
+
local pattern="$2"
|
|
88
|
+
local max_lines="$3"
|
|
89
|
+
|
|
90
|
+
local match
|
|
91
|
+
local grep_exit=0
|
|
92
|
+
match=$(grep -nE "$pattern" "$SCHEMA" | head -1) || grep_exit=$?
|
|
93
|
+
|
|
94
|
+
if [ "$grep_exit" -eq 2 ]; then
|
|
95
|
+
echo " ERROR: grep failed on pattern: $pattern" >&2
|
|
96
|
+
return 1
|
|
97
|
+
fi
|
|
98
|
+
|
|
99
|
+
if [ -z "$match" ]; then
|
|
100
|
+
echo " (not found: $pattern)"
|
|
101
|
+
return 3
|
|
102
|
+
fi
|
|
103
|
+
|
|
104
|
+
echo "### $label"
|
|
105
|
+
grep -E "$pattern" "$SCHEMA" -A "$max_lines" | \
|
|
106
|
+
awk '/^\}$/{print; exit} {print}' | \
|
|
107
|
+
head -n "$max_lines" || true
|
|
108
|
+
echo ""
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
# ── Main loop ────────────────────────────────────────────────────────────────
|
|
112
|
+
|
|
113
|
+
for ENTITY in "$@"; do
|
|
114
|
+
# Validate entity name: must be a valid PascalCase identifier (letters, digits, underscores)
|
|
115
|
+
if [[ ! "$ENTITY" =~ ^[A-Za-z_][A-Za-z0-9_]*$ ]]; then
|
|
116
|
+
echo "ERROR: Invalid entity name: '$ENTITY'"
|
|
117
|
+
echo " Entity names must start with a letter or underscore, followed by letters, digits, or underscores."
|
|
118
|
+
echo " Examples: Account, My_Custom_Object__c"
|
|
119
|
+
continue
|
|
120
|
+
fi
|
|
121
|
+
|
|
122
|
+
echo ""
|
|
123
|
+
echo "======================================================================"
|
|
124
|
+
echo " SCHEMA LOOKUP: $ENTITY"
|
|
125
|
+
echo "======================================================================"
|
|
126
|
+
echo ""
|
|
127
|
+
|
|
128
|
+
found=0
|
|
129
|
+
|
|
130
|
+
# Helper: call extract_block, track matches, surface errors
|
|
131
|
+
try_extract() {
|
|
132
|
+
local rc=0
|
|
133
|
+
extract_block "$@" || rc=$?
|
|
134
|
+
if [ "$rc" -eq 0 ]; then
|
|
135
|
+
found=$((found + 1))
|
|
136
|
+
elif [ "$rc" -eq 1 ]; then
|
|
137
|
+
echo " Aborting lookup for '$ENTITY' due to grep error" >&2
|
|
138
|
+
fi
|
|
139
|
+
# rc=3 is not-found — continue silently (already printed by extract_block)
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
# 1. Type definition — all fields and relationships
|
|
143
|
+
try_extract \
|
|
144
|
+
"Type definition — fields and relationships" \
|
|
145
|
+
"^type ${ENTITY} implements Record" \
|
|
146
|
+
200
|
|
147
|
+
|
|
148
|
+
# 2. Filter input — used in `where:` arguments
|
|
149
|
+
try_extract \
|
|
150
|
+
"Filter options — use in where: { ... }" \
|
|
151
|
+
"^input ${ENTITY}_Filter" \
|
|
152
|
+
100
|
|
153
|
+
|
|
154
|
+
# 3. OrderBy input — used in `orderBy:` arguments
|
|
155
|
+
try_extract \
|
|
156
|
+
"Sort options — use in orderBy: { ... }" \
|
|
157
|
+
"^input ${ENTITY}_OrderBy" \
|
|
158
|
+
60
|
|
159
|
+
|
|
160
|
+
# 4. Create mutation wrapper
|
|
161
|
+
try_extract \
|
|
162
|
+
"Create mutation wrapper — ${ENTITY}CreateInput" \
|
|
163
|
+
"^input ${ENTITY}CreateInput" \
|
|
164
|
+
10
|
|
165
|
+
|
|
166
|
+
# 5. Create mutation fields
|
|
167
|
+
try_extract \
|
|
168
|
+
"Create mutation fields — ${ENTITY}CreateRepresentation" \
|
|
169
|
+
"^input ${ENTITY}CreateRepresentation" \
|
|
170
|
+
100
|
|
171
|
+
|
|
172
|
+
# 6. Update mutation wrapper
|
|
173
|
+
try_extract \
|
|
174
|
+
"Update mutation wrapper — ${ENTITY}UpdateInput" \
|
|
175
|
+
"^input ${ENTITY}UpdateInput" \
|
|
176
|
+
10
|
|
177
|
+
|
|
178
|
+
# 7. Update mutation fields
|
|
179
|
+
try_extract \
|
|
180
|
+
"Update mutation fields — ${ENTITY}UpdateRepresentation" \
|
|
181
|
+
"^input ${ENTITY}UpdateRepresentation" \
|
|
182
|
+
100
|
|
183
|
+
|
|
184
|
+
if [ "$found" -eq 0 ]; then
|
|
185
|
+
echo "WARNING: No schema entries found for '$ENTITY'."
|
|
186
|
+
echo " - Names are PascalCase (e.g., 'Account' not 'account')"
|
|
187
|
+
echo " - Custom objects may need deployment first"
|
|
188
|
+
fi
|
|
189
|
+
|
|
190
|
+
echo ""
|
|
191
|
+
done
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Updates unique fields in data JSON files so "sf data import tree" can be run
|
|
4
|
+
* repeatedly (e.g. after org already has data). Run before data import.
|
|
5
|
+
*
|
|
6
|
+
* Usage:
|
|
7
|
+
* node scripts/prepare-import-unique-fields.js
|
|
8
|
+
* node scripts/prepare-import-unique-fields.js --data-dir /path/to/<sfdx-source>/data
|
|
9
|
+
*
|
|
10
|
+
* Expects data dir to contain (optional) JSON files:
|
|
11
|
+
* Contact.json (Email with unique domain per run, LastName, FirstName, Phone — standard Contact)
|
|
12
|
+
* Agent__c.json (License_Number__c — unique per record)
|
|
13
|
+
* Property_Management_Company__c.json (Company_Code__c, max 10 chars)
|
|
14
|
+
* Property_Owner__c.json (Email__c)
|
|
15
|
+
* Missing files are skipped. Customize this script for your app's objects/fields.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
const fs = require('fs');
|
|
19
|
+
const path = require('path');
|
|
20
|
+
|
|
21
|
+
function resolveSfdxSource() {
|
|
22
|
+
const sfdxPath = path.resolve(__dirname, '..', 'sfdx-project.json');
|
|
23
|
+
if (!fs.existsSync(sfdxPath)) {
|
|
24
|
+
console.error('Error: sfdx-project.json not found at project root.');
|
|
25
|
+
process.exit(1);
|
|
26
|
+
}
|
|
27
|
+
const sfdxProject = JSON.parse(fs.readFileSync(sfdxPath, 'utf8'));
|
|
28
|
+
const pkgDir = sfdxProject?.packageDirectories?.[0]?.path;
|
|
29
|
+
if (!pkgDir) {
|
|
30
|
+
console.error('Error: No packageDirectories[].path found in sfdx-project.json.');
|
|
31
|
+
process.exit(1);
|
|
32
|
+
}
|
|
33
|
+
return path.resolve(__dirname, '..', pkgDir, 'main', 'default');
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const DEFAULT_DATA_DIR = path.resolve(resolveSfdxSource(), 'data');
|
|
37
|
+
|
|
38
|
+
function parseArgs() {
|
|
39
|
+
const args = process.argv.slice(2);
|
|
40
|
+
let dataDir = DEFAULT_DATA_DIR;
|
|
41
|
+
for (let i = 0; i < args.length; i++) {
|
|
42
|
+
if (args[i] === '--data-dir' && args[i + 1]) {
|
|
43
|
+
dataDir = path.resolve(args[++i]);
|
|
44
|
+
break;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
return dataDir;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const dataDir = parseArgs();
|
|
51
|
+
const runId = Date.now();
|
|
52
|
+
const runSuffix2 = String(runId % 100).padStart(2, '0'); // 00-99 for Company_Code__c (10-char limit)
|
|
53
|
+
|
|
54
|
+
// Contact: Email (unique domain + local), LastName, FirstName, Phone — avoid duplicate rules
|
|
55
|
+
const contactPath = path.join(dataDir, 'Contact.json');
|
|
56
|
+
if (fs.existsSync(contactPath)) {
|
|
57
|
+
let contact = JSON.parse(fs.readFileSync(contactPath, 'utf8'));
|
|
58
|
+
if (contact.records) {
|
|
59
|
+
contact.records.forEach((r, i) => {
|
|
60
|
+
if (r.Email && r.Email.includes('@')) {
|
|
61
|
+
const parts = r.Email.replace(/\+[0-9]+@/, '@').split('@');
|
|
62
|
+
const local = (parts[0] || 'user') + '+' + runId;
|
|
63
|
+
const domain = 'run' + runId + '.example.com';
|
|
64
|
+
r.Email = local + '@' + domain;
|
|
65
|
+
}
|
|
66
|
+
if (r.LastName)
|
|
67
|
+
r.LastName = String(r.LastName).replace(/-[0-9]+$/, '') + '-' + runId;
|
|
68
|
+
if (r.FirstName)
|
|
69
|
+
r.FirstName = String(r.FirstName).replace(/-[0-9]+$/, '') + '-' + (i + 1);
|
|
70
|
+
if (r.Phone)
|
|
71
|
+
r.Phone = String(r.Phone).replace(/\d{2}$/, runSuffix2);
|
|
72
|
+
});
|
|
73
|
+
fs.writeFileSync(contactPath, JSON.stringify(contact, null, 2));
|
|
74
|
+
console.log('Updated Contact.json (Email, LastName, FirstName, Phone)');
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// Agent__c: License_Number__c — unique per record (field is often unique in org)
|
|
79
|
+
const agentPath = path.join(dataDir, 'Agent__c.json');
|
|
80
|
+
if (fs.existsSync(agentPath)) {
|
|
81
|
+
let agent = JSON.parse(fs.readFileSync(agentPath, 'utf8'));
|
|
82
|
+
if (agent.records) {
|
|
83
|
+
agent.records.forEach((r, i) => {
|
|
84
|
+
if (r.License_Number__c) {
|
|
85
|
+
const base = r.License_Number__c.replace(/-[0-9]+(-[0-9]+)?$/, '');
|
|
86
|
+
r.License_Number__c = base + '-' + runId + '-' + (i + 1);
|
|
87
|
+
}
|
|
88
|
+
});
|
|
89
|
+
fs.writeFileSync(agentPath, JSON.stringify(agent, null, 2));
|
|
90
|
+
console.log('Updated Agent__c.json (License_Number__c)');
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// Property_Management_Company__c: Company_Code__c — max 10 chars, use 8-char base + 2-digit suffix
|
|
95
|
+
const companyPath = path.join(dataDir, 'Property_Management_Company__c.json');
|
|
96
|
+
if (fs.existsSync(companyPath)) {
|
|
97
|
+
let company = JSON.parse(fs.readFileSync(companyPath, 'utf8'));
|
|
98
|
+
if (company.records) {
|
|
99
|
+
company.records.forEach((r) => {
|
|
100
|
+
if (r.Company_Code__c)
|
|
101
|
+
r.Company_Code__c = r.Company_Code__c.slice(0, 8) + runSuffix2;
|
|
102
|
+
});
|
|
103
|
+
fs.writeFileSync(companyPath, JSON.stringify(company, null, 2));
|
|
104
|
+
console.log('Updated Property_Management_Company__c.json (Company_Code__c)');
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// Property_Owner__c: Email__c — add +runId before @
|
|
109
|
+
const ownerPath = path.join(dataDir, 'Property_Owner__c.json');
|
|
110
|
+
if (fs.existsSync(ownerPath)) {
|
|
111
|
+
let owner = JSON.parse(fs.readFileSync(ownerPath, 'utf8'));
|
|
112
|
+
if (owner.records) {
|
|
113
|
+
owner.records.forEach((r) => {
|
|
114
|
+
if (r.Email__c && r.Email__c.includes('@'))
|
|
115
|
+
r.Email__c = r.Email__c.replace(/\+[0-9]+@/, '@').replace('@', '+' + runId + '@');
|
|
116
|
+
});
|
|
117
|
+
fs.writeFileSync(ownerPath, JSON.stringify(owner, null, 2));
|
|
118
|
+
console.log('Updated Property_Owner__c.json (Email__c)');
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
console.log('Unique fields updated: runId=%s companySuffix=%s', runId, runSuffix2);
|