@salesforce/templates 66.13.5 → 66.13.7
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/lib/templates/project/angularextapp/CHANGELOG.md +258 -0
- package/lib/templates/project/angularextapp/_p_/_m_/_w_/_a_/angular.json +1 -1
- package/lib/templates/project/angularextapp/_p_/_m_/_w_/_a_/eslint-plugin-angular-graphql.js +148 -0
- package/lib/templates/project/angularextapp/_p_/_m_/_w_/_a_/eslint.config.js +9 -1
- package/lib/templates/project/angularextapp/_p_/_m_/_w_/_a_/package-lock.json +680 -408
- package/lib/templates/project/angularextapp/_p_/_m_/_w_/_a_/package.json +2 -2
- package/lib/templates/project/angularextapp/package.json +1 -1
- package/lib/templates/project/angularextapp/scripts/org-setup-config-schema.mjs +17 -0
- package/lib/templates/project/angularextapp/scripts/org-setup-utils.mjs +33 -3
- package/lib/templates/project/angularextapp/scripts/org-setup.mjs +535 -3
- package/lib/templates/project/angularintapp/CHANGELOG.md +266 -0
- package/lib/templates/project/angularintapp/_p_/_m_/_w_/_a_/angular.json +1 -1
- package/lib/templates/project/angularintapp/_p_/_m_/_w_/_a_/eslint-plugin-angular-graphql.js +148 -0
- package/lib/templates/project/angularintapp/_p_/_m_/_w_/_a_/eslint.config.js +9 -1
- package/lib/templates/project/angularintapp/_p_/_m_/_w_/_a_/package-lock.json +690 -418
- package/lib/templates/project/angularintapp/_p_/_m_/_w_/_a_/package.json +2 -2
- package/lib/templates/project/angularintapp/_p_/_m_/_w_/_a_/src/app/features/agentforce/agentforce-embed.service.ts +6 -1
- package/lib/templates/project/angularintapp/package.json +1 -1
- package/lib/templates/project/angularintapp/scripts/org-setup-config-schema.mjs +17 -0
- package/lib/templates/project/angularintapp/scripts/org-setup-utils.mjs +33 -3
- package/lib/templates/project/angularintapp/scripts/org-setup.mjs +535 -3
- package/lib/templates/project/reactexternalapp/CHANGELOG.md +1409 -0
- package/lib/templates/project/reactexternalapp/PRD.md +38 -0
- package/lib/templates/project/reactexternalapp/README.md +14 -10
- package/lib/templates/project/reactexternalapp/_p_/_m_/_ps_/reactexternalapp_Guest_User_Api_Access.permissionset-meta.xml +25 -0
- package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/package-lock.json +953 -714
- package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/package.json +9 -7
- package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/scripts/get-graphql-schema.mjs +8 -5
- package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/_ls_/LanguageSwitcher.tsx +116 -0
- package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/_ls_/__examples__/language-switcher-example.tsx +36 -0
- package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/_ls_/__examples__/vite-config-site-example.ts +44 -0
- package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/_ls_/buildLanguageUrl.ts +158 -0
- package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/_ls_/index.ts +28 -0
- package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/_ls_/languages.ts +46 -0
- package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/authentication/components/SocialLogin.tsx +141 -0
- package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/authentication/pages/Login.tsx +2 -0
- package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/search/README.md +246 -0
- package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/search/adapters/cms/api/apiUtils.ts +56 -0
- package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/search/adapters/cms/api/orgApiVersionService.ts +37 -0
- package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/search/adapters/cms/api/searchableContentTypesService.ts +116 -0
- package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/search/adapters/cms/channelResolver.ts +40 -0
- package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/search/adapters/cms/cmsQueryFragment.ts +97 -0
- package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/search/adapters/cms/contentTypeSessionCache.ts +134 -0
- package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/search/adapters/cms/contentTypeUtils.ts +38 -0
- package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/search/adapters/cms/hooks/useSearchableContentTypes.ts +128 -0
- package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/search/adapters/cms/index.ts +54 -0
- package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/search/adapters/cms/parseResponse.ts +65 -0
- package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/search/adapters/cms/searchChannel.ts +15 -0
- package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/search/adapters/cms/types.ts +66 -0
- package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/search/adapters/registry.ts +38 -0
- package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/search/adapters/sobject/index.ts +19 -0
- package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/search/adapters/sobject/parseResponse.ts +56 -0
- package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/search/adapters/sobject/queryFragment.ts +141 -0
- package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/search/adapters/types.ts +101 -0
- package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/search/api/distinctValuesService.ts +84 -0
- package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/search/api/searchService.ts +136 -0
- package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/search/components/GlobalSearchBox.tsx +98 -0
- package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/search/components/MergedSearchResults.tsx +294 -0
- package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/search/components/Search.tsx +203 -0
- package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/search/components/SearchResults.tsx +88 -0
- package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/search/components/SourceSection.tsx +187 -0
- package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/search/components/controls/PaginationControls.tsx +185 -0
- package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/search/components/controls/ScopeSelector.tsx +107 -0
- package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/search/components/controls/SearchBar.tsx +55 -0
- package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/search/components/controls/SortControl.tsx +62 -0
- package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/search/components/filters/ActiveFilters.tsx +61 -0
- package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/search/components/filters/DefaultFilterPanel.tsx +125 -0
- package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/{_os_/components → search/components/filters}/FilterContext.tsx +7 -20
- package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/search/components/filters/inputs/BooleanFilter.tsx +50 -0
- package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/search/components/filters/inputs/DateRangeFilter.tsx +160 -0
- package/lib/templates/project/{reactinternalapp/_p_/_m_/_w_/_a_/src/_f_/_os_/components/filters → reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/search/components/filters/inputs}/FilterFieldWrapper.tsx +11 -6
- package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/search/components/filters/inputs/MultiSelectFilter.tsx +89 -0
- package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/search/components/filters/inputs/NumericRangeFilter.tsx +108 -0
- package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/search/components/filters/inputs/SelectFilter.tsx +46 -0
- package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/search/components/filters/inputs/TextFilter.tsx +52 -0
- package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/search/components/results/CmsResultRow.tsx +101 -0
- package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/search/components/results/DefaultResultRow.tsx +109 -0
- package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/search/components/results/resolveResultRenderer.ts +49 -0
- package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/search/config.json +88 -0
- package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/search/constants.ts +8 -0
- package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/{_os_ → search}/hooks/useAsyncData.ts +3 -10
- package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/search/hooks/useDistinctValues.ts +59 -0
- package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/search/hooks/useSearch.ts +966 -0
- package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/search/index.ts +115 -0
- package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/search/loadConfig.ts +14 -0
- package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/search/queryBuilder.ts +100 -0
- package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/search/types.ts +376 -0
- package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/search/utils/debounce.ts +17 -0
- package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/search/utils/fieldUtils.ts +14 -0
- package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/search/utils/filterUtils.ts +285 -0
- package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/search/utils/sortUtils.ts +34 -0
- package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/api/graphqlClient.ts +24 -8
- package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/appLayout.tsx +7 -0
- package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/components/CustomerWebClientChat.tsx +74 -0
- package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/{_f_/_os_/components → components}/ObjectBreadcrumb.tsx +7 -2
- package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/components/ui/button.tsx +1 -1
- package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/components/ui/datePicker.tsx +2 -2
- package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/components/ui/table.tsx +9 -2
- package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/index.ts +8 -0
- package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/pages/AccountObjectDetailPage.tsx +53 -18
- package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/pages/Home.tsx +3 -27
- package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/pages/TestChatPage.tsx +26 -0
- package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/routes.tsx +21 -8
- package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/types/chat.ts +36 -0
- package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/types/globals.d.ts +23 -0
- package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/{_f_/_os_/utils/fieldUtils.ts → utils/accountFields.ts} +9 -0
- package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/tsconfig.json +2 -2
- package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/tsconfig.tsbuildinfo +1 -0
- package/lib/templates/project/reactexternalapp/_p_/_m_/classes/UIBundleSocialLoginConfig.cls +133 -0
- package/lib/templates/project/reactexternalapp/_p_/_m_/classes/UIBundleSocialLoginConfig.cls-meta.xml +5 -0
- package/lib/templates/project/reactexternalapp/_p_/_m_/classes/UIBundleSocialLoginConfig_Test.cls +101 -0
- package/lib/templates/project/reactexternalapp/_p_/_m_/classes/UIBundleSocialLoginConfig_Test.cls-meta.xml +5 -0
- package/lib/templates/project/reactexternalapp/_p_/_m_/package.xml +4 -0
- package/lib/templates/project/reactexternalapp/package.json +8 -2
- package/lib/templates/project/reactexternalapp/scripts/org-setup-config-schema.mjs +120 -0
- package/lib/templates/project/reactexternalapp/scripts/org-setup-dev.mjs +87 -0
- package/lib/templates/project/reactexternalapp/scripts/org-setup-utils.mjs +569 -0
- package/lib/templates/project/reactexternalapp/scripts/org-setup-xml.mjs +182 -0
- package/lib/templates/project/reactexternalapp/scripts/org-setup.config.json +6 -2
- package/lib/templates/project/reactexternalapp/scripts/org-setup.mjs +1509 -328
- package/lib/templates/project/reactexternalapp/scripts/validate-org-setup-config.mjs +38 -0
- package/lib/templates/project/reactinternalapp/CHANGELOG.md +1223 -0
- package/lib/templates/project/reactinternalapp/PRD.md +35 -0
- package/lib/templates/project/reactinternalapp/README.md +14 -10
- package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/package-lock.json +813 -538
- package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/package.json +10 -9
- package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/_f_/search/README.md +246 -0
- package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/_f_/search/adapters/cms/api/apiUtils.ts +56 -0
- package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/_f_/search/adapters/cms/api/orgApiVersionService.ts +37 -0
- package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/_f_/search/adapters/cms/api/searchableContentTypesService.ts +116 -0
- package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/_f_/search/adapters/cms/channelResolver.ts +40 -0
- package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/_f_/search/adapters/cms/cmsQueryFragment.ts +97 -0
- package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/_f_/search/adapters/cms/contentTypeSessionCache.ts +134 -0
- package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/_f_/search/adapters/cms/contentTypeUtils.ts +38 -0
- package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/_f_/search/adapters/cms/hooks/useSearchableContentTypes.ts +128 -0
- package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/_f_/search/adapters/cms/index.ts +54 -0
- package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/_f_/search/adapters/cms/parseResponse.ts +65 -0
- package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/_f_/search/adapters/cms/searchChannel.ts +15 -0
- package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/_f_/search/adapters/cms/types.ts +66 -0
- package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/_f_/search/adapters/registry.ts +38 -0
- package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/_f_/search/adapters/sobject/index.ts +19 -0
- package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/_f_/search/adapters/sobject/parseResponse.ts +56 -0
- package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/_f_/search/adapters/sobject/queryFragment.ts +141 -0
- package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/_f_/search/adapters/types.ts +101 -0
- package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/_f_/search/api/distinctValuesService.ts +84 -0
- package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/_f_/search/api/searchService.ts +136 -0
- package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/_f_/search/components/GlobalSearchBox.tsx +98 -0
- package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/_f_/search/components/MergedSearchResults.tsx +294 -0
- package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/_f_/search/components/Search.tsx +203 -0
- package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/_f_/search/components/SearchResults.tsx +88 -0
- package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/_f_/search/components/SourceSection.tsx +187 -0
- package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/_f_/search/components/controls/PaginationControls.tsx +185 -0
- package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/_f_/search/components/controls/ScopeSelector.tsx +107 -0
- package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/_f_/search/components/controls/SearchBar.tsx +55 -0
- package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/_f_/search/components/controls/SortControl.tsx +62 -0
- package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/_f_/search/components/filters/ActiveFilters.tsx +61 -0
- package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/_f_/search/components/filters/DefaultFilterPanel.tsx +125 -0
- package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/_f_/{_os_/components → search/components/filters}/FilterContext.tsx +7 -20
- package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/_f_/search/components/filters/inputs/BooleanFilter.tsx +50 -0
- package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/_f_/search/components/filters/inputs/DateRangeFilter.tsx +160 -0
- package/lib/templates/project/{reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/_os_/components/filters → reactinternalapp/_p_/_m_/_w_/_a_/src/_f_/search/components/filters/inputs}/FilterFieldWrapper.tsx +11 -6
- package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/_f_/search/components/filters/inputs/MultiSelectFilter.tsx +89 -0
- package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/_f_/search/components/filters/inputs/NumericRangeFilter.tsx +108 -0
- package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/_f_/search/components/filters/inputs/SelectFilter.tsx +46 -0
- package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/_f_/search/components/filters/inputs/TextFilter.tsx +52 -0
- package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/_f_/search/components/results/CmsResultRow.tsx +101 -0
- package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/_f_/search/components/results/DefaultResultRow.tsx +109 -0
- package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/_f_/search/components/results/resolveResultRenderer.ts +49 -0
- package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/_f_/search/config.json +88 -0
- package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/_f_/search/constants.ts +8 -0
- package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/_f_/{_os_ → search}/hooks/useAsyncData.ts +3 -10
- package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/_f_/search/hooks/useDistinctValues.ts +59 -0
- package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/_f_/search/hooks/useSearch.ts +966 -0
- package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/_f_/search/index.ts +115 -0
- package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/_f_/search/loadConfig.ts +14 -0
- package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/_f_/search/queryBuilder.ts +100 -0
- package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/_f_/search/types.ts +376 -0
- package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/_f_/search/utils/debounce.ts +17 -0
- package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/_f_/search/utils/fieldUtils.ts +14 -0
- package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/_f_/search/utils/filterUtils.ts +285 -0
- package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/_f_/search/utils/sortUtils.ts +34 -0
- package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/components/AgentforceConversationClient.tsx +16 -132
- package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/{_f_/_os_/components → components}/ObjectBreadcrumb.tsx +7 -2
- package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/components/ui/button.tsx +1 -1
- package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/components/ui/datePicker.tsx +2 -2
- package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/components/ui/table.tsx +9 -2
- package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/pages/AccountObjectDetailPage.tsx +49 -16
- package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/pages/Home.tsx +3 -27
- package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/routes.tsx +12 -5
- package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/{_f_/_os_/utils/fieldUtils.ts → utils/accountFields.ts} +9 -0
- package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/tsconfig.json +2 -2
- package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/tsconfig.tsbuildinfo +1 -0
- package/lib/templates/project/reactinternalapp/package.json +4 -2
- package/lib/templates/project/reactinternalapp/scripts/org-setup-config-schema.mjs +24 -0
- package/lib/templates/project/reactinternalapp/scripts/org-setup-dev.mjs +87 -0
- package/lib/templates/project/reactinternalapp/scripts/org-setup-utils.mjs +569 -0
- package/lib/templates/project/reactinternalapp/scripts/org-setup-xml.mjs +182 -0
- package/lib/templates/project/reactinternalapp/scripts/org-setup.mjs +1162 -214
- package/lib/templates/uiBundles/angularbasic/angular.json +1 -1
- package/lib/templates/uiBundles/angularbasic/eslint-plugin-angular-graphql.js +148 -0
- package/lib/templates/uiBundles/angularbasic/eslint.config.js +9 -1
- package/lib/templates/uiBundles/angularbasic/package-lock.json +680 -408
- package/lib/templates/uiBundles/angularbasic/package.json +2 -2
- package/lib/templates/uiBundles/reactbasic/package-lock.json +738 -440
- package/lib/utils/template-placeholders.js +14 -0
- package/lib/utils/template-placeholders.js.map +1 -1
- package/lib/utils/uiBundleTemplateUtils.d.ts +5 -1
- package/lib/utils/uiBundleTemplateUtils.js +7 -1
- package/lib/utils/uiBundleTemplateUtils.js.map +1 -1
- package/package.json +7 -7
- package/lib/templates/project/reactexternalapp/AGENT.md +0 -252
- package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/_os_/_ex_/api/accountSearchService.ts +0 -46
- package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/_os_/_ex_/api/query/distinctAccountIndustries.graphql +0 -19
- package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/_os_/_ex_/api/query/distinctAccountTypes.graphql +0 -19
- package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/_os_/_ex_/api/query/getAccountDetail.graphql +0 -121
- package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/_os_/_ex_/api/query/searchAccounts.graphql +0 -51
- package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/_os_/_ex_/pages/AccountObjectDetailPage.tsx +0 -355
- package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/_os_/_ex_/pages/AccountSearch.tsx +0 -304
- package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/_os_/_ex_/pages/Home.tsx +0 -34
- package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/_os_/api/objectSearchService.ts +0 -82
- package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/_os_/components/ActiveFilters.tsx +0 -89
- package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/_os_/components/PaginationControls.tsx +0 -109
- package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/_os_/components/SearchBar.tsx +0 -41
- package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/_os_/components/SortControl.tsx +0 -143
- package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/_os_/components/filters/BooleanFilter.tsx +0 -78
- package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/_os_/components/filters/DateFilter.tsx +0 -128
- package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/_os_/components/filters/DateRangeFilter.tsx +0 -70
- package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/_os_/components/filters/MultiSelectFilter.tsx +0 -97
- package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/_os_/components/filters/NumericRangeFilter.tsx +0 -167
- package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/_os_/components/filters/SearchFilter.tsx +0 -52
- package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/_os_/components/filters/SelectFilter.tsx +0 -97
- package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/_os_/components/filters/TextFilter.tsx +0 -93
- package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/_os_/hooks/useDebouncedCallback.ts +0 -34
- package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/_os_/hooks/useObjectSearchParams.ts +0 -254
- package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/_os_/utils/debounce.ts +0 -25
- package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/_os_/utils/filterUtils.ts +0 -404
- package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/_os_/utils/sortUtils.ts +0 -38
- package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/api/account/accountSearchService.ts +0 -46
- package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/api/account/query/distinctAccountIndustries.graphql +0 -19
- package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/api/account/query/distinctAccountTypes.graphql +0 -19
- package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/api/account/query/searchAccounts.graphql +0 -51
- package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/api/graphql-operations-types.ts +0 -11260
- package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/pages/AccountSearch.tsx +0 -297
- package/lib/templates/project/reactexternalapp/scripts/prepare-import-unique-fields.js +0 -122
- package/lib/templates/project/reactinternalapp/AGENT.md +0 -252
- package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/_f_/_os_/_ex_/api/accountSearchService.ts +0 -46
- package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/_f_/_os_/_ex_/api/query/distinctAccountIndustries.graphql +0 -19
- package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/_f_/_os_/_ex_/api/query/distinctAccountTypes.graphql +0 -19
- package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/_f_/_os_/_ex_/api/query/getAccountDetail.graphql +0 -121
- package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/_f_/_os_/_ex_/api/query/searchAccounts.graphql +0 -51
- package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/_f_/_os_/_ex_/pages/AccountObjectDetailPage.tsx +0 -355
- package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/_f_/_os_/_ex_/pages/AccountSearch.tsx +0 -304
- package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/_f_/_os_/_ex_/pages/Home.tsx +0 -34
- package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/_f_/_os_/api/objectSearchService.ts +0 -82
- package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/_f_/_os_/components/ActiveFilters.tsx +0 -89
- package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/_f_/_os_/components/PaginationControls.tsx +0 -109
- package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/_f_/_os_/components/SearchBar.tsx +0 -41
- package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/_f_/_os_/components/SortControl.tsx +0 -143
- package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/_f_/_os_/components/filters/BooleanFilter.tsx +0 -78
- package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/_f_/_os_/components/filters/DateFilter.tsx +0 -128
- package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/_f_/_os_/components/filters/DateRangeFilter.tsx +0 -70
- package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/_f_/_os_/components/filters/MultiSelectFilter.tsx +0 -97
- package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/_f_/_os_/components/filters/NumericRangeFilter.tsx +0 -167
- package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/_f_/_os_/components/filters/SearchFilter.tsx +0 -52
- package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/_f_/_os_/components/filters/SelectFilter.tsx +0 -97
- package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/_f_/_os_/components/filters/TextFilter.tsx +0 -93
- package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/_f_/_os_/hooks/useDebouncedCallback.ts +0 -34
- package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/_f_/_os_/hooks/useObjectSearchParams.ts +0 -254
- package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/_f_/_os_/utils/debounce.ts +0 -25
- package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/_f_/_os_/utils/filterUtils.ts +0 -404
- package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/_f_/_os_/utils/sortUtils.ts +0 -38
- package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/api/account/accountSearchService.ts +0 -46
- package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/api/account/query/distinctAccountIndustries.graphql +0 -19
- package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/api/account/query/distinctAccountTypes.graphql +0 -19
- package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/api/account/query/searchAccounts.graphql +0 -51
- package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/api/graphql-operations-types.ts +0 -11260
- package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/pages/AccountSearch.tsx +0 -297
- package/lib/templates/project/reactinternalapp/scripts/prepare-import-unique-fields.js +0 -122
- /package/lib/templates/project/angularextapp/_p_/_m_/{permissionsets → _ps_}/angularextapp_Guest_User_Api_Access.permissionset-meta.xml +0 -0
- /package/lib/templates/project/angularintapp/_p_/_m_/{permissionsets → _ps_}/angularintapp_Access.permissionset-meta.xml +0 -0
- /package/lib/templates/project/reactinternalapp/_p_/_m_/{permissionsets → _ps_}/reactinternalapp_Access.permissionset-meta.xml +0 -0
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2026, Salesforce, Inc.
|
|
3
|
+
* All rights reserved.
|
|
4
|
+
* For full license text, see the LICENSE.txt file
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import CustomerWebClientChat from "../components/CustomerWebClientChat";
|
|
8
|
+
|
|
9
|
+
export default function TestChatPage() {
|
|
10
|
+
return (
|
|
11
|
+
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-12">
|
|
12
|
+
<div className="text-center">
|
|
13
|
+
<h1 className="text-4xl font-bold text-gray-900 mb-4">Chat</h1>
|
|
14
|
+
<p className="text-lg text-gray-600 mb-8">
|
|
15
|
+
Welcome to your Customer Web Client chat application.
|
|
16
|
+
</p>
|
|
17
|
+
</div>
|
|
18
|
+
<CustomerWebClientChat
|
|
19
|
+
orgId="<ORG_ID_15_OR_18_CHAR_00D...>"
|
|
20
|
+
deploymentName="<EMBEDDED_SERVICE_DEPLOYMENT_NAME>"
|
|
21
|
+
siteURL="<SITE_URL>"
|
|
22
|
+
scrt2URL="<SCRT2_URL>"
|
|
23
|
+
/>
|
|
24
|
+
</div>
|
|
25
|
+
);
|
|
26
|
+
}
|
|
@@ -9,9 +9,10 @@ import Profile from "./features/authentication/pages/Profile";
|
|
|
9
9
|
import ChangePassword from "./features/authentication/pages/ChangePassword";
|
|
10
10
|
import PrivateRoute from "./features/authentication/layouts/privateRouteLayout";
|
|
11
11
|
import { ROUTES } from "./features/authentication/authenticationConfig";
|
|
12
|
-
import
|
|
13
|
-
import
|
|
12
|
+
import { Search as GlobalSearch, config } from "./features/search";
|
|
13
|
+
import TestChatPage from "./pages/TestChatPage";
|
|
14
14
|
import AuthAppLayout from "./features/authentication/layouts/AuthAppLayout";
|
|
15
|
+
import AccountObjectDetail from "./pages/AccountObjectDetailPage";
|
|
15
16
|
|
|
16
17
|
export const routes: RouteObject[] = [
|
|
17
18
|
{
|
|
@@ -23,10 +24,6 @@ export const routes: RouteObject[] = [
|
|
|
23
24
|
element: <Home />,
|
|
24
25
|
handle: { showInNavigation: true, label: "Home" }
|
|
25
26
|
},
|
|
26
|
-
{
|
|
27
|
-
path: '*',
|
|
28
|
-
element: <NotFound />
|
|
29
|
-
},
|
|
30
27
|
{
|
|
31
28
|
path: ROUTES.LOGIN.PATH,
|
|
32
29
|
element: <Login />,
|
|
@@ -62,13 +59,29 @@ export const routes: RouteObject[] = [
|
|
|
62
59
|
}
|
|
63
60
|
]
|
|
64
61
|
},
|
|
62
|
+
{
|
|
63
|
+
path: "search",
|
|
64
|
+
element: (
|
|
65
|
+
<GlobalSearch
|
|
66
|
+
config={config}
|
|
67
|
+
title="Search"
|
|
68
|
+
searchPlaceholder="Search accounts, contacts, opportunities, and content..."
|
|
69
|
+
/>
|
|
70
|
+
),
|
|
71
|
+
handle: { showInNavigation: true, label: "Search" }
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
path: "test-chat",
|
|
75
|
+
element: <TestChatPage />,
|
|
76
|
+
handle: { showInNavigation: true, label: "Test Chat" }
|
|
77
|
+
},
|
|
65
78
|
{
|
|
66
79
|
path: "accounts/:recordId",
|
|
67
80
|
element: <AccountObjectDetail />
|
|
68
81
|
},
|
|
69
82
|
{
|
|
70
|
-
path:
|
|
71
|
-
element: <
|
|
83
|
+
path: '*',
|
|
84
|
+
element: <NotFound />
|
|
72
85
|
}
|
|
73
86
|
]
|
|
74
87
|
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2026, Salesforce, Inc.
|
|
3
|
+
* All rights reserved.
|
|
4
|
+
* For full license text, see the LICENSE.txt file
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
/** Shape of the Embedded Messaging bootstrap global injected by the site's bootstrap.js. */
|
|
8
|
+
export interface WindowWithCwcProperties extends Window {
|
|
9
|
+
embeddedservice_bootstrap?: {
|
|
10
|
+
settings: {
|
|
11
|
+
language: string;
|
|
12
|
+
devMode?: boolean;
|
|
13
|
+
};
|
|
14
|
+
init: (
|
|
15
|
+
orgId: string,
|
|
16
|
+
deploymentName: string,
|
|
17
|
+
siteURL: string,
|
|
18
|
+
options: { scrt2URL: string },
|
|
19
|
+
) => void;
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export interface CustomerWebClientChatProps {
|
|
24
|
+
/** The organization id (15- or 18-char Salesforce id starting with `00D`). */
|
|
25
|
+
orgId: string;
|
|
26
|
+
/** The Embedded Service deployment / channel name the agent is connected to. */
|
|
27
|
+
deploymentName: string;
|
|
28
|
+
/** The ESW site URL. Usually contains `ESW` and the deployment name. */
|
|
29
|
+
siteURL: string;
|
|
30
|
+
/** The SCRT2 (Service Cloud Real-Time) chat service URL. Usually contains `scrt`. */
|
|
31
|
+
scrt2URL: string;
|
|
32
|
+
/** Optional chat language. Defaults to `"en"`. */
|
|
33
|
+
language?: string;
|
|
34
|
+
/** Optional. Enables Embedded Messaging dev mode. Defaults to `false`. */
|
|
35
|
+
devMode?: boolean;
|
|
36
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2026, Salesforce, Inc.,
|
|
3
|
+
* All rights reserved.
|
|
4
|
+
* For full license text, see the LICENSE.txt file
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Ambient augmentation of the runtime environment on {@link globalThis.SFDC_ENV}.
|
|
9
|
+
*
|
|
10
|
+
* The platform's `SfdcEnv` (see `@salesforce/platform-sdk`) does not yet declare
|
|
11
|
+
* a `language` field. The language switcher reads the active language from it, so
|
|
12
|
+
* we augment the interface with an optional `language` here. Because declared
|
|
13
|
+
* interfaces merge, this only ADDS `language` — it does not redeclare `basePath`
|
|
14
|
+
* or the other platform-owned fields.
|
|
15
|
+
*
|
|
16
|
+
* Expected value: the page locale in hyphenated form, e.g. `"en-US"` — the
|
|
17
|
+
* platform converts the underscore locale code (`en_US`) to dashes before
|
|
18
|
+
* injecting it into `SFDC_ENV`.
|
|
19
|
+
*/
|
|
20
|
+
interface SfdcEnv {
|
|
21
|
+
/** Current page language in hyphenated form, e.g. "en-US". */
|
|
22
|
+
language?: string;
|
|
23
|
+
}
|
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Field helpers for reading uiapi GraphQL response nodes on the Account
|
|
3
|
+
* detail page. Previously imported from feature-react-object-search; inlined
|
|
4
|
+
* here so the app no longer depends on that feature.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
/** Picks the user-facing string for a `{ value, displayValue }` field. */
|
|
1
8
|
export function fieldValue(
|
|
2
9
|
field: { displayValue?: string | null; value?: unknown } | null | undefined,
|
|
3
10
|
): string | null {
|
|
@@ -6,6 +13,7 @@ export function fieldValue(
|
|
|
6
13
|
return null;
|
|
7
14
|
}
|
|
8
15
|
|
|
16
|
+
/** Builds the display lines for a Salesforce compound address, or null if empty. */
|
|
9
17
|
export function getAddressFieldLines(address: {
|
|
10
18
|
street?: string | null;
|
|
11
19
|
city?: string | null;
|
|
@@ -20,6 +28,7 @@ export function getAddressFieldLines(address: {
|
|
|
20
28
|
return lines;
|
|
21
29
|
}
|
|
22
30
|
|
|
31
|
+
/** Formats an ISO datetime string with `toLocaleString`, or null if absent. */
|
|
23
32
|
export function formatDateTimeField(
|
|
24
33
|
value?: string | null,
|
|
25
34
|
...args: Parameters<Date["toLocaleString"]>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"root":["./src/app.tsx","./src/appLayout.tsx","./src/index.ts","./src/navigationMenu.tsx","./src/router-utils.tsx","./src/routes.tsx","./src/api/graphqlClient.ts","./src/components/CustomerWebClientChat.tsx","./src/components/ObjectBreadcrumb.tsx","./src/components/alerts/status-alert.tsx","./src/components/layouts/card-layout.tsx","./src/components/ui/alert.tsx","./src/components/ui/avatar.tsx","./src/components/ui/badge.tsx","./src/components/ui/breadcrumb.tsx","./src/components/ui/button.tsx","./src/components/ui/calendar.tsx","./src/components/ui/card.tsx","./src/components/ui/checkbox.tsx","./src/components/ui/collapsible.tsx","./src/components/ui/datePicker.tsx","./src/components/ui/dialog.tsx","./src/components/ui/dropdown-menu.tsx","./src/components/ui/field.tsx","./src/components/ui/index.ts","./src/components/ui/input.tsx","./src/components/ui/label.tsx","./src/components/ui/pagination.tsx","./src/components/ui/popover.tsx","./src/components/ui/select.tsx","./src/components/ui/separator.tsx","./src/components/ui/skeleton.tsx","./src/components/ui/sonner.tsx","./src/components/ui/spinner.tsx","./src/components/ui/table.tsx","./src/components/ui/tabs.tsx","./src/features/authentication/authHelpers.ts","./src/features/authentication/authenticationConfig.ts","./src/features/authentication/api/userProfileApi.ts","./src/features/authentication/components/SocialLogin.tsx","./src/features/authentication/context/AuthContext.tsx","./src/features/authentication/footers/footer-link.tsx","./src/features/authentication/forms/auth-form.tsx","./src/features/authentication/forms/submit-button.tsx","./src/features/authentication/hooks/form.tsx","./src/features/authentication/hooks/useCountdownTimer.ts","./src/features/authentication/hooks/useRetryWithBackoff.ts","./src/features/authentication/layout/centered-page-layout.tsx","./src/features/authentication/layouts/AuthAppLayout.tsx","./src/features/authentication/layouts/privateRouteLayout.tsx","./src/features/authentication/menu/AuthMenu.tsx","./src/features/authentication/pages/ChangePassword.tsx","./src/features/authentication/pages/ForgotPassword.tsx","./src/features/authentication/pages/Login.tsx","./src/features/authentication/pages/Profile.tsx","./src/features/authentication/pages/Register.tsx","./src/features/authentication/pages/ResetPassword.tsx","./src/features/authentication/sessionTimeout/SessionTimeoutValidator.tsx","./src/features/authentication/sessionTimeout/sessionTimeService.ts","./src/features/authentication/sessionTimeout/sessionTimeoutConfig.ts","./src/features/authentication/utils/helpers.ts","./src/features/language-switcher/LanguageSwitcher.tsx","./src/features/language-switcher/buildLanguageUrl.ts","./src/features/language-switcher/index.ts","./src/features/language-switcher/languages.ts","./src/features/language-switcher/__examples__/language-switcher-example.tsx","./src/features/language-switcher/__examples__/vite-config-site-example.ts","./src/features/search/constants.ts","./src/features/search/index.ts","./src/features/search/loadConfig.ts","./src/features/search/queryBuilder.ts","./src/features/search/types.ts","./src/features/search/__tests__/queryBuilder.test.ts","./src/features/search/adapters/registry.ts","./src/features/search/adapters/types.ts","./src/features/search/adapters/cms/channelResolver.ts","./src/features/search/adapters/cms/cmsQueryFragment.ts","./src/features/search/adapters/cms/contentTypeSessionCache.ts","./src/features/search/adapters/cms/contentTypeUtils.ts","./src/features/search/adapters/cms/index.ts","./src/features/search/adapters/cms/parseResponse.ts","./src/features/search/adapters/cms/searchChannel.ts","./src/features/search/adapters/cms/types.ts","./src/features/search/adapters/cms/__tests__/channelResolver.test.ts","./src/features/search/adapters/cms/__tests__/cmsQueryFragment.test.ts","./src/features/search/adapters/cms/__tests__/contentTypeSessionCache.test.ts","./src/features/search/adapters/cms/__tests__/contentTypeUtils.test.ts","./src/features/search/adapters/cms/__tests__/orgApiVersionService.test.ts","./src/features/search/adapters/cms/__tests__/parseResponse.test.ts","./src/features/search/adapters/cms/__tests__/searchChannel.test.ts","./src/features/search/adapters/cms/__tests__/searchableContentTypesService.test.ts","./src/features/search/adapters/cms/api/apiUtils.ts","./src/features/search/adapters/cms/api/orgApiVersionService.ts","./src/features/search/adapters/cms/api/searchableContentTypesService.ts","./src/features/search/adapters/cms/hooks/useSearchableContentTypes.ts","./src/features/search/adapters/sobject/index.ts","./src/features/search/adapters/sobject/parseResponse.ts","./src/features/search/adapters/sobject/queryFragment.ts","./src/features/search/api/distinctValuesService.ts","./src/features/search/api/searchService.ts","./src/features/search/api/__tests__/searchService.test.ts","./src/features/search/components/GlobalSearchBox.tsx","./src/features/search/components/MergedSearchResults.tsx","./src/features/search/components/Search.tsx","./src/features/search/components/SearchResults.tsx","./src/features/search/components/SourceSection.tsx","./src/features/search/components/__tests__/Search.test.tsx","./src/features/search/components/controls/PaginationControls.tsx","./src/features/search/components/controls/ScopeSelector.tsx","./src/features/search/components/controls/SearchBar.tsx","./src/features/search/components/controls/SortControl.tsx","./src/features/search/components/filters/ActiveFilters.tsx","./src/features/search/components/filters/DefaultFilterPanel.tsx","./src/features/search/components/filters/FilterContext.tsx","./src/features/search/components/filters/inputs/BooleanFilter.tsx","./src/features/search/components/filters/inputs/DateRangeFilter.tsx","./src/features/search/components/filters/inputs/FilterFieldWrapper.tsx","./src/features/search/components/filters/inputs/MultiSelectFilter.tsx","./src/features/search/components/filters/inputs/NumericRangeFilter.tsx","./src/features/search/components/filters/inputs/SelectFilter.tsx","./src/features/search/components/filters/inputs/TextFilter.tsx","./src/features/search/components/results/CmsResultRow.tsx","./src/features/search/components/results/DefaultResultRow.tsx","./src/features/search/components/results/resolveResultRenderer.ts","./src/features/search/components/results/__tests__/CmsResultRow.test.tsx","./src/features/search/components/results/__tests__/resolveResultRenderer.test.ts","./src/features/search/hooks/useAsyncData.ts","./src/features/search/hooks/useDistinctValues.ts","./src/features/search/hooks/useSearch.ts","./src/features/search/utils/debounce.ts","./src/features/search/utils/fieldUtils.ts","./src/features/search/utils/filterUtils.ts","./src/features/search/utils/sortUtils.ts","./src/hooks/useAsyncData.ts","./src/lib/utils.ts","./src/pages/AccountObjectDetailPage.tsx","./src/pages/Home.tsx","./src/pages/NotFound.tsx","./src/pages/TestChatPage.tsx","./src/types/chat.ts","./src/types/globals.d.ts","./src/utils/accountFields.ts","./e2e/app.spec.ts","./vite-env.d.ts","./vitest-env.d.ts","./vitest.setup.ts","../../../../../../../../../sdk/platform-sdk/types/env.d.ts"],"version":"5.9.3"}
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* REST endpoint for Social Login configuration on React Experience Cloud sites.
|
|
3
|
+
*
|
|
4
|
+
* Endpoint: GET /services/apexrest/auth/social-login-config?startURL=/
|
|
5
|
+
*
|
|
6
|
+
* This replicates the behavior of the OOTB community_login/socialLogin LWC:
|
|
7
|
+
* - applauncher.SocialLoginController.getAuthProviders()
|
|
8
|
+
* - applauncher.SocialLoginController.getSamlProviders()
|
|
9
|
+
* - applauncher.SocialLoginController.getCommunityDomainSsoUrl()
|
|
10
|
+
* - applauncher.SocialLoginController.getSamlSsoUrl()
|
|
11
|
+
* - applauncher.SocialLoginController.handleIdp()
|
|
12
|
+
*
|
|
13
|
+
* The OOTB LWC does not render on React (Site Container) sites due to a platform
|
|
14
|
+
* restriction (isSiteContainer check in node-loginsettings.ftl).
|
|
15
|
+
* This endpoint enables a custom React component to achieve the same functionality.
|
|
16
|
+
*
|
|
17
|
+
* @see https://developer.salesforce.com/docs/atlas.en-us.apexref.meta/apexref/apex_class_Auth_AuthConfiguration.htm
|
|
18
|
+
*/
|
|
19
|
+
@RestResource(urlMapping='/auth/social-login-config')
|
|
20
|
+
global with sharing class UIBundleSocialLoginConfig {
|
|
21
|
+
|
|
22
|
+
@HttpGet
|
|
23
|
+
global static SocialLoginConfigResponse getConfig() {
|
|
24
|
+
try {
|
|
25
|
+
String startUrl = RestContext.request.params.get('startURL');
|
|
26
|
+
if (String.isBlank(startUrl)) {
|
|
27
|
+
startUrl = '/';
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// Ensure startURL includes the community path prefix so post-auth
|
|
31
|
+
// redirect lands on the correct community (not the org default).
|
|
32
|
+
String pathPrefix = Site.getPathPrefix();
|
|
33
|
+
if (String.isNotBlank(pathPrefix) && !startUrl.startsWith(pathPrefix)) {
|
|
34
|
+
startUrl = pathPrefix + startUrl;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
String communityUrl = Site.getBaseUrl();
|
|
38
|
+
Auth.AuthConfiguration authConfig = new Auth.AuthConfiguration(communityUrl, startUrl);
|
|
39
|
+
|
|
40
|
+
List<AuthProviderInfo> authProviders = new List<AuthProviderInfo>();
|
|
41
|
+
List<SamlProviderInfo> samlProviders = new List<SamlProviderInfo>();
|
|
42
|
+
String autoRedirectUrl = null;
|
|
43
|
+
|
|
44
|
+
// Fetch OAuth Auth Providers (Google, Facebook, etc.)
|
|
45
|
+
List<AuthProvider> rawAuthProviders = authConfig.getAuthProviders();
|
|
46
|
+
for (AuthProvider ap : rawAuthProviders) {
|
|
47
|
+
String ssoUrl = Auth.AuthConfiguration.getAuthProviderSsoDomainUrl(
|
|
48
|
+
communityUrl, startUrl, ap.DeveloperName
|
|
49
|
+
);
|
|
50
|
+
authProviders.add(new AuthProviderInfo(
|
|
51
|
+
ap.DeveloperName,
|
|
52
|
+
ap.FriendlyName,
|
|
53
|
+
ap.IconUrl,
|
|
54
|
+
ssoUrl
|
|
55
|
+
));
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// Fetch SAML SSO Providers
|
|
59
|
+
List<SamlSsoConfig> rawSamlProviders = authConfig.getSamlProviders();
|
|
60
|
+
for (SamlSsoConfig saml : rawSamlProviders) {
|
|
61
|
+
String ssoUrl = Auth.AuthConfiguration.getSamlSsoUrl(
|
|
62
|
+
communityUrl, startUrl, saml.Id
|
|
63
|
+
);
|
|
64
|
+
samlProviders.add(new SamlProviderInfo(
|
|
65
|
+
saml.Id,
|
|
66
|
+
saml.MasterLabel,
|
|
67
|
+
ssoUrl
|
|
68
|
+
));
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// handleIdp behavior: auto-redirect if exactly one IDP and no username/password login
|
|
72
|
+
Integer totalProviders = rawAuthProviders.size() + rawSamlProviders.size();
|
|
73
|
+
if (totalProviders == 1 && !authConfig.getUsernamePasswordEnabled()) {
|
|
74
|
+
if (!authProviders.isEmpty()) {
|
|
75
|
+
autoRedirectUrl = authProviders[0].ssoUrl;
|
|
76
|
+
} else if (!samlProviders.isEmpty()) {
|
|
77
|
+
autoRedirectUrl = samlProviders[0].ssoUrl;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
return new SocialLoginConfigResponse(authProviders, samlProviders, autoRedirectUrl);
|
|
82
|
+
} catch (Exception ex) {
|
|
83
|
+
System.debug(LoggingLevel.ERROR, 'UIBundleSocialLoginConfig error: ' + ex.getMessage());
|
|
84
|
+
return new SocialLoginConfigResponse(
|
|
85
|
+
new List<AuthProviderInfo>(),
|
|
86
|
+
new List<SamlProviderInfo>(),
|
|
87
|
+
null
|
|
88
|
+
);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
global class SocialLoginConfigResponse {
|
|
93
|
+
global List<AuthProviderInfo> authProviders;
|
|
94
|
+
global List<SamlProviderInfo> samlProviders;
|
|
95
|
+
global String autoRedirectUrl;
|
|
96
|
+
|
|
97
|
+
global SocialLoginConfigResponse(
|
|
98
|
+
List<AuthProviderInfo> authProviders,
|
|
99
|
+
List<SamlProviderInfo> samlProviders,
|
|
100
|
+
String autoRedirectUrl
|
|
101
|
+
) {
|
|
102
|
+
this.authProviders = authProviders;
|
|
103
|
+
this.samlProviders = samlProviders;
|
|
104
|
+
this.autoRedirectUrl = autoRedirectUrl;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
global class AuthProviderInfo {
|
|
109
|
+
global String developerName;
|
|
110
|
+
global String friendlyName;
|
|
111
|
+
global String iconUrl;
|
|
112
|
+
global String ssoUrl;
|
|
113
|
+
|
|
114
|
+
global AuthProviderInfo(String developerName, String friendlyName, String iconUrl, String ssoUrl) {
|
|
115
|
+
this.developerName = developerName;
|
|
116
|
+
this.friendlyName = friendlyName;
|
|
117
|
+
this.iconUrl = iconUrl;
|
|
118
|
+
this.ssoUrl = ssoUrl;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
global class SamlProviderInfo {
|
|
123
|
+
global String id;
|
|
124
|
+
global String masterLabel;
|
|
125
|
+
global String ssoUrl;
|
|
126
|
+
|
|
127
|
+
global SamlProviderInfo(String id, String masterLabel, String ssoUrl) {
|
|
128
|
+
this.id = id;
|
|
129
|
+
this.masterLabel = masterLabel;
|
|
130
|
+
this.ssoUrl = ssoUrl;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
package/lib/templates/project/reactexternalapp/_p_/_m_/classes/UIBundleSocialLoginConfig_Test.cls
ADDED
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Test class for UIBundleSocialLoginConfig REST endpoint.
|
|
3
|
+
*
|
|
4
|
+
* Auth.AuthConfiguration requires a valid community URL so these tests
|
|
5
|
+
* exercise the error-handling path and verify the response wrapper structure.
|
|
6
|
+
* Integration-level testing of actual Auth Provider/SAML discovery happens
|
|
7
|
+
* in the target org via the React component E2E flow.
|
|
8
|
+
*/
|
|
9
|
+
@isTest
|
|
10
|
+
private class UIBundleSocialLoginConfig_Test {
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Test that the endpoint returns an empty config when no community context
|
|
14
|
+
* is available (covers the catch block graceful fallback).
|
|
15
|
+
*/
|
|
16
|
+
@isTest
|
|
17
|
+
static void testGetConfigNoSiteContext() {
|
|
18
|
+
RestRequest req = new RestRequest();
|
|
19
|
+
req.requestURI = '/services/apexrest/auth/social-login-config';
|
|
20
|
+
req.httpMethod = 'GET';
|
|
21
|
+
req.params.put('startURL', '/');
|
|
22
|
+
RestContext.request = req;
|
|
23
|
+
RestContext.response = new RestResponse();
|
|
24
|
+
|
|
25
|
+
Test.startTest();
|
|
26
|
+
UIBundleSocialLoginConfig.SocialLoginConfigResponse result =
|
|
27
|
+
UIBundleSocialLoginConfig.getConfig();
|
|
28
|
+
Test.stopTest();
|
|
29
|
+
|
|
30
|
+
// Should return empty lists (graceful fallback), not null
|
|
31
|
+
System.assertNotEquals(null, result, 'Response should not be null');
|
|
32
|
+
System.assertNotEquals(null, result.authProviders, 'authProviders list should not be null');
|
|
33
|
+
System.assertNotEquals(null, result.samlProviders, 'samlProviders list should not be null');
|
|
34
|
+
System.assertEquals(0, result.authProviders.size(), 'authProviders should be empty without community context');
|
|
35
|
+
System.assertEquals(0, result.samlProviders.size(), 'samlProviders should be empty without community context');
|
|
36
|
+
System.assertEquals(null, result.autoRedirectUrl, 'autoRedirectUrl should be null without providers');
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Test that the endpoint handles a missing startURL parameter gracefully
|
|
41
|
+
* (defaults to "/").
|
|
42
|
+
*/
|
|
43
|
+
@isTest
|
|
44
|
+
static void testGetConfigNoStartUrl() {
|
|
45
|
+
RestRequest req = new RestRequest();
|
|
46
|
+
req.requestURI = '/services/apexrest/auth/social-login-config';
|
|
47
|
+
req.httpMethod = 'GET';
|
|
48
|
+
// Intentionally not setting startURL param
|
|
49
|
+
RestContext.request = req;
|
|
50
|
+
RestContext.response = new RestResponse();
|
|
51
|
+
|
|
52
|
+
Test.startTest();
|
|
53
|
+
UIBundleSocialLoginConfig.SocialLoginConfigResponse result =
|
|
54
|
+
UIBundleSocialLoginConfig.getConfig();
|
|
55
|
+
Test.stopTest();
|
|
56
|
+
|
|
57
|
+
System.assertNotEquals(null, result, 'Response should not be null even without startURL');
|
|
58
|
+
System.assertNotEquals(null, result.authProviders, 'authProviders should not be null');
|
|
59
|
+
System.assertNotEquals(null, result.samlProviders, 'samlProviders should not be null');
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Test the inner class constructors for code coverage.
|
|
64
|
+
*/
|
|
65
|
+
@isTest
|
|
66
|
+
static void testInnerClassConstructors() {
|
|
67
|
+
Test.startTest();
|
|
68
|
+
|
|
69
|
+
UIBundleSocialLoginConfig.AuthProviderInfo authInfo =
|
|
70
|
+
new UIBundleSocialLoginConfig.AuthProviderInfo(
|
|
71
|
+
'TestProvider', 'Test Provider', 'https://example.com/icon.png', 'https://example.com/sso'
|
|
72
|
+
);
|
|
73
|
+
System.assertEquals('TestProvider', authInfo.developerName);
|
|
74
|
+
System.assertEquals('Test Provider', authInfo.friendlyName);
|
|
75
|
+
System.assertEquals('https://example.com/icon.png', authInfo.iconUrl);
|
|
76
|
+
System.assertEquals('https://example.com/sso', authInfo.ssoUrl);
|
|
77
|
+
|
|
78
|
+
UIBundleSocialLoginConfig.SamlProviderInfo samlInfo =
|
|
79
|
+
new UIBundleSocialLoginConfig.SamlProviderInfo(
|
|
80
|
+
'001000000000001', 'Test SAML', 'https://example.com/saml/sso'
|
|
81
|
+
);
|
|
82
|
+
System.assertEquals('001000000000001', samlInfo.id);
|
|
83
|
+
System.assertEquals('Test SAML', samlInfo.masterLabel);
|
|
84
|
+
System.assertEquals('https://example.com/saml/sso', samlInfo.ssoUrl);
|
|
85
|
+
|
|
86
|
+
List<UIBundleSocialLoginConfig.AuthProviderInfo> authList =
|
|
87
|
+
new List<UIBundleSocialLoginConfig.AuthProviderInfo>{ authInfo };
|
|
88
|
+
List<UIBundleSocialLoginConfig.SamlProviderInfo> samlList =
|
|
89
|
+
new List<UIBundleSocialLoginConfig.SamlProviderInfo>{ samlInfo };
|
|
90
|
+
|
|
91
|
+
UIBundleSocialLoginConfig.SocialLoginConfigResponse resp =
|
|
92
|
+
new UIBundleSocialLoginConfig.SocialLoginConfigResponse(
|
|
93
|
+
authList, samlList, 'https://example.com/redirect'
|
|
94
|
+
);
|
|
95
|
+
System.assertEquals(1, resp.authProviders.size());
|
|
96
|
+
System.assertEquals(1, resp.samlProviders.size());
|
|
97
|
+
System.assertEquals('https://example.com/redirect', resp.autoRedirectUrl);
|
|
98
|
+
|
|
99
|
+
Test.stopTest();
|
|
100
|
+
}
|
|
101
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@salesforce/ui-bundle-template-base-sfdx-project",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "11.57.2",
|
|
4
4
|
"description": "Base SFDX project template",
|
|
5
5
|
"license": "SEE LICENSE IN LICENSE.txt",
|
|
6
6
|
"publishConfig": {
|
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
"build": "echo 'No build required for base-sfdx-project'",
|
|
12
12
|
"clean": "echo 'No clean required for base-sfdx-project'",
|
|
13
13
|
"lint": "eslint --no-error-on-unmatched-pattern **/{aura,lwc}/**/*.js",
|
|
14
|
+
"validate:org-setup-config": "node scripts/validate-org-setup-config.mjs",
|
|
14
15
|
"test": "npm run test:unit",
|
|
15
16
|
"test:coverage": "npm run test",
|
|
16
17
|
"test:unit": "sfdx-lwc-jest -- --passWithNoTests",
|
|
@@ -20,7 +21,12 @@
|
|
|
20
21
|
"prettier": "prettier --write \"**/*.{cls,cmp,component,css,html,js,json,md,page,trigger,xml,yaml,yml}\"",
|
|
21
22
|
"prettier:verify": "prettier --check \"**/*.{cls,cmp,component,css,html,js,json,md,page,trigger,xml,yaml,yml}\"",
|
|
22
23
|
"precommit": "lint-staged",
|
|
23
|
-
"setup": "node scripts/org-setup.mjs"
|
|
24
|
+
"setup": "node scripts/org-setup.mjs",
|
|
25
|
+
"dev:preview": "node scripts/org-setup-dev.mjs"
|
|
26
|
+
},
|
|
27
|
+
"dependencies": {
|
|
28
|
+
"fast-xml-parser": "^5.9.3",
|
|
29
|
+
"zod": "^3.24.1"
|
|
24
30
|
},
|
|
25
31
|
"devDependencies": {
|
|
26
32
|
"@lwc/eslint-plugin-lwc": "^3.3.0",
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared schema + validator for org-setup.config.json (W-23043729).
|
|
3
|
+
*
|
|
4
|
+
* Authored ONCE, used at TWO moments:
|
|
5
|
+
* (a) build / CI time — `scripts/validate-org-setup-config.mjs` validates every
|
|
6
|
+
* org-setup.config.json this repo ships, failing the build on any violation.
|
|
7
|
+
* (b) setup runtime — `org-setup.mjs` calls `validateConfig` once in main(),
|
|
8
|
+
* before any step runs, to catch the developer's local post-scaffold edits.
|
|
9
|
+
*
|
|
10
|
+
* `validateConfig` is pure: it parses + validates and RETURNS a result. Each call
|
|
11
|
+
* site owns its own print/exit, so the build gate can report every bad file and
|
|
12
|
+
* the runtime can exit immediately — and the validator stays unit-testable.
|
|
13
|
+
*
|
|
14
|
+
* The zod schema uses `.strict()` at every level so unknown keys (e.g. the
|
|
15
|
+
* `permsetAssignment` singular typo) are rejected rather than silently ignored.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
import { z } from 'zod';
|
|
19
|
+
|
|
20
|
+
/** Closed set of assignee values — no arbitrary usernames. */
|
|
21
|
+
const Assignee = z.enum(['currentUser', 'guestUser', 'skip']);
|
|
22
|
+
|
|
23
|
+
// No siteName: for guestUser the site is derived from the single
|
|
24
|
+
// networks/<siteName>.network-meta.xml the app ships (see spec §5.2).
|
|
25
|
+
const Assignment = z
|
|
26
|
+
.object({
|
|
27
|
+
assignee: Assignee,
|
|
28
|
+
})
|
|
29
|
+
.strict();
|
|
30
|
+
|
|
31
|
+
export const ConfigSchema = z
|
|
32
|
+
.object({
|
|
33
|
+
permsetAssignments: z
|
|
34
|
+
.object({
|
|
35
|
+
// guestUser is valid here — siteName is derived, not per-assignment.
|
|
36
|
+
defaultAssignee: Assignee.default('skip'),
|
|
37
|
+
assignments: z.record(z.string(), Assignment).default({}),
|
|
38
|
+
})
|
|
39
|
+
.strict()
|
|
40
|
+
.optional(),
|
|
41
|
+
role: z
|
|
42
|
+
.object({
|
|
43
|
+
assignee: z.literal('currentUser'), // only value the role code honors
|
|
44
|
+
roleName: z.string().min(1),
|
|
45
|
+
})
|
|
46
|
+
.strict()
|
|
47
|
+
.optional(),
|
|
48
|
+
selfRegistration: z
|
|
49
|
+
.object({
|
|
50
|
+
// No siteName: the site is derived from the single
|
|
51
|
+
// networks/<siteName>.network-meta.xml the app ships (see spec §5.2),
|
|
52
|
+
// exactly like the guestUser permset path.
|
|
53
|
+
//
|
|
54
|
+
// selfRegProfile also drives the M1 license pre-check (W-23043735):
|
|
55
|
+
// setup derives the required UserLicense from this profile
|
|
56
|
+
// (Profile.UserLicense, matched on the stable LicenseDefinitionKey) and
|
|
57
|
+
// warns + skips self-registration when the org lacks it or has no seats.
|
|
58
|
+
// No separate license field is declared — the requirement can't drift
|
|
59
|
+
// from the profile the flow actually assigns.
|
|
60
|
+
selfRegProfile: z.string().min(1),
|
|
61
|
+
accountName: z.string().min(1),
|
|
62
|
+
})
|
|
63
|
+
.strict()
|
|
64
|
+
.optional(),
|
|
65
|
+
socialLogin: z
|
|
66
|
+
.object({
|
|
67
|
+
// Profile to add to NetworkMemberGroup so SSO-registered users can access
|
|
68
|
+
// the community (e.g. "Customer Community User"). Also enables the
|
|
69
|
+
// "Allow standard external profiles" org setting.
|
|
70
|
+
communityMemberProfile: z.string().min(1),
|
|
71
|
+
// DeveloperName of AuthProvider (OAuth) or SamlSsoConfig (SAML) records to link to the site's AuthConfig.
|
|
72
|
+
// Required because React (Site Container) sites hide SSO config in Admin UI.
|
|
73
|
+
authProviderNames: z.array(z.string().min(1)).min(1),
|
|
74
|
+
// Permission set to assign to community users created via SSO.
|
|
75
|
+
// Required because getCurrentUser() calls /chatter/users/me which needs
|
|
76
|
+
// API access (PermissionsApiEnabled) that the community profile lacks.
|
|
77
|
+
// Typically the app's "*_Guest_User_Api_Access" permset.
|
|
78
|
+
communityUserPermset: z.string().min(1).optional(),
|
|
79
|
+
})
|
|
80
|
+
.strict()
|
|
81
|
+
.optional(),
|
|
82
|
+
})
|
|
83
|
+
.strict();
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Render a single zod issue as a "path: message" line. Empty path (a root-level
|
|
87
|
+
* problem) renders as "<root>: message".
|
|
88
|
+
*/
|
|
89
|
+
function formatIssue(issue) {
|
|
90
|
+
const path = issue.path.length > 0 ? issue.path.join('.') : '<root>';
|
|
91
|
+
return `${path}: ${issue.message}`;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Parse + validate a raw org-setup.config.json string.
|
|
96
|
+
*
|
|
97
|
+
* @param {string} rawText raw file contents (not yet JSON-parsed)
|
|
98
|
+
* @param {string} [configPath] path used only for error messages
|
|
99
|
+
* @returns {{ ok: true, data: object } | { ok: false, errors: string[] }}
|
|
100
|
+
* On success, `data` is the parsed + defaulted config. On failure, `errors`
|
|
101
|
+
* is a non-empty list of human-readable messages (JSON parse error or zod
|
|
102
|
+
* issues). The caller decides whether to print/exit.
|
|
103
|
+
*/
|
|
104
|
+
export function validateConfig(rawText, configPath) {
|
|
105
|
+
const where = configPath ? ` (${configPath})` : '';
|
|
106
|
+
|
|
107
|
+
let parsed;
|
|
108
|
+
try {
|
|
109
|
+
parsed = JSON.parse(rawText);
|
|
110
|
+
} catch (err) {
|
|
111
|
+
return { ok: false, errors: [`malformed JSON${where}: ${err.message}`] };
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
const result = ConfigSchema.safeParse(parsed);
|
|
115
|
+
if (!result.success) {
|
|
116
|
+
return { ok: false, errors: result.error.issues.map(formatIssue) };
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
return { ok: true, data: result.data };
|
|
120
|
+
}
|