@salesforce/templates 66.13.4 → 66.13.6
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/generators/baseGenerator.d.ts +2 -0
- package/lib/generators/baseGenerator.js +353 -0
- package/lib/generators/baseGenerator.js.map +1 -1
- package/lib/index.d.ts +1 -0
- package/lib/index.js +3 -1
- package/lib/index.js.map +1 -1
- 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 +421 -394
- 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 +431 -404
- 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 +1313 -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 +660 -692
- 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_/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/api/distinctValuesService.ts +84 -0
- package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/search/api/searchService.ts +71 -0
- package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/search/components/MergedSearchResults.tsx +277 -0
- package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/search/components/Search.tsx +185 -0
- package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/search/components/SearchResults.tsx +77 -0
- package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/search/components/SourceSection.tsx +182 -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 +55 -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/DefaultResultRow.tsx +109 -0
- package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/search/config.json +83 -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 +703 -0
- package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/search/index.ts +90 -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 +156 -0
- package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/_f_/search/types.ts +307 -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 +6 -0
- package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/pages/AccountObjectDetailPage.tsx +49 -16
- package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/pages/AccountSearch.tsx +21 -293
- package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/src/pages/Home.tsx +22 -7
- 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 +11 -5
- 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/{_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 +1127 -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 +509 -505
- package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/package.json +9 -8
- 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 +71 -0
- package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/_f_/search/components/MergedSearchResults.tsx +277 -0
- package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/_f_/search/components/Search.tsx +185 -0
- package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/_f_/search/components/SearchResults.tsx +77 -0
- package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/_f_/search/components/SourceSection.tsx +182 -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 +55 -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/DefaultResultRow.tsx +109 -0
- package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/_f_/search/config.json +83 -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 +703 -0
- package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/_f_/search/index.ts +90 -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 +156 -0
- package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/_f_/search/types.ts +307 -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/AccountSearch.tsx +21 -293
- package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/pages/Home.tsx +21 -6
- package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/src/routes.tsx +4 -4
- 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 +421 -394
- package/lib/templates/uiBundles/angularbasic/package.json +2 -2
- package/lib/templates/uiBundles/reactbasic/package-lock.json +445 -418
- package/lib/utils/template-placeholders.js +7 -0
- package/lib/utils/template-placeholders.js.map +1 -1
- package/lib/utils/uiBundleTemplateUtils.d.ts +3 -1
- package/lib/utils/uiBundleTemplateUtils.js +4 -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/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/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
|
@@ -1,297 +1,25 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
Collapsible,
|
|
17
|
-
CollapsibleContent,
|
|
18
|
-
CollapsibleTrigger,
|
|
19
|
-
} from "../components/ui/collapsible";
|
|
20
|
-
import { Skeleton } from "../components/ui/skeleton";
|
|
21
|
-
import {
|
|
22
|
-
FilterProvider,
|
|
23
|
-
FilterResetButton,
|
|
24
|
-
} from "../features/object-search/components/FilterContext";
|
|
25
|
-
import { SearchFilter } from "../features/object-search/components/filters/SearchFilter";
|
|
26
|
-
import { TextFilter } from "../features/object-search/components/filters/TextFilter";
|
|
27
|
-
import { SelectFilter } from "../features/object-search/components/filters/SelectFilter";
|
|
28
|
-
import { MultiSelectFilter } from "../features/object-search/components/filters/MultiSelectFilter";
|
|
29
|
-
import { NumericRangeFilter } from "../features/object-search/components/filters/NumericRangeFilter";
|
|
30
|
-
import { DateFilter } from "../features/object-search/components/filters/DateFilter";
|
|
31
|
-
import { DateRangeFilter } from "../features/object-search/components/filters/DateRangeFilter";
|
|
32
|
-
import { ActiveFilters } from "../features/object-search/components/ActiveFilters";
|
|
33
|
-
import { SortControl } from "../features/object-search/components/SortControl";
|
|
34
|
-
import type { FilterFieldConfig } from "../features/object-search/utils/filterUtils";
|
|
35
|
-
import type { SortFieldConfig } from "../features/object-search/utils/sortUtils";
|
|
36
|
-
import type { Account_Filter, Account_OrderBy } from "../api/graphql-operations-types";
|
|
37
|
-
import type { AccountSearchResult } from "../api/account/accountSearchService";
|
|
38
|
-
import { ObjectBreadcrumb } from "../features/object-search/components/ObjectBreadcrumb";
|
|
39
|
-
import PaginationControls from "../features/object-search/components/PaginationControls";
|
|
40
|
-
import type { PaginationConfig } from "../features/object-search/hooks/useObjectSearchParams";
|
|
41
|
-
|
|
42
|
-
const PAGINATION_CONFIG: PaginationConfig = {
|
|
43
|
-
defaultPageSize: 7,
|
|
44
|
-
validPageSizes: [7, 14, 28, 42],
|
|
45
|
-
};
|
|
46
|
-
|
|
47
|
-
type AccountNode = NonNullable<
|
|
48
|
-
NonNullable<NonNullable<AccountSearchResult["edges"]>[number]>["node"]
|
|
49
|
-
>;
|
|
50
|
-
|
|
51
|
-
const FILTER_CONFIGS: FilterFieldConfig[] = [
|
|
52
|
-
{
|
|
53
|
-
field: "search",
|
|
54
|
-
label: "Search",
|
|
55
|
-
type: "search",
|
|
56
|
-
searchFields: ["Name", "Phone", "Industry"],
|
|
57
|
-
placeholder: "Search by name, phone, or industry...",
|
|
58
|
-
},
|
|
59
|
-
{ field: "Name", label: "Account Name", type: "text", placeholder: "Search by name..." },
|
|
60
|
-
{ field: "Industry", label: "Industry", type: "picklist" },
|
|
61
|
-
{ field: "Type", label: "Type", type: "multipicklist" },
|
|
62
|
-
{ field: "AnnualRevenue", label: "Annual Revenue", type: "numeric" },
|
|
63
|
-
{ field: "CreatedDate", label: "Created Date", type: "datetime" },
|
|
64
|
-
{ field: "LastModifiedDate", label: "Last Modified Date", type: "datetimerange" },
|
|
65
|
-
];
|
|
66
|
-
|
|
67
|
-
const ACCOUNT_SORT_CONFIGS: SortFieldConfig<keyof Account_OrderBy>[] = [
|
|
68
|
-
{ field: "Name", label: "Name" },
|
|
69
|
-
{ field: "AnnualRevenue", label: "Annual Revenue" },
|
|
70
|
-
{ field: "Industry", label: "Industry" },
|
|
71
|
-
{ field: "CreatedDate", label: "Created Date" },
|
|
72
|
-
];
|
|
73
|
-
|
|
74
|
-
// -- Component --------------------------------------------------------------
|
|
75
|
-
|
|
1
|
+
import { Search, config } from "../features/search";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Account search page.
|
|
5
|
+
*
|
|
6
|
+
* Renders the config-driven `<Search>` feature (feature-react-search) locked to
|
|
7
|
+
* the Account source via `restrictTo`. The shared `config.json` already defines
|
|
8
|
+
* the Account source's searchable fields, filters, sort options, and
|
|
9
|
+
* `routePattern` ("/accounts/:id"), so result rows link to the Account detail
|
|
10
|
+
* page and the filter / sort chrome render automatically — no per-page wiring.
|
|
11
|
+
*
|
|
12
|
+
* `restrictTo` hides the scope selector and fetches only Accounts, so the page
|
|
13
|
+
* reads as a single-object search even though the underlying feature supports
|
|
14
|
+
* many sources.
|
|
15
|
+
*/
|
|
76
16
|
export default function AccountSearch() {
|
|
77
|
-
const [filtersOpen, setFiltersOpen] = useState(true);
|
|
78
|
-
const { data: industryOptions } = useAsyncData(fetchDistinctIndustries, []);
|
|
79
|
-
const { data: typeOptions } = useAsyncData(fetchDistinctTypes, []);
|
|
80
|
-
|
|
81
|
-
const { filters, sort, query, pagination, resetAll } = useObjectSearchParams<
|
|
82
|
-
Account_Filter,
|
|
83
|
-
Account_OrderBy
|
|
84
|
-
>(FILTER_CONFIGS, ACCOUNT_SORT_CONFIGS, PAGINATION_CONFIG);
|
|
85
|
-
|
|
86
|
-
const { data, loading, error } = useAsyncData(
|
|
87
|
-
() =>
|
|
88
|
-
searchAccounts({
|
|
89
|
-
where: query.where,
|
|
90
|
-
orderBy: query.orderBy,
|
|
91
|
-
first: pagination.pageSize,
|
|
92
|
-
after: pagination.afterCursor,
|
|
93
|
-
}),
|
|
94
|
-
[query.where, query.orderBy, pagination.pageSize, pagination.afterCursor],
|
|
95
|
-
);
|
|
96
|
-
|
|
97
|
-
const pageInfo = data?.pageInfo;
|
|
98
|
-
const totalCount = data?.totalCount;
|
|
99
|
-
const hasNextPage = pageInfo?.hasNextPage ?? false;
|
|
100
|
-
const hasPreviousPage = pagination.pageIndex > 0;
|
|
101
|
-
|
|
102
|
-
const validAccountNodes = useMemo(
|
|
103
|
-
() =>
|
|
104
|
-
(data?.edges ?? []).reduce<AccountNode[]>((acc, edge) => {
|
|
105
|
-
if (edge?.node) acc.push(edge.node);
|
|
106
|
-
return acc;
|
|
107
|
-
}, []),
|
|
108
|
-
[data?.edges],
|
|
109
|
-
);
|
|
110
|
-
|
|
111
|
-
return (
|
|
112
|
-
<div className="max-w-6xl mx-auto px-4 sm:px-6 lg:px-8 py-6">
|
|
113
|
-
<ObjectBreadcrumb listPath="/accounts" listLabel="Accounts" />
|
|
114
|
-
|
|
115
|
-
<h1 className="text-2xl font-bold mb-4">Search Accounts</h1>
|
|
116
|
-
|
|
117
|
-
<div className="flex flex-col lg:flex-row gap-6">
|
|
118
|
-
{/* Sidebar — Filter Panel */}
|
|
119
|
-
<aside className="w-full lg:w-80 shrink-0">
|
|
120
|
-
<FilterProvider
|
|
121
|
-
filters={filters.active}
|
|
122
|
-
onFilterChange={filters.set}
|
|
123
|
-
onFilterRemove={filters.remove}
|
|
124
|
-
onReset={resetAll}
|
|
125
|
-
>
|
|
126
|
-
<Card>
|
|
127
|
-
<Collapsible open={filtersOpen} onOpenChange={setFiltersOpen}>
|
|
128
|
-
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
|
|
129
|
-
<CardTitle className="text-base font-semibold">
|
|
130
|
-
<h2>Filters</h2>
|
|
131
|
-
</CardTitle>
|
|
132
|
-
<div className="flex items-center gap-1">
|
|
133
|
-
<FilterResetButton variant="destructive" size="sm" />
|
|
134
|
-
<CollapsibleTrigger asChild>
|
|
135
|
-
<Button variant="ghost" size="icon">
|
|
136
|
-
<ChevronDown
|
|
137
|
-
className={`h-4 w-4 transition-transform ${filtersOpen ? "" : "-rotate-90"}`}
|
|
138
|
-
/>
|
|
139
|
-
<span className="sr-only">Toggle filters</span>
|
|
140
|
-
</Button>
|
|
141
|
-
</CollapsibleTrigger>
|
|
142
|
-
</div>
|
|
143
|
-
</CardHeader>
|
|
144
|
-
<CollapsibleContent>
|
|
145
|
-
<CardContent className="space-y-1 pt-0">
|
|
146
|
-
<SearchFilter
|
|
147
|
-
field="search"
|
|
148
|
-
label="Search"
|
|
149
|
-
placeholder="Search by name, phone, or industry..."
|
|
150
|
-
/>
|
|
151
|
-
<TextFilter field="Name" label="Account Name" placeholder="Search by name..." />
|
|
152
|
-
<SelectFilter
|
|
153
|
-
field="Industry"
|
|
154
|
-
label="Industry"
|
|
155
|
-
options={industryOptions ?? []}
|
|
156
|
-
/>
|
|
157
|
-
<MultiSelectFilter field="Type" label="Type" options={typeOptions ?? []} />
|
|
158
|
-
<NumericRangeFilter field="AnnualRevenue" label="Annual Revenue" />
|
|
159
|
-
<DateFilter field="CreatedDate" label="Created Date" filterType="datetime" />
|
|
160
|
-
<DateRangeFilter
|
|
161
|
-
field="LastModifiedDate"
|
|
162
|
-
label="Last Modified Date"
|
|
163
|
-
filterType="datetimerange"
|
|
164
|
-
/>
|
|
165
|
-
</CardContent>
|
|
166
|
-
</CollapsibleContent>
|
|
167
|
-
</Collapsible>
|
|
168
|
-
</Card>
|
|
169
|
-
</FilterProvider>
|
|
170
|
-
</aside>
|
|
171
|
-
|
|
172
|
-
{/* Main area — Sort + Results */}
|
|
173
|
-
<div className="flex-1 min-w-0">
|
|
174
|
-
{/* Sort control + active filters */}
|
|
175
|
-
<div className="flex flex-wrap items-center gap-2 mb-4">
|
|
176
|
-
<SortControl
|
|
177
|
-
configs={ACCOUNT_SORT_CONFIGS}
|
|
178
|
-
sort={sort.current}
|
|
179
|
-
onSortChange={sort.set}
|
|
180
|
-
/>
|
|
181
|
-
<ActiveFilters filters={filters.active} onRemove={filters.remove} />
|
|
182
|
-
</div>
|
|
183
|
-
|
|
184
|
-
<div className="min-h-132">
|
|
185
|
-
{/* Loading state */}
|
|
186
|
-
{loading && (
|
|
187
|
-
<>
|
|
188
|
-
<Skeleton className="h-5 w-30 mb-3" />
|
|
189
|
-
<div className="divide-y">
|
|
190
|
-
{Array.from({ length: pagination.pageSize }, (_, i) => (
|
|
191
|
-
<div key={i} className="flex items-center justify-between py-3">
|
|
192
|
-
<div className="space-y-2">
|
|
193
|
-
<Skeleton className="h-5 w-40" />
|
|
194
|
-
<Skeleton className="h-4 w-28" />
|
|
195
|
-
</div>
|
|
196
|
-
<div className="space-y-2 flex flex-col items-end">
|
|
197
|
-
<Skeleton className="h-4 w-24" />
|
|
198
|
-
<Skeleton className="h-4 w-20" />
|
|
199
|
-
</div>
|
|
200
|
-
</div>
|
|
201
|
-
))}
|
|
202
|
-
</div>
|
|
203
|
-
</>
|
|
204
|
-
)}
|
|
205
|
-
|
|
206
|
-
{/* Error state */}
|
|
207
|
-
{error && (
|
|
208
|
-
<>
|
|
209
|
-
<p className="text-sm text-muted-foreground mb-3">0 accounts found</p>
|
|
210
|
-
<Alert variant="destructive" role="alert">
|
|
211
|
-
<AlertCircle />
|
|
212
|
-
<AlertTitle>Failed to load accounts</AlertTitle>
|
|
213
|
-
<AlertDescription>
|
|
214
|
-
Something went wrong while loading accounts. Please try again later.
|
|
215
|
-
</AlertDescription>
|
|
216
|
-
</Alert>
|
|
217
|
-
</>
|
|
218
|
-
)}
|
|
219
|
-
|
|
220
|
-
{/* Results list */}
|
|
221
|
-
{!loading && !error && validAccountNodes.length > 0 && (
|
|
222
|
-
<>
|
|
223
|
-
<p className="text-sm text-muted-foreground mb-3">
|
|
224
|
-
{totalCount != null && (hasNextPage || hasPreviousPage)
|
|
225
|
-
? `${totalCount} account${totalCount !== 1 ? "s" : ""} found`
|
|
226
|
-
: `Showing ${validAccountNodes.length} account${validAccountNodes.length !== 1 ? "s" : ""}`}
|
|
227
|
-
</p>
|
|
228
|
-
<AccountResultsList nodes={validAccountNodes} />
|
|
229
|
-
</>
|
|
230
|
-
)}
|
|
231
|
-
|
|
232
|
-
{/* No results state */}
|
|
233
|
-
{!loading && !error && validAccountNodes.length === 0 && (
|
|
234
|
-
<div className="flex flex-col items-center justify-center py-16 text-center">
|
|
235
|
-
<SearchX className="size-12 text-muted-foreground mb-4" />
|
|
236
|
-
<h2 className="text-lg font-semibold mb-1">No accounts found</h2>
|
|
237
|
-
<p className="text-sm text-muted-foreground">
|
|
238
|
-
Try adjusting your filters or search criteria.
|
|
239
|
-
</p>
|
|
240
|
-
</div>
|
|
241
|
-
)}
|
|
242
|
-
</div>
|
|
243
|
-
|
|
244
|
-
{/* Pagination — always visible, disabled while loading or on error */}
|
|
245
|
-
<PaginationControls
|
|
246
|
-
pageIndex={pagination.pageIndex}
|
|
247
|
-
hasNextPage={hasNextPage}
|
|
248
|
-
hasPreviousPage={hasPreviousPage}
|
|
249
|
-
pageSize={pagination.pageSize}
|
|
250
|
-
pageSizeOptions={PAGINATION_CONFIG.validPageSizes}
|
|
251
|
-
onNextPage={() => {
|
|
252
|
-
if (pageInfo?.endCursor) pagination.goToNextPage(pageInfo.endCursor);
|
|
253
|
-
}}
|
|
254
|
-
onPreviousPage={pagination.goToPreviousPage}
|
|
255
|
-
onPageSizeChange={pagination.setPageSize}
|
|
256
|
-
disabled={loading || !!error}
|
|
257
|
-
/>
|
|
258
|
-
</div>
|
|
259
|
-
</div>
|
|
260
|
-
</div>
|
|
261
|
-
);
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
// -- Result Components ------------------------------------------------------
|
|
265
|
-
|
|
266
|
-
function AccountResultsList({ nodes }: { nodes: AccountNode[] }) {
|
|
267
|
-
return (
|
|
268
|
-
<ul className="divide-y">
|
|
269
|
-
{nodes.map((node) => (
|
|
270
|
-
<AccountResultItem key={node.Id} node={node} />
|
|
271
|
-
))}
|
|
272
|
-
</ul>
|
|
273
|
-
);
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
function AccountResultItem({ node }: { node: AccountNode }) {
|
|
277
17
|
return (
|
|
278
|
-
<
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
<span className="font-medium">{fieldValue(node.Name) ?? "\u2014"}</span>
|
|
285
|
-
<p className="text-sm text-muted-foreground">
|
|
286
|
-
{[fieldValue(node.Industry), fieldValue(node.Type)].filter(Boolean).join(" \u00B7 ") ||
|
|
287
|
-
"\u2014"}
|
|
288
|
-
</p>
|
|
289
|
-
</div>
|
|
290
|
-
<div className="text-right text-sm">
|
|
291
|
-
<p>{fieldValue(node.Phone) ?? ""}</p>
|
|
292
|
-
<p className="text-muted-foreground">{fieldValue(node.Owner?.Name) ?? ""}</p>
|
|
293
|
-
</div>
|
|
294
|
-
</Link>
|
|
295
|
-
</li>
|
|
18
|
+
<Search
|
|
19
|
+
config={config}
|
|
20
|
+
title="Search Accounts"
|
|
21
|
+
searchPlaceholder="Search by name, phone, or industry..."
|
|
22
|
+
restrictTo={{ kind: "sobject", key: "accounts" }}
|
|
23
|
+
/>
|
|
296
24
|
);
|
|
297
25
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { useState } from "react";
|
|
2
2
|
import { useNavigate } from "react-router";
|
|
3
|
-
import {
|
|
3
|
+
import { Search } from "lucide-react";
|
|
4
|
+
import { Input } from "../components/ui/input";
|
|
4
5
|
import { Button } from "../components/ui/button";
|
|
5
6
|
|
|
6
7
|
export default function HomePage() {
|
|
@@ -9,6 +10,8 @@ export default function HomePage() {
|
|
|
9
10
|
|
|
10
11
|
const handleSubmit = (e: React.SyntheticEvent<HTMLFormElement>) => {
|
|
11
12
|
e.preventDefault();
|
|
13
|
+
// `q` matches the search feature's GLOBAL_QUERY_KEY, so the term
|
|
14
|
+
// pre-fills the Account search page on arrival.
|
|
12
15
|
const params = text ? `?q=${encodeURIComponent(text)}` : "";
|
|
13
16
|
navigate(`/accounts${params}`);
|
|
14
17
|
};
|
|
@@ -16,17 +19,29 @@ export default function HomePage() {
|
|
|
16
19
|
return (
|
|
17
20
|
<div className="max-w-2xl mx-auto px-4 sm:px-6 lg:px-8 py-12">
|
|
18
21
|
<div className="flex items-center gap-6 mb-6">
|
|
19
|
-
<h1 className="text-2xl font-bold">
|
|
22
|
+
<h1 className="text-2xl font-bold">Search Accounts</h1>
|
|
20
23
|
<Button variant="outline" size="sm" onClick={() => navigate("/accounts")}>
|
|
21
24
|
Browse All Accounts
|
|
22
25
|
</Button>
|
|
23
26
|
</div>
|
|
24
27
|
<form onSubmit={handleSubmit} className="flex gap-2">
|
|
25
|
-
<
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
28
|
+
<div className="relative flex-1">
|
|
29
|
+
<label htmlFor="account-search-input" className="sr-only">
|
|
30
|
+
Search accounts
|
|
31
|
+
</label>
|
|
32
|
+
<Search
|
|
33
|
+
aria-hidden="true"
|
|
34
|
+
className="absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-muted-foreground"
|
|
35
|
+
/>
|
|
36
|
+
<Input
|
|
37
|
+
id="account-search-input"
|
|
38
|
+
type="text"
|
|
39
|
+
value={text}
|
|
40
|
+
onChange={(e) => setText(e.target.value)}
|
|
41
|
+
placeholder="Search by name, phone, or industry..."
|
|
42
|
+
className="pl-9"
|
|
43
|
+
/>
|
|
44
|
+
</div>
|
|
30
45
|
<Button type="submit">Search</Button>
|
|
31
46
|
</form>
|
|
32
47
|
</div>
|
|
@@ -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 TestChatPage from "./pages/TestChatPage";
|
|
13
|
+
import AuthAppLayout from "./features/authentication/layouts/AuthAppLayout";
|
|
12
14
|
import AccountSearch from "./pages/AccountSearch";
|
|
13
15
|
import AccountObjectDetail from "./pages/AccountObjectDetailPage";
|
|
14
|
-
import AuthAppLayout from "./features/authentication/layouts/AuthAppLayout";
|
|
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,6 +59,11 @@ export const routes: RouteObject[] = [
|
|
|
62
59
|
}
|
|
63
60
|
]
|
|
64
61
|
},
|
|
62
|
+
{
|
|
63
|
+
path: "test-chat",
|
|
64
|
+
element: <TestChatPage />,
|
|
65
|
+
handle: { showInNavigation: true, label: "Test Chat" }
|
|
66
|
+
},
|
|
65
67
|
{
|
|
66
68
|
path: "accounts/:recordId",
|
|
67
69
|
element: <AccountObjectDetail />
|
|
@@ -69,6 +71,10 @@ export const routes: RouteObject[] = [
|
|
|
69
71
|
{
|
|
70
72
|
path: "accounts",
|
|
71
73
|
element: <AccountSearch />
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
path: '*',
|
|
77
|
+
element: <NotFound />
|
|
72
78
|
}
|
|
73
79
|
]
|
|
74
80
|
}
|
|
@@ -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
|
+
}
|
|
@@ -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/search/index.ts","./src/features/search/loadConfig.ts","./src/features/search/queryBuilder.ts","./src/features/search/types.ts","./src/features/search/api/distinctValuesService.ts","./src/features/search/api/searchService.ts","./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/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/DefaultResultRow.tsx","./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/AccountSearch.tsx","./src/pages/Home.tsx","./src/pages/NotFound.tsx","./src/pages/TestChatPage.tsx","./src/types/chat.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
|
+
}
|