@salesforce/templates 66.3.0 → 66.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/templates/flexipage/RecordPage/_flexipage.flexipage-meta.xml +0 -24
- package/lib/templates/project/reactb2e/.a4drules/{graphql.md → features/feature-graphql-graphql-data-access-rule.md} +186 -125
- package/lib/templates/project/reactb2e/.a4drules/features/feature-react-agentforce-conversation-client-embedded-agent-rule.md +32 -0
- package/lib/templates/project/reactb2e/.a4drules/features/feature-react-chart-analytics-charts-rule.md +27 -0
- package/lib/templates/project/reactb2e/.a4drules/skills/feature-graphql-graphql-data-access/SKILL.md +155 -0
- package/lib/templates/project/{reactb2x/.a4drules/graphql/tools/knowledge/lds-explore-graphql-schema.md → reactb2e/.a4drules/skills/feature-graphql-graphql-data-access/docs/explore-schema.md} +58 -29
- package/lib/templates/project/{reactb2x/.a4drules/graphql/tools/knowledge/lds-generate-graphql-mutationquery.md → reactb2e/.a4drules/skills/feature-graphql-graphql-data-access/docs/generate-mutation-query.md} +52 -42
- package/lib/templates/project/{reactb2x/.a4drules/graphql/tools/knowledge/lds-generate-graphql-readquery.md → reactb2e/.a4drules/skills/feature-graphql-graphql-data-access/docs/generate-read-query.md} +32 -22
- package/lib/templates/project/{reactb2x/.a4drules/graphql/tools/schemas/shared.graphqls → reactb2e/.a4drules/skills/feature-graphql-graphql-data-access/docs/shared-schema.graphqls} +1 -1
- package/lib/templates/project/reactb2e/.a4drules/skills/feature-micro-frontend-micro-frontend/SKILL.md +137 -0
- package/lib/templates/project/reactb2e/.a4drules/skills/feature-react-agentforce-conversation-client-embedded-agent/SKILL.md +108 -0
- package/lib/templates/project/reactb2e/.a4drules/skills/feature-react-agentforce-conversation-client-embedded-agent/docs/embed-examples.md +182 -0
- package/lib/templates/project/reactb2e/.a4drules/skills/feature-react-chart-analytics-charts/SKILL.md +41 -0
- package/lib/templates/project/reactb2e/.a4drules/skills/feature-react-chart-analytics-charts/docs/schema-mapping.md +4 -0
- package/lib/templates/project/reactb2e/.a4drules/webapp-code-quality.md +136 -0
- package/lib/templates/project/reactb2e/.a4drules/{images.md → webapp-images.md} +6 -4
- package/lib/templates/project/reactb2e/.a4drules/webapp-no-node-e.md +3 -2
- package/lib/templates/project/reactb2e/.a4drules/webapp-react.md +149 -0
- package/lib/templates/project/reactb2e/.a4drules/{typescript.md → webapp-typescript.md} +10 -29
- package/lib/templates/project/reactb2e/.a4drules/webapp.md +60 -45
- package/lib/templates/project/reactb2e/AGENT.md +1 -1
- package/lib/templates/project/reactb2e/CHANGELOG.md +377 -0
- package/lib/templates/project/reactb2e/README.md +38 -4
- package/lib/templates/project/reactb2e/force-app/main/default/webapplications/appreacttemplateb2e/CHANGELOG.md +10 -0
- package/lib/templates/project/reactb2e/force-app/main/default/webapplications/appreacttemplateb2e/README.md +35 -0
- package/lib/templates/project/reactb2e/force-app/main/default/webapplications/appreacttemplateb2e/package.json +17 -7
- package/lib/templates/project/reactb2e/force-app/main/default/webapplications/appreacttemplateb2e/src/appLayout.tsx +76 -10
- package/lib/templates/project/reactb2e/force-app/main/default/webapplications/appreacttemplateb2e/src/components/__inherit_AgentforceConversationClient.tsx +3 -0
- package/lib/templates/project/reactb2e/force-app/main/default/webapplications/appreacttemplateb2e/src/components/alerts/status-alert.tsx +49 -0
- package/lib/templates/project/reactb2e/force-app/main/default/webapplications/appreacttemplateb2e/src/components/layouts/card-layout.tsx +29 -0
- package/lib/templates/project/reactb2e/force-app/main/default/webapplications/appreacttemplateb2e/src/components/ui/alert.tsx +76 -0
- package/lib/templates/project/reactb2e/force-app/main/default/webapplications/appreacttemplateb2e/src/components/ui/button.tsx +67 -0
- package/lib/templates/project/reactb2e/force-app/main/default/webapplications/appreacttemplateb2e/src/components/ui/card.tsx +103 -0
- package/lib/templates/project/reactb2e/force-app/main/default/webapplications/appreacttemplateb2e/src/components/ui/dialog.tsx +162 -0
- package/lib/templates/project/reactb2e/force-app/main/default/webapplications/appreacttemplateb2e/src/components/ui/field.tsx +237 -0
- package/lib/templates/project/reactb2e/force-app/main/default/webapplications/appreacttemplateb2e/src/components/ui/index.ts +84 -0
- package/lib/templates/project/reactb2e/force-app/main/default/webapplications/appreacttemplateb2e/src/components/ui/input.tsx +19 -0
- package/lib/templates/project/reactb2e/force-app/main/default/webapplications/appreacttemplateb2e/src/components/ui/label.tsx +22 -0
- package/lib/templates/project/reactb2e/force-app/main/default/webapplications/appreacttemplateb2e/src/components/ui/pagination.tsx +132 -0
- package/lib/templates/project/reactb2e/force-app/main/default/webapplications/appreacttemplateb2e/src/components/ui/select.tsx +193 -0
- package/lib/templates/project/reactb2e/force-app/main/default/webapplications/appreacttemplateb2e/src/components/ui/separator.tsx +26 -0
- package/lib/templates/project/reactb2e/force-app/main/default/webapplications/appreacttemplateb2e/src/components/ui/skeleton.tsx +14 -0
- package/lib/templates/project/reactb2e/force-app/main/default/webapplications/appreacttemplateb2e/src/components/ui/spinner.tsx +16 -0
- package/lib/templates/project/reactb2e/force-app/main/default/webapplications/appreacttemplateb2e/src/components/ui/table.tsx +114 -0
- package/lib/templates/project/reactb2e/force-app/main/default/webapplications/appreacttemplateb2e/src/components/ui/tabs.tsx +88 -0
- package/lib/templates/project/reactb2e/force-app/main/default/webapplications/appreacttemplateb2e/src/components.json +18 -0
- package/lib/templates/project/reactb2e/force-app/main/default/webapplications/appreacttemplateb2e/src/constants.ts +39 -0
- package/lib/templates/project/reactb2e/force-app/main/default/webapplications/appreacttemplateb2e/src/features/global-search/api/index.ts +19 -0
- package/lib/templates/project/reactb2e/force-app/main/default/webapplications/appreacttemplateb2e/src/features/global-search/api/objectDetailService.ts +125 -0
- package/lib/templates/project/reactb2e/force-app/main/default/webapplications/appreacttemplateb2e/src/features/global-search/api/objectInfoGraphQLService.ts +194 -0
- package/lib/templates/project/reactb2e/force-app/main/default/webapplications/appreacttemplateb2e/src/features/global-search/api/objectInfoService.ts +199 -0
- package/lib/templates/project/reactb2e/force-app/main/default/webapplications/appreacttemplateb2e/src/features/global-search/api/recordListGraphQLService.ts +365 -0
- package/lib/templates/project/reactb2e/force-app/main/default/webapplications/appreacttemplateb2e/src/features/global-search/components/detail/DetailFields.tsx +55 -0
- package/lib/templates/project/reactb2e/force-app/main/default/webapplications/appreacttemplateb2e/src/features/global-search/components/detail/DetailForm.tsx +146 -0
- package/lib/templates/project/reactb2e/force-app/main/default/webapplications/appreacttemplateb2e/src/features/global-search/components/detail/DetailHeader.tsx +34 -0
- package/lib/templates/project/reactb2e/force-app/main/default/webapplications/appreacttemplateb2e/src/features/global-search/components/detail/DetailLayoutSections.tsx +80 -0
- package/lib/templates/project/reactb2e/force-app/main/default/webapplications/appreacttemplateb2e/src/features/global-search/components/detail/Section.tsx +108 -0
- package/lib/templates/project/reactb2e/force-app/main/default/webapplications/appreacttemplateb2e/src/features/global-search/components/detail/SectionRow.tsx +20 -0
- package/lib/templates/project/reactb2e/force-app/main/default/webapplications/appreacttemplateb2e/src/features/global-search/components/detail/UiApiDetailForm.tsx +140 -0
- package/lib/templates/project/reactb2e/force-app/main/default/webapplications/appreacttemplateb2e/src/features/global-search/components/detail/formatted/FieldValueDisplay.tsx +73 -0
- package/lib/templates/project/reactb2e/force-app/main/default/webapplications/appreacttemplateb2e/src/features/global-search/components/detail/formatted/FormattedAddress.tsx +29 -0
- package/lib/templates/project/reactb2e/force-app/main/default/webapplications/appreacttemplateb2e/src/features/global-search/components/detail/formatted/FormattedEmail.tsx +17 -0
- package/lib/templates/project/reactb2e/force-app/main/default/webapplications/appreacttemplateb2e/src/features/global-search/components/detail/formatted/FormattedPhone.tsx +24 -0
- package/lib/templates/project/reactb2e/force-app/main/default/webapplications/appreacttemplateb2e/src/features/global-search/components/detail/formatted/FormattedText.tsx +11 -0
- package/lib/templates/project/reactb2e/force-app/main/default/webapplications/appreacttemplateb2e/src/features/global-search/components/detail/formatted/FormattedUrl.tsx +29 -0
- package/lib/templates/project/reactb2e/force-app/main/default/webapplications/appreacttemplateb2e/src/features/global-search/components/detail/formatted/index.ts +6 -0
- package/lib/templates/project/reactb2e/force-app/main/default/webapplications/appreacttemplateb2e/src/features/global-search/components/filters/FilterField.tsx +54 -0
- package/lib/templates/project/reactb2e/force-app/main/default/webapplications/appreacttemplateb2e/src/features/global-search/components/filters/FilterInput.tsx +55 -0
- package/lib/templates/project/reactb2e/force-app/main/default/webapplications/appreacttemplateb2e/src/features/global-search/components/filters/FilterSelect.tsx +72 -0
- package/lib/templates/project/reactb2e/force-app/main/default/webapplications/appreacttemplateb2e/src/features/global-search/components/filters/FiltersPanel.tsx +380 -0
- package/lib/templates/project/reactb2e/force-app/main/default/webapplications/appreacttemplateb2e/src/features/global-search/components/forms/filters-form.tsx +114 -0
- package/lib/templates/project/reactb2e/force-app/main/default/webapplications/appreacttemplateb2e/src/features/global-search/components/forms/submit-button.tsx +47 -0
- package/lib/templates/project/reactb2e/force-app/main/default/webapplications/appreacttemplateb2e/src/features/global-search/components/search/GlobalSearchInput.tsx +114 -0
- package/lib/templates/project/reactb2e/force-app/main/default/webapplications/appreacttemplateb2e/src/features/global-search/components/search/ResultCardFields.tsx +71 -0
- package/lib/templates/project/reactb2e/force-app/main/default/webapplications/appreacttemplateb2e/src/features/global-search/components/search/SearchHeader.tsx +31 -0
- package/lib/templates/project/reactb2e/force-app/main/default/webapplications/appreacttemplateb2e/src/features/global-search/components/search/SearchPagination.tsx +144 -0
- package/lib/templates/project/reactb2e/force-app/main/default/webapplications/appreacttemplateb2e/src/features/global-search/components/search/SearchResultCard.tsx +136 -0
- package/lib/templates/project/reactb2e/force-app/main/default/webapplications/appreacttemplateb2e/src/features/global-search/components/search/SearchResultsPanel.tsx +197 -0
- package/lib/templates/project/reactb2e/force-app/main/default/webapplications/appreacttemplateb2e/src/features/global-search/components/shared/LoadingFallback.tsx +61 -0
- package/lib/templates/project/reactb2e/force-app/main/default/webapplications/appreacttemplateb2e/src/features/global-search/filters/FilterInput.tsx +55 -0
- package/lib/templates/project/reactb2e/force-app/main/default/webapplications/appreacttemplateb2e/src/features/global-search/filters/FilterSelect.tsx +72 -0
- package/lib/templates/project/reactb2e/force-app/main/default/webapplications/appreacttemplateb2e/src/features/global-search/hooks/form.tsx +209 -0
- package/lib/templates/project/reactb2e/force-app/main/default/webapplications/appreacttemplateb2e/src/features/global-search/hooks/index.ts +22 -0
- package/lib/templates/project/reactb2e/force-app/main/default/webapplications/appreacttemplateb2e/src/features/global-search/hooks/useObjectInfoBatch.ts +65 -0
- package/lib/templates/project/reactb2e/force-app/main/default/webapplications/appreacttemplateb2e/src/features/global-search/hooks/useObjectSearchData.ts +395 -0
- package/lib/templates/project/reactb2e/force-app/main/default/webapplications/appreacttemplateb2e/src/features/global-search/hooks/useRecordDetailLayout.ts +156 -0
- package/lib/templates/project/reactb2e/force-app/main/default/webapplications/appreacttemplateb2e/src/features/global-search/hooks/useRecordListGraphQL.ts +135 -0
- package/lib/templates/project/reactb2e/force-app/main/default/webapplications/appreacttemplateb2e/src/features/global-search/pages/DetailPage.tsx +109 -0
- package/lib/templates/project/reactb2e/force-app/main/default/webapplications/appreacttemplateb2e/src/features/global-search/pages/GlobalSearch.tsx +229 -0
- package/lib/templates/project/reactb2e/force-app/main/default/webapplications/appreacttemplateb2e/src/features/global-search/types/filters/filters.ts +120 -0
- package/lib/templates/project/reactb2e/force-app/main/default/webapplications/appreacttemplateb2e/src/features/global-search/types/filters/picklist.ts +32 -0
- package/lib/templates/project/reactb2e/force-app/main/default/webapplications/appreacttemplateb2e/src/features/global-search/types/index.ts +4 -0
- package/lib/templates/project/reactb2e/force-app/main/default/webapplications/appreacttemplateb2e/src/features/global-search/types/objectInfo/objectInfo.ts +166 -0
- package/lib/templates/project/reactb2e/force-app/main/default/webapplications/appreacttemplateb2e/src/features/global-search/types/recordDetail/recordDetail.ts +61 -0
- package/lib/templates/project/reactb2e/force-app/main/default/webapplications/appreacttemplateb2e/src/features/global-search/types/search/searchResults.ts +229 -0
- package/lib/templates/project/reactb2e/force-app/main/default/webapplications/appreacttemplateb2e/src/features/global-search/utils/apiUtils.ts +125 -0
- package/lib/templates/project/reactb2e/force-app/main/default/webapplications/appreacttemplateb2e/src/features/global-search/utils/cacheUtils.ts +76 -0
- package/lib/templates/project/reactb2e/force-app/main/default/webapplications/appreacttemplateb2e/src/features/global-search/utils/debounce.ts +89 -0
- package/lib/templates/project/reactb2e/force-app/main/default/webapplications/appreacttemplateb2e/src/features/global-search/utils/fieldUtils.ts +354 -0
- package/lib/templates/project/reactb2e/force-app/main/default/webapplications/appreacttemplateb2e/src/features/global-search/utils/fieldValueExtractor.ts +67 -0
- package/lib/templates/project/reactb2e/force-app/main/default/webapplications/appreacttemplateb2e/src/features/global-search/utils/filterUtils.ts +32 -0
- package/lib/templates/project/reactb2e/force-app/main/default/webapplications/appreacttemplateb2e/src/features/global-search/utils/formDataTransformUtils.ts +260 -0
- package/lib/templates/project/reactb2e/force-app/main/default/webapplications/appreacttemplateb2e/src/features/global-search/utils/formUtils.ts +142 -0
- package/lib/templates/project/reactb2e/force-app/main/default/webapplications/appreacttemplateb2e/src/features/global-search/utils/graphQLNodeFieldUtils.ts +186 -0
- package/lib/templates/project/reactb2e/force-app/main/default/webapplications/appreacttemplateb2e/src/features/global-search/utils/graphQLObjectInfoAdapter.ts +319 -0
- package/lib/templates/project/reactb2e/force-app/main/default/webapplications/appreacttemplateb2e/src/features/global-search/utils/graphQLRecordAdapter.ts +90 -0
- package/lib/templates/project/reactb2e/force-app/main/default/webapplications/appreacttemplateb2e/src/features/global-search/utils/index.ts +59 -0
- package/lib/templates/project/reactb2e/force-app/main/default/webapplications/appreacttemplateb2e/src/features/global-search/utils/layoutTransformUtils.ts +236 -0
- package/lib/templates/project/reactb2e/force-app/main/default/webapplications/appreacttemplateb2e/src/features/global-search/utils/linkUtils.ts +14 -0
- package/lib/templates/project/reactb2e/force-app/main/default/webapplications/appreacttemplateb2e/src/features/global-search/utils/paginationUtils.ts +49 -0
- package/lib/templates/project/reactb2e/force-app/main/default/webapplications/appreacttemplateb2e/src/features/global-search/utils/recordUtils.ts +159 -0
- package/lib/templates/project/reactb2e/force-app/main/default/webapplications/appreacttemplateb2e/src/features/global-search/utils/sanitizationUtils.ts +49 -0
- package/lib/templates/project/reactb2e/force-app/main/default/webapplications/appreacttemplateb2e/src/lib/utils.ts +6 -0
- package/lib/templates/project/reactb2e/force-app/main/default/webapplications/appreacttemplateb2e/src/pages/Home.tsx +11 -10
- package/lib/templates/project/reactb2e/force-app/main/default/webapplications/appreacttemplateb2e/src/pages/TestAccPage.tsx +19 -0
- package/lib/templates/project/reactb2e/force-app/main/default/webapplications/appreacttemplateb2e/src/routes.tsx +28 -0
- package/lib/templates/project/reactb2e/force-app/main/default/webapplications/appreacttemplateb2e/src/styles/global.css +122 -0
- package/lib/templates/project/reactb2e/force-app/main/default/webapplications/appreacttemplateb2e/vite.config.ts +2 -1
- package/lib/templates/project/reactb2e/package.json +1 -1
- package/lib/templates/project/reactb2x/.a4drules/{graphql.md → features/feature-graphql-graphql-data-access-rule.md} +186 -125
- package/lib/templates/project/reactb2x/.a4drules/features/feature-react-agentforce-conversation-client-embedded-agent-rule.md +32 -0
- package/lib/templates/project/reactb2x/.a4drules/features/feature-react-chart-analytics-charts-rule.md +27 -0
- package/lib/templates/project/reactb2x/.a4drules/skills/feature-graphql-graphql-data-access/SKILL.md +155 -0
- package/lib/templates/project/{reactb2e/.a4drules/graphql/tools/knowledge/lds-explore-graphql-schema.md → reactb2x/.a4drules/skills/feature-graphql-graphql-data-access/docs/explore-schema.md} +58 -29
- package/lib/templates/project/{reactb2e/.a4drules/graphql/tools/knowledge/lds-generate-graphql-mutationquery.md → reactb2x/.a4drules/skills/feature-graphql-graphql-data-access/docs/generate-mutation-query.md} +52 -42
- package/lib/templates/project/{reactb2e/.a4drules/graphql/tools/knowledge/lds-generate-graphql-readquery.md → reactb2x/.a4drules/skills/feature-graphql-graphql-data-access/docs/generate-read-query.md} +32 -22
- package/lib/templates/project/{reactb2e/.a4drules/graphql/tools/schemas/shared.graphqls → reactb2x/.a4drules/skills/feature-graphql-graphql-data-access/docs/shared-schema.graphqls} +1 -1
- package/lib/templates/project/reactb2x/.a4drules/skills/feature-micro-frontend-micro-frontend/SKILL.md +137 -0
- package/lib/templates/project/reactb2x/.a4drules/skills/feature-react-agentforce-conversation-client-embedded-agent/SKILL.md +108 -0
- package/lib/templates/project/reactb2x/.a4drules/skills/feature-react-agentforce-conversation-client-embedded-agent/docs/embed-examples.md +182 -0
- package/lib/templates/project/reactb2x/.a4drules/skills/feature-react-chart-analytics-charts/SKILL.md +41 -0
- package/lib/templates/project/reactb2x/.a4drules/skills/feature-react-chart-analytics-charts/docs/schema-mapping.md +4 -0
- package/lib/templates/project/reactb2x/.a4drules/webapp-code-quality.md +136 -0
- package/lib/templates/project/reactb2x/.a4drules/{images.md → webapp-images.md} +6 -4
- package/lib/templates/project/reactb2x/.a4drules/webapp-no-node-e.md +3 -2
- package/lib/templates/project/reactb2x/.a4drules/webapp-react.md +149 -0
- package/lib/templates/project/reactb2x/.a4drules/{typescript.md → webapp-typescript.md} +10 -29
- package/lib/templates/project/reactb2x/.a4drules/webapp.md +60 -45
- package/lib/templates/project/reactb2x/AGENT.md +1 -1
- package/lib/templates/project/reactb2x/CHANGELOG.md +377 -0
- package/lib/templates/project/reactb2x/README.md +58 -4
- package/lib/templates/project/reactb2x/force-app/main/default/webapplications/appreacttemplateb2x/CHANGELOG.md +10 -0
- package/lib/templates/project/reactb2x/force-app/main/default/webapplications/appreacttemplateb2x/README.md +35 -0
- package/lib/templates/project/reactb2x/force-app/main/default/webapplications/appreacttemplateb2x/package.json +8 -7
- package/lib/templates/project/reactb2x/force-app/main/default/webapplications/appreacttemplateb2x/src/appLayout.tsx +75 -3
- package/lib/templates/project/reactb2x/force-app/main/default/webapplications/appreacttemplateb2x/src/components/alerts/status-alert.tsx +36 -32
- package/lib/templates/project/reactb2x/force-app/main/default/webapplications/appreacttemplateb2x/src/components/layouts/card-layout.tsx +29 -0
- package/lib/templates/project/reactb2x/force-app/main/default/webapplications/appreacttemplateb2x/src/components/ui/alert.tsx +61 -54
- package/lib/templates/project/reactb2x/force-app/main/default/webapplications/appreacttemplateb2x/src/components/ui/button.tsx +57 -57
- package/lib/templates/project/reactb2x/force-app/main/default/webapplications/appreacttemplateb2x/src/components/ui/card.tsx +86 -75
- package/lib/templates/project/reactb2x/force-app/main/default/webapplications/appreacttemplateb2x/src/components/ui/dialog.tsx +129 -110
- package/lib/templates/project/reactb2x/force-app/main/default/webapplications/appreacttemplateb2x/src/components/ui/field.tsx +208 -193
- package/lib/templates/project/reactb2x/force-app/main/default/webapplications/appreacttemplateb2x/src/components/ui/index.ts +65 -53
- package/lib/templates/project/reactb2x/force-app/main/default/webapplications/appreacttemplateb2x/src/components/ui/input.tsx +14 -14
- package/lib/templates/project/reactb2x/force-app/main/default/webapplications/appreacttemplateb2x/src/components/ui/label.tsx +17 -14
- package/lib/templates/project/reactb2x/force-app/main/default/webapplications/appreacttemplateb2x/src/components/ui/pagination.tsx +108 -88
- package/lib/templates/project/reactb2x/force-app/main/default/webapplications/appreacttemplateb2x/src/components/ui/select.tsx +156 -146
- package/lib/templates/project/reactb2x/force-app/main/default/webapplications/appreacttemplateb2x/src/components/ui/separator.tsx +19 -19
- package/lib/templates/project/reactb2x/force-app/main/default/webapplications/appreacttemplateb2x/src/components/ui/skeleton.tsx +10 -10
- package/lib/templates/project/reactb2x/force-app/main/default/webapplications/appreacttemplateb2x/src/components/ui/spinner.tsx +12 -11
- package/lib/templates/project/reactb2x/force-app/main/default/webapplications/appreacttemplateb2x/src/components/ui/table.tsx +96 -69
- package/lib/templates/project/reactb2x/force-app/main/default/webapplications/appreacttemplateb2x/src/components/ui/tabs.tsx +71 -61
- package/lib/templates/project/reactb2x/force-app/main/default/webapplications/appreacttemplateb2x/src/components.json +1 -1
- package/lib/templates/project/reactb2x/force-app/main/default/webapplications/appreacttemplateb2x/src/constants.ts +39 -0
- package/lib/templates/project/reactb2x/force-app/main/default/webapplications/appreacttemplateb2x/src/{context → features/authentication/context}/AuthContext.tsx +1 -1
- package/lib/templates/project/reactb2x/force-app/main/default/webapplications/appreacttemplateb2x/src/{components → features/authentication}/footers/footer-link.tsx +1 -1
- package/lib/templates/project/reactb2x/force-app/main/default/webapplications/appreacttemplateb2x/src/{components → features/authentication}/forms/auth-form.tsx +4 -4
- package/lib/templates/project/reactb2x/force-app/main/default/webapplications/appreacttemplateb2x/src/{components → features/authentication}/forms/submit-button.tsx +4 -4
- package/lib/templates/project/reactb2x/force-app/main/default/webapplications/appreacttemplateb2x/src/{hooks → features/authentication/hooks}/form.tsx +13 -9
- package/lib/templates/project/reactb2x/force-app/main/default/webapplications/appreacttemplateb2x/src/{components → features/authentication}/layout/card-skeleton.tsx +2 -2
- package/lib/templates/project/reactb2x/force-app/main/default/webapplications/appreacttemplateb2x/src/{components → features/authentication}/layout/centered-page-layout.tsx +2 -3
- package/lib/templates/project/reactb2x/force-app/main/default/webapplications/appreacttemplateb2x/src/{layouts → features/authentication/layouts}/AuthAppLayout.tsx +2 -2
- package/lib/templates/project/reactb2x/force-app/main/default/webapplications/appreacttemplateb2x/src/{components/auth → features/authentication/layouts}/authenticationRouteLayout.tsx +2 -2
- package/lib/templates/project/reactb2x/force-app/main/default/webapplications/appreacttemplateb2x/src/{components/auth → features/authentication/layouts}/privateRouteLayout.tsx +2 -2
- package/lib/templates/project/reactb2x/force-app/main/default/webapplications/appreacttemplateb2x/src/{pages → features/authentication/pages}/ChangePassword.tsx +6 -6
- package/lib/templates/project/reactb2x/force-app/main/default/webapplications/appreacttemplateb2x/src/{pages → features/authentication/pages}/ForgotPassword.tsx +5 -5
- package/lib/templates/project/reactb2x/force-app/main/default/webapplications/appreacttemplateb2x/src/{pages → features/authentication/pages}/Login.tsx +6 -6
- package/lib/templates/project/reactb2x/force-app/main/default/webapplications/appreacttemplateb2x/src/{pages → features/authentication/pages}/Profile.tsx +22 -13
- package/lib/templates/project/reactb2x/force-app/main/default/webapplications/appreacttemplateb2x/src/{pages → features/authentication/pages}/Register.tsx +6 -11
- package/lib/templates/project/reactb2x/force-app/main/default/webapplications/appreacttemplateb2x/src/{pages → features/authentication/pages}/ResetPassword.tsx +8 -8
- package/lib/templates/project/reactb2x/force-app/main/default/webapplications/appreacttemplateb2x/src/{components/auth → features/authentication}/sessionTimeout/SessionTimeoutValidator.tsx +6 -6
- package/lib/templates/project/reactb2x/force-app/main/default/webapplications/appreacttemplateb2x/src/features/global-search/api/index.ts +19 -0
- package/lib/templates/project/reactb2x/force-app/main/default/webapplications/appreacttemplateb2x/src/features/global-search/api/objectDetailService.ts +125 -0
- package/lib/templates/project/reactb2x/force-app/main/default/webapplications/appreacttemplateb2x/src/features/global-search/api/objectInfoGraphQLService.ts +194 -0
- package/lib/templates/project/reactb2x/force-app/main/default/webapplications/appreacttemplateb2x/src/features/global-search/api/objectInfoService.ts +199 -0
- package/lib/templates/project/reactb2x/force-app/main/default/webapplications/appreacttemplateb2x/src/features/global-search/api/recordListGraphQLService.ts +365 -0
- package/lib/templates/project/reactb2x/force-app/main/default/webapplications/appreacttemplateb2x/src/features/global-search/components/detail/DetailFields.tsx +55 -0
- package/lib/templates/project/reactb2x/force-app/main/default/webapplications/appreacttemplateb2x/src/features/global-search/components/detail/DetailForm.tsx +146 -0
- package/lib/templates/project/reactb2x/force-app/main/default/webapplications/appreacttemplateb2x/src/features/global-search/components/detail/DetailHeader.tsx +34 -0
- package/lib/templates/project/reactb2x/force-app/main/default/webapplications/appreacttemplateb2x/src/features/global-search/components/detail/DetailLayoutSections.tsx +80 -0
- package/lib/templates/project/reactb2x/force-app/main/default/webapplications/appreacttemplateb2x/src/features/global-search/components/detail/Section.tsx +108 -0
- package/lib/templates/project/reactb2x/force-app/main/default/webapplications/appreacttemplateb2x/src/features/global-search/components/detail/SectionRow.tsx +20 -0
- package/lib/templates/project/reactb2x/force-app/main/default/webapplications/appreacttemplateb2x/src/features/global-search/components/detail/UiApiDetailForm.tsx +140 -0
- package/lib/templates/project/reactb2x/force-app/main/default/webapplications/appreacttemplateb2x/src/features/global-search/components/detail/formatted/FieldValueDisplay.tsx +73 -0
- package/lib/templates/project/reactb2x/force-app/main/default/webapplications/appreacttemplateb2x/src/features/global-search/components/detail/formatted/FormattedAddress.tsx +29 -0
- package/lib/templates/project/reactb2x/force-app/main/default/webapplications/appreacttemplateb2x/src/features/global-search/components/detail/formatted/FormattedEmail.tsx +17 -0
- package/lib/templates/project/reactb2x/force-app/main/default/webapplications/appreacttemplateb2x/src/features/global-search/components/detail/formatted/FormattedPhone.tsx +24 -0
- package/lib/templates/project/reactb2x/force-app/main/default/webapplications/appreacttemplateb2x/src/features/global-search/components/detail/formatted/FormattedText.tsx +11 -0
- package/lib/templates/project/reactb2x/force-app/main/default/webapplications/appreacttemplateb2x/src/features/global-search/components/detail/formatted/FormattedUrl.tsx +29 -0
- package/lib/templates/project/reactb2x/force-app/main/default/webapplications/appreacttemplateb2x/src/features/global-search/components/detail/formatted/index.ts +6 -0
- package/lib/templates/project/reactb2x/force-app/main/default/webapplications/appreacttemplateb2x/src/features/global-search/components/filters/FilterField.tsx +54 -0
- package/lib/templates/project/reactb2x/force-app/main/default/webapplications/appreacttemplateb2x/src/features/global-search/components/filters/FilterInput.tsx +55 -0
- package/lib/templates/project/reactb2x/force-app/main/default/webapplications/appreacttemplateb2x/src/features/global-search/components/filters/FilterSelect.tsx +72 -0
- package/lib/templates/project/reactb2x/force-app/main/default/webapplications/appreacttemplateb2x/src/features/global-search/components/filters/FiltersPanel.tsx +380 -0
- package/lib/templates/project/reactb2x/force-app/main/default/webapplications/appreacttemplateb2x/src/features/global-search/components/forms/filters-form.tsx +114 -0
- package/lib/templates/project/reactb2x/force-app/main/default/webapplications/appreacttemplateb2x/src/features/global-search/components/forms/submit-button.tsx +47 -0
- package/lib/templates/project/reactb2x/force-app/main/default/webapplications/appreacttemplateb2x/src/features/global-search/components/search/GlobalSearchInput.tsx +114 -0
- package/lib/templates/project/reactb2x/force-app/main/default/webapplications/appreacttemplateb2x/src/features/global-search/components/search/ResultCardFields.tsx +71 -0
- package/lib/templates/project/reactb2x/force-app/main/default/webapplications/appreacttemplateb2x/src/features/global-search/components/search/SearchHeader.tsx +31 -0
- package/lib/templates/project/reactb2x/force-app/main/default/webapplications/appreacttemplateb2x/src/features/global-search/components/search/SearchPagination.tsx +144 -0
- package/lib/templates/project/reactb2x/force-app/main/default/webapplications/appreacttemplateb2x/src/features/global-search/components/search/SearchResultCard.tsx +136 -0
- package/lib/templates/project/reactb2x/force-app/main/default/webapplications/appreacttemplateb2x/src/features/global-search/components/search/SearchResultsPanel.tsx +197 -0
- package/lib/templates/project/reactb2x/force-app/main/default/webapplications/appreacttemplateb2x/src/features/global-search/components/shared/LoadingFallback.tsx +61 -0
- package/lib/templates/project/reactb2x/force-app/main/default/webapplications/appreacttemplateb2x/src/features/global-search/filters/FilterInput.tsx +55 -0
- package/lib/templates/project/reactb2x/force-app/main/default/webapplications/appreacttemplateb2x/src/features/global-search/filters/FilterSelect.tsx +72 -0
- package/lib/templates/project/reactb2x/force-app/main/default/webapplications/appreacttemplateb2x/src/features/global-search/hooks/form.tsx +209 -0
- package/lib/templates/project/reactb2x/force-app/main/default/webapplications/appreacttemplateb2x/src/features/global-search/hooks/index.ts +22 -0
- package/lib/templates/project/reactb2x/force-app/main/default/webapplications/appreacttemplateb2x/src/features/global-search/hooks/useObjectInfoBatch.ts +65 -0
- package/lib/templates/project/reactb2x/force-app/main/default/webapplications/appreacttemplateb2x/src/features/global-search/hooks/useObjectSearchData.ts +395 -0
- package/lib/templates/project/reactb2x/force-app/main/default/webapplications/appreacttemplateb2x/src/features/global-search/hooks/useRecordDetailLayout.ts +156 -0
- package/lib/templates/project/reactb2x/force-app/main/default/webapplications/appreacttemplateb2x/src/features/global-search/hooks/useRecordListGraphQL.ts +135 -0
- package/lib/templates/project/reactb2x/force-app/main/default/webapplications/appreacttemplateb2x/src/features/global-search/pages/DetailPage.tsx +109 -0
- package/lib/templates/project/reactb2x/force-app/main/default/webapplications/appreacttemplateb2x/src/features/global-search/pages/GlobalSearch.tsx +229 -0
- package/lib/templates/project/reactb2x/force-app/main/default/webapplications/appreacttemplateb2x/src/features/global-search/types/filters/filters.ts +120 -0
- package/lib/templates/project/reactb2x/force-app/main/default/webapplications/appreacttemplateb2x/src/features/global-search/types/filters/picklist.ts +32 -0
- package/lib/templates/project/reactb2x/force-app/main/default/webapplications/appreacttemplateb2x/src/features/global-search/types/index.ts +4 -0
- package/lib/templates/project/reactb2x/force-app/main/default/webapplications/appreacttemplateb2x/src/features/global-search/types/objectInfo/objectInfo.ts +166 -0
- package/lib/templates/project/reactb2x/force-app/main/default/webapplications/appreacttemplateb2x/src/features/global-search/types/recordDetail/recordDetail.ts +61 -0
- package/lib/templates/project/reactb2x/force-app/main/default/webapplications/appreacttemplateb2x/src/features/global-search/types/search/searchResults.ts +229 -0
- package/lib/templates/project/reactb2x/force-app/main/default/webapplications/appreacttemplateb2x/src/features/global-search/utils/apiUtils.ts +125 -0
- package/lib/templates/project/reactb2x/force-app/main/default/webapplications/appreacttemplateb2x/src/features/global-search/utils/cacheUtils.ts +76 -0
- package/lib/templates/project/reactb2x/force-app/main/default/webapplications/appreacttemplateb2x/src/features/global-search/utils/debounce.ts +89 -0
- package/lib/templates/project/reactb2x/force-app/main/default/webapplications/appreacttemplateb2x/src/features/global-search/utils/fieldUtils.ts +354 -0
- package/lib/templates/project/reactb2x/force-app/main/default/webapplications/appreacttemplateb2x/src/features/global-search/utils/fieldValueExtractor.ts +67 -0
- package/lib/templates/project/reactb2x/force-app/main/default/webapplications/appreacttemplateb2x/src/features/global-search/utils/filterUtils.ts +32 -0
- package/lib/templates/project/reactb2x/force-app/main/default/webapplications/appreacttemplateb2x/src/features/global-search/utils/formDataTransformUtils.ts +260 -0
- package/lib/templates/project/reactb2x/force-app/main/default/webapplications/appreacttemplateb2x/src/features/global-search/utils/formUtils.ts +142 -0
- package/lib/templates/project/reactb2x/force-app/main/default/webapplications/appreacttemplateb2x/src/features/global-search/utils/graphQLNodeFieldUtils.ts +186 -0
- package/lib/templates/project/reactb2x/force-app/main/default/webapplications/appreacttemplateb2x/src/features/global-search/utils/graphQLObjectInfoAdapter.ts +319 -0
- package/lib/templates/project/reactb2x/force-app/main/default/webapplications/appreacttemplateb2x/src/features/global-search/utils/graphQLRecordAdapter.ts +90 -0
- package/lib/templates/project/reactb2x/force-app/main/default/webapplications/appreacttemplateb2x/src/features/global-search/utils/index.ts +59 -0
- package/lib/templates/project/reactb2x/force-app/main/default/webapplications/appreacttemplateb2x/src/features/global-search/utils/layoutTransformUtils.ts +236 -0
- package/lib/templates/project/reactb2x/force-app/main/default/webapplications/appreacttemplateb2x/src/features/global-search/utils/linkUtils.ts +14 -0
- package/lib/templates/project/reactb2x/force-app/main/default/webapplications/appreacttemplateb2x/src/features/global-search/utils/paginationUtils.ts +49 -0
- package/lib/templates/project/reactb2x/force-app/main/default/webapplications/appreacttemplateb2x/src/features/global-search/utils/recordUtils.ts +159 -0
- package/lib/templates/project/reactb2x/force-app/main/default/webapplications/appreacttemplateb2x/src/features/global-search/utils/sanitizationUtils.ts +49 -0
- package/lib/templates/project/reactb2x/force-app/main/default/webapplications/appreacttemplateb2x/src/lib/utils.ts +3 -3
- package/lib/templates/project/reactb2x/force-app/main/default/webapplications/appreacttemplateb2x/src/pages/Home.tsx +11 -10
- package/lib/templates/project/reactb2x/force-app/main/default/webapplications/appreacttemplateb2x/src/routes.tsx +33 -11
- package/lib/templates/project/reactb2x/force-app/main/default/webapplications/appreacttemplateb2x/src/styles/global.css +107 -107
- package/lib/templates/project/reactb2x/force-app/main/default/webapplications/appreacttemplateb2x/vite.config.ts +2 -1
- package/lib/templates/project/reactb2x/package.json +1 -1
- package/lib/templates/webapplication/reactbasic/CHANGELOG.md +10 -0
- package/lib/templates/webapplication/reactbasic/README.md +75 -0
- package/lib/templates/webapplication/reactbasic/package.json +13 -5
- package/lib/templates/webapplication/reactbasic/src/appLayout.tsx +75 -3
- package/lib/templates/webapplication/reactbasic/src/components/alerts/status-alert.tsx +49 -0
- package/lib/templates/webapplication/reactbasic/src/components/layouts/card-layout.tsx +29 -0
- package/lib/templates/webapplication/reactbasic/src/components/ui/alert.tsx +76 -0
- package/lib/templates/webapplication/reactbasic/src/components/ui/button.tsx +67 -0
- package/lib/templates/webapplication/reactbasic/src/components/ui/card.tsx +103 -0
- package/lib/templates/webapplication/reactbasic/src/components/ui/dialog.tsx +162 -0
- package/lib/templates/webapplication/reactbasic/src/components/ui/field.tsx +237 -0
- package/lib/templates/webapplication/reactbasic/src/components/ui/index.ts +84 -0
- package/lib/templates/webapplication/reactbasic/src/components/ui/input.tsx +19 -0
- package/lib/templates/webapplication/reactbasic/src/components/ui/label.tsx +22 -0
- package/lib/templates/webapplication/reactbasic/src/components/ui/pagination.tsx +132 -0
- package/lib/templates/webapplication/reactbasic/src/components/ui/select.tsx +193 -0
- package/lib/templates/webapplication/reactbasic/src/components/ui/separator.tsx +26 -0
- package/lib/templates/webapplication/reactbasic/src/components/ui/skeleton.tsx +14 -0
- package/lib/templates/webapplication/reactbasic/src/components/ui/spinner.tsx +16 -0
- package/lib/templates/webapplication/reactbasic/src/components/ui/table.tsx +114 -0
- package/lib/templates/webapplication/reactbasic/src/components/ui/tabs.tsx +88 -0
- package/lib/templates/webapplication/reactbasic/src/components.json +18 -0
- package/lib/templates/webapplication/reactbasic/src/lib/utils.ts +6 -0
- package/lib/templates/webapplication/reactbasic/src/styles/global.css +122 -0
- package/lib/templates/webapplication/reactbasic/vite.config.ts +2 -1
- package/lib/templates/webapplication/webappbasic/README.md +15 -0
- package/lib/utils/webappTemplateUtils.d.ts +10 -0
- package/lib/utils/webappTemplateUtils.js +55 -7
- package/lib/utils/webappTemplateUtils.js.map +1 -1
- package/package.json +5 -5
- package/lib/templates/project/reactb2e/.a4drules/README.md +0 -35
- package/lib/templates/project/reactb2e/.a4drules/a4d-webapp-generate.md +0 -27
- package/lib/templates/project/reactb2e/.a4drules/build-validation.md +0 -78
- package/lib/templates/project/reactb2e/.a4drules/code-quality.md +0 -137
- package/lib/templates/project/reactb2e/.a4drules/graphql/tools/knowledge/lds-guide-graphql.md +0 -205
- package/lib/templates/project/reactb2e/.a4drules/react.md +0 -387
- package/lib/templates/project/reactb2e/.a4drules/react_image_processing.md +0 -45
- package/lib/templates/project/reactb2e/.a4drules/ui-layout.md +0 -23
- package/lib/templates/project/reactb2e/.a4drules/webapp-nav-and-placeholders.md +0 -33
- package/lib/templates/project/reactb2e/.a4drules/webapp-ui-first.md +0 -32
- package/lib/templates/project/reactb2e/force-app/main/default/webapplications/appreacttemplateb2e/build/vite.config.d.ts +0 -2
- package/lib/templates/project/reactb2e/force-app/main/default/webapplications/appreacttemplateb2e/build/vite.config.js +0 -93
- package/lib/templates/project/reactb2e/force-app/main/default/webapplications/appreacttemplateb2e/package-lock.json +0 -14392
- package/lib/templates/project/reactb2e/force-app/main/default/webapplications/appreacttemplateb2e/src/api/graphql-operations-types.ts +0 -116
- package/lib/templates/project/reactb2e/force-app/main/default/webapplications/appreacttemplateb2e/src/api/utils/accounts.ts +0 -33
- package/lib/templates/project/reactb2e/force-app/main/default/webapplications/appreacttemplateb2e/src/api/utils/query/highRevenueAccountsQuery.graphql +0 -29
- package/lib/templates/project/reactb2x/.a4drules/README.md +0 -35
- package/lib/templates/project/reactb2x/.a4drules/a4d-webapp-generate.md +0 -27
- package/lib/templates/project/reactb2x/.a4drules/build-validation.md +0 -78
- package/lib/templates/project/reactb2x/.a4drules/code-quality.md +0 -137
- package/lib/templates/project/reactb2x/.a4drules/graphql/tools/knowledge/lds-guide-graphql.md +0 -205
- package/lib/templates/project/reactb2x/.a4drules/react.md +0 -387
- package/lib/templates/project/reactb2x/.a4drules/react_image_processing.md +0 -45
- package/lib/templates/project/reactb2x/.a4drules/ui-layout.md +0 -23
- package/lib/templates/project/reactb2x/.a4drules/webapp-nav-and-placeholders.md +0 -33
- package/lib/templates/project/reactb2x/.a4drules/webapp-ui-first.md +0 -32
- package/lib/templates/project/reactb2x/force-app/main/default/webapplications/appreacttemplateb2x/build/vite.config.d.ts +0 -2
- package/lib/templates/project/reactb2x/force-app/main/default/webapplications/appreacttemplateb2x/build/vite.config.js +0 -93
- package/lib/templates/project/reactb2x/force-app/main/default/webapplications/appreacttemplateb2x/package-lock.json +0 -18408
- package/lib/templates/project/reactb2x/force-app/main/default/webapplications/appreacttemplateb2x/src/api/graphql-operations-types.ts +0 -116
- package/lib/templates/project/reactb2x/force-app/main/default/webapplications/appreacttemplateb2x/src/api/utils/accounts.ts +0 -33
- package/lib/templates/project/reactb2x/force-app/main/default/webapplications/appreacttemplateb2x/src/api/utils/query/highRevenueAccountsQuery.graphql +0 -29
- package/lib/templates/project/reactb2x/force-app/main/default/webapplications/appreacttemplateb2x/src/components/layout/card-layout.tsx +0 -23
- package/lib/templates/project/reactb2x/force-app/main/default/webapplications/appreacttemplateb2x/src/lib/data-sdk.ts +0 -21
- package/lib/templates/webapplication/reactbasic/build/vite.config.d.ts +0 -2
- package/lib/templates/webapplication/reactbasic/build/vite.config.js +0 -93
- package/lib/templates/webapplication/reactbasic/package-lock.json +0 -14373
- package/lib/templates/webapplication/reactbasic/src/api/graphql-operations-types.ts +0 -116
- package/lib/templates/webapplication/reactbasic/src/api/utils/accounts.ts +0 -33
- package/lib/templates/webapplication/reactbasic/src/api/utils/query/highRevenueAccountsQuery.graphql +0 -29
- /package/lib/templates/project/reactb2x/force-app/main/default/webapplications/appreacttemplateb2x/src/{components/auth → features/authentication}/authHelpers.ts +0 -0
- /package/lib/templates/project/reactb2x/force-app/main/default/webapplications/appreacttemplateb2x/src/{components/auth → features/authentication}/authenticationConfig.ts +0 -0
- /package/lib/templates/project/reactb2x/force-app/main/default/webapplications/appreacttemplateb2x/src/{hooks → features/authentication/hooks}/useCountdownTimer.ts +0 -0
- /package/lib/templates/project/reactb2x/force-app/main/default/webapplications/appreacttemplateb2x/src/{hooks → features/authentication/hooks}/useRetryWithBackoff.ts +0 -0
- /package/lib/templates/project/reactb2x/force-app/main/default/webapplications/appreacttemplateb2x/src/{components/auth → features/authentication}/sessionTimeout/sessionTimeService.ts +0 -0
- /package/lib/templates/project/reactb2x/force-app/main/default/webapplications/appreacttemplateb2x/src/{components/auth → features/authentication}/sessionTimeout/sessionTimeoutConfig.ts +0 -0
- /package/lib/templates/project/reactb2x/force-app/main/default/webapplications/appreacttemplateb2x/src/{utils → features/authentication/utils}/helpers.ts +0 -0
|
@@ -0,0 +1,395 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Object Search Data Hooks
|
|
3
|
+
*
|
|
4
|
+
* - useObjectListMetadata: single source for list-view metadata (filters → columns + picklists). Use in list pages to avoid duplicate state and API calls.
|
|
5
|
+
* - useObjectColumns / useObjectFilters: thin wrappers over useObjectListMetadata for backward compatibility.
|
|
6
|
+
* - getSharedFilters: module-level deduplication for getObjectListFilters across hook instances.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { useState, useEffect, useRef, useMemo } from "react";
|
|
10
|
+
import { objectInfoService, type SearchParams } from "../api/objectInfoService";
|
|
11
|
+
import type {
|
|
12
|
+
Column,
|
|
13
|
+
SearchResultRecord,
|
|
14
|
+
SearchResultRecordData,
|
|
15
|
+
} from "../types/search/searchResults";
|
|
16
|
+
import type { Filter, FilterCriteria } from "../types/filters/filters";
|
|
17
|
+
import type { PicklistValue } from "../types/filters/picklist";
|
|
18
|
+
import { createFiltersKey } from "../utils/cacheUtils";
|
|
19
|
+
|
|
20
|
+
// --- Shared filters cache (deduplicates getObjectListFilters across useObjectColumns + useObjectFilters) ---
|
|
21
|
+
const sharedFiltersCache = new Map<string, Filter[]>();
|
|
22
|
+
const sharedFiltersInFlight = new Map<string, Promise<Filter[]>>();
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Returns filters for the object, deduplicating the API call across hook instances.
|
|
26
|
+
* Does not pass abort signal to the API so the shared request is not aborted when
|
|
27
|
+
* one consumer's effect cleans up (e.g. React Strict Mode); callers still guard with isCancelled.
|
|
28
|
+
*/
|
|
29
|
+
function getSharedFilters(objectApiName: string): Promise<Filter[]> {
|
|
30
|
+
const cached = sharedFiltersCache.get(objectApiName);
|
|
31
|
+
if (cached) return Promise.resolve(cached);
|
|
32
|
+
const inFlight = sharedFiltersInFlight.get(objectApiName);
|
|
33
|
+
if (inFlight) return inFlight;
|
|
34
|
+
const promise = objectInfoService
|
|
35
|
+
.getObjectListFilters(objectApiName)
|
|
36
|
+
.then((filters) => {
|
|
37
|
+
sharedFiltersCache.set(objectApiName, filters);
|
|
38
|
+
sharedFiltersInFlight.delete(objectApiName);
|
|
39
|
+
return filters;
|
|
40
|
+
})
|
|
41
|
+
.catch((err) => {
|
|
42
|
+
sharedFiltersInFlight.delete(objectApiName);
|
|
43
|
+
throw err;
|
|
44
|
+
});
|
|
45
|
+
sharedFiltersInFlight.set(objectApiName, promise);
|
|
46
|
+
return promise;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// --- Shared Types ---
|
|
50
|
+
export interface FiltersData {
|
|
51
|
+
filters: Filter[];
|
|
52
|
+
picklistValues: Record<string, PicklistValue[]>;
|
|
53
|
+
loading: boolean;
|
|
54
|
+
error: string | null;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Derives column definitions from filter definitions for list/result UI.
|
|
59
|
+
*/
|
|
60
|
+
function filtersToColumns(filters: Filter[]): Column[] {
|
|
61
|
+
return filters.map((f) => ({
|
|
62
|
+
fieldApiName: f.targetFieldPath,
|
|
63
|
+
label: f.label,
|
|
64
|
+
searchable: true,
|
|
65
|
+
sortable: true,
|
|
66
|
+
}));
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export interface ObjectListMetadata {
|
|
70
|
+
columns: Column[];
|
|
71
|
+
filters: Filter[];
|
|
72
|
+
picklistValues: Record<string, PicklistValue[]>;
|
|
73
|
+
loading: boolean;
|
|
74
|
+
error: string | null;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Single hook for list-view metadata: filters (shared API), derived columns, and picklist values.
|
|
79
|
+
* Use this in list/search pages to avoid duplicate useObjectColumns + useObjectFilters and duplicate state.
|
|
80
|
+
*/
|
|
81
|
+
export function useObjectListMetadata(objectApiName: string | null): ObjectListMetadata {
|
|
82
|
+
const [state, setState] = useState<{
|
|
83
|
+
columns: Column[];
|
|
84
|
+
filters: Filter[];
|
|
85
|
+
picklistValues: Record<string, PicklistValue[]>;
|
|
86
|
+
loading: boolean;
|
|
87
|
+
error: string | null;
|
|
88
|
+
}>({
|
|
89
|
+
columns: [],
|
|
90
|
+
filters: [],
|
|
91
|
+
picklistValues: {},
|
|
92
|
+
loading: true,
|
|
93
|
+
error: null,
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
useEffect(() => {
|
|
97
|
+
if (!objectApiName) {
|
|
98
|
+
setState((s) => ({ ...s, loading: false, error: "Invalid object" }));
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
let isCancelled = false;
|
|
103
|
+
const ac = new AbortController();
|
|
104
|
+
|
|
105
|
+
const run = async () => {
|
|
106
|
+
setState((s) => ({ ...s, loading: true, error: null }));
|
|
107
|
+
try {
|
|
108
|
+
const filters = await getSharedFilters(objectApiName!);
|
|
109
|
+
if (isCancelled) return;
|
|
110
|
+
|
|
111
|
+
const selectFilters = filters.filter((f) => f.affordance?.toLowerCase() === "select");
|
|
112
|
+
const picklistPromises = selectFilters.map((f) =>
|
|
113
|
+
objectInfoService
|
|
114
|
+
.getPicklistValues(objectApiName!, f.targetFieldPath, undefined, ac.signal)
|
|
115
|
+
.then((values) => ({ fieldPath: f.targetFieldPath, values }))
|
|
116
|
+
.catch((err) => {
|
|
117
|
+
if (err?.name === "AbortError") throw err;
|
|
118
|
+
return { fieldPath: f.targetFieldPath, values: [] as PicklistValue[] };
|
|
119
|
+
}),
|
|
120
|
+
);
|
|
121
|
+
const picklistResults = await Promise.all(picklistPromises);
|
|
122
|
+
if (isCancelled) return;
|
|
123
|
+
|
|
124
|
+
const picklistValues: Record<string, PicklistValue[]> = {};
|
|
125
|
+
picklistResults.forEach(({ fieldPath, values }) => {
|
|
126
|
+
picklistValues[fieldPath] = values;
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
setState({
|
|
130
|
+
columns: filtersToColumns(filters),
|
|
131
|
+
filters,
|
|
132
|
+
picklistValues,
|
|
133
|
+
loading: false,
|
|
134
|
+
error: null,
|
|
135
|
+
});
|
|
136
|
+
} catch (err) {
|
|
137
|
+
if (isCancelled || (err instanceof Error && err.name === "AbortError")) return;
|
|
138
|
+
setState((s) => ({
|
|
139
|
+
...s,
|
|
140
|
+
columns: [],
|
|
141
|
+
filters: [],
|
|
142
|
+
picklistValues: {},
|
|
143
|
+
loading: false,
|
|
144
|
+
error: "Failed to load list metadata",
|
|
145
|
+
}));
|
|
146
|
+
}
|
|
147
|
+
};
|
|
148
|
+
|
|
149
|
+
run();
|
|
150
|
+
return () => {
|
|
151
|
+
isCancelled = true;
|
|
152
|
+
ac.abort();
|
|
153
|
+
};
|
|
154
|
+
}, [objectApiName]);
|
|
155
|
+
|
|
156
|
+
return state;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Hook: useObjectColumns
|
|
161
|
+
* Thin wrapper over useObjectListMetadata for backward compatibility.
|
|
162
|
+
*/
|
|
163
|
+
export function useObjectColumns(objectApiName: string | null) {
|
|
164
|
+
const { columns, loading, error } = useObjectListMetadata(objectApiName);
|
|
165
|
+
return {
|
|
166
|
+
columns: objectApiName ? columns : [],
|
|
167
|
+
columnsLoading: loading,
|
|
168
|
+
columnsError: error,
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Hook: useObjectSearchResults
|
|
174
|
+
*
|
|
175
|
+
* Fetches search results for a specific object based on the provided query parameters.
|
|
176
|
+
* Maintains the *latest* result set for the object in state to prevent redundant
|
|
177
|
+
* network requests when the component re-renders with the same parameters.
|
|
178
|
+
* Includes debouncing for search queries (but not pagination).
|
|
179
|
+
*
|
|
180
|
+
* @param objectApiName - The API name of the object to search
|
|
181
|
+
* @param searchQuery - The search query string
|
|
182
|
+
* @param searchPageSize - Number of results per page (default: 50)
|
|
183
|
+
* @param searchPageToken - Pagination token (default: '0')
|
|
184
|
+
* @param filters - Array of filter criteria to apply (default: [])
|
|
185
|
+
* @param sortBy - Sort field and direction (default: 'relevance')
|
|
186
|
+
* @returns Object containing results array, pagination tokens, loading state, and error state
|
|
187
|
+
*
|
|
188
|
+
* @example
|
|
189
|
+
* ```tsx
|
|
190
|
+
* const { results, nextPageToken, previousPageToken, currentPageToken, resultsLoading, resultsError } = useObjectSearchResults(
|
|
191
|
+
* 'Account',
|
|
192
|
+
* 'test query',
|
|
193
|
+
* 25,
|
|
194
|
+
* '0',
|
|
195
|
+
* [{ objectApiName: 'Account', fieldPath: 'Name', operator: 'contains', values: ['test'] }]
|
|
196
|
+
* );
|
|
197
|
+
* ```
|
|
198
|
+
*/
|
|
199
|
+
export function useObjectSearchResults(
|
|
200
|
+
objectApiName: string | null,
|
|
201
|
+
searchQuery: string,
|
|
202
|
+
searchPageSize: number = 50,
|
|
203
|
+
searchPageToken: string = "0",
|
|
204
|
+
filters: FilterCriteria[] = [],
|
|
205
|
+
sortBy: string = "relevance",
|
|
206
|
+
) {
|
|
207
|
+
const [resultsCache, setResultsCache] = useState<
|
|
208
|
+
Record<
|
|
209
|
+
string,
|
|
210
|
+
{
|
|
211
|
+
results: SearchResultRecord[];
|
|
212
|
+
query: string;
|
|
213
|
+
pageToken: string;
|
|
214
|
+
pageSize: number;
|
|
215
|
+
filtersKey: string;
|
|
216
|
+
sortBy: string;
|
|
217
|
+
nextPageToken: string | null;
|
|
218
|
+
previousPageToken: string | null;
|
|
219
|
+
currentPageToken: string;
|
|
220
|
+
}
|
|
221
|
+
>
|
|
222
|
+
>({});
|
|
223
|
+
const [loading, setLoading] = useState<Record<string, boolean>>({});
|
|
224
|
+
const [error, setError] = useState<Record<string, string | null>>({});
|
|
225
|
+
|
|
226
|
+
const debounceTimeout = useRef<ReturnType<typeof setTimeout> | null>(null);
|
|
227
|
+
const abortControllerRef = useRef<AbortController | null>(null);
|
|
228
|
+
const resultsCacheRef = useRef(resultsCache);
|
|
229
|
+
|
|
230
|
+
const filtersKey = useMemo(() => {
|
|
231
|
+
const filtersArray = Array.isArray(filters) ? filters : [];
|
|
232
|
+
return createFiltersKey(filtersArray);
|
|
233
|
+
}, [filters]);
|
|
234
|
+
|
|
235
|
+
useEffect(() => {
|
|
236
|
+
resultsCacheRef.current = resultsCache;
|
|
237
|
+
}, [resultsCache]);
|
|
238
|
+
|
|
239
|
+
useEffect(() => {
|
|
240
|
+
if (!objectApiName || !searchQuery.trim()) {
|
|
241
|
+
return;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
let isCancelled = false;
|
|
245
|
+
const abortController = new AbortController();
|
|
246
|
+
|
|
247
|
+
if (abortControllerRef.current) {
|
|
248
|
+
abortControllerRef.current.abort();
|
|
249
|
+
}
|
|
250
|
+
abortControllerRef.current = abortController;
|
|
251
|
+
|
|
252
|
+
if (debounceTimeout.current) {
|
|
253
|
+
clearTimeout(debounceTimeout.current);
|
|
254
|
+
debounceTimeout.current = null;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
const cached = resultsCacheRef.current[objectApiName];
|
|
258
|
+
if (
|
|
259
|
+
!abortController.signal.aborted &&
|
|
260
|
+
cached &&
|
|
261
|
+
cached.query === searchQuery &&
|
|
262
|
+
cached.pageToken === searchPageToken &&
|
|
263
|
+
cached.pageSize === searchPageSize &&
|
|
264
|
+
cached.filtersKey === filtersKey &&
|
|
265
|
+
cached.sortBy === sortBy
|
|
266
|
+
) {
|
|
267
|
+
return;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
if (abortController.signal.aborted) {
|
|
271
|
+
return;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
const fetchResults = async () => {
|
|
275
|
+
setLoading((prev) => ({ ...prev, [objectApiName]: true }));
|
|
276
|
+
setError((prev) => ({ ...prev, [objectApiName]: null }));
|
|
277
|
+
|
|
278
|
+
try {
|
|
279
|
+
const searchParams: SearchParams = {
|
|
280
|
+
sortBy: sortBy === "relevance" ? "" : sortBy,
|
|
281
|
+
filters: filters,
|
|
282
|
+
pageSize: searchPageSize,
|
|
283
|
+
pageToken: searchPageToken,
|
|
284
|
+
};
|
|
285
|
+
|
|
286
|
+
const keywordSearchResult = await objectInfoService.searchResults(
|
|
287
|
+
searchQuery,
|
|
288
|
+
objectApiName,
|
|
289
|
+
searchParams,
|
|
290
|
+
abortController.signal,
|
|
291
|
+
);
|
|
292
|
+
|
|
293
|
+
if (isCancelled || abortController.signal.aborted) return;
|
|
294
|
+
|
|
295
|
+
const normalizedRecords = keywordSearchResult.records.map((r) => ({
|
|
296
|
+
record: r.record as SearchResultRecordData,
|
|
297
|
+
highlightInfo: r.highlightInfo,
|
|
298
|
+
searchInfo: r.searchInfo,
|
|
299
|
+
}));
|
|
300
|
+
|
|
301
|
+
const nextPageToken: string | null = keywordSearchResult.nextPageToken ?? null;
|
|
302
|
+
const previousPageToken: string | null = keywordSearchResult.previousPageToken ?? null;
|
|
303
|
+
|
|
304
|
+
setResultsCache((prev): typeof prev => ({
|
|
305
|
+
...prev,
|
|
306
|
+
[objectApiName]: {
|
|
307
|
+
results: normalizedRecords,
|
|
308
|
+
query: searchQuery,
|
|
309
|
+
pageToken: searchPageToken,
|
|
310
|
+
pageSize: searchPageSize,
|
|
311
|
+
filtersKey: filtersKey,
|
|
312
|
+
sortBy,
|
|
313
|
+
nextPageToken,
|
|
314
|
+
previousPageToken,
|
|
315
|
+
currentPageToken: keywordSearchResult.currentPageToken,
|
|
316
|
+
},
|
|
317
|
+
}));
|
|
318
|
+
} catch (err) {
|
|
319
|
+
if (isCancelled || (err instanceof Error && err.name === "AbortError")) {
|
|
320
|
+
return;
|
|
321
|
+
}
|
|
322
|
+
setError((prev) => ({ ...prev, [objectApiName]: "Unable to load search results" }));
|
|
323
|
+
// Cache empty result so we skip refetch on remount (avoid infinite loop on API error)
|
|
324
|
+
setResultsCache((prev) => ({
|
|
325
|
+
...prev,
|
|
326
|
+
[objectApiName]: {
|
|
327
|
+
results: [],
|
|
328
|
+
query: searchQuery,
|
|
329
|
+
pageToken: searchPageToken,
|
|
330
|
+
pageSize: searchPageSize,
|
|
331
|
+
filtersKey: filtersKey,
|
|
332
|
+
sortBy,
|
|
333
|
+
nextPageToken: null,
|
|
334
|
+
previousPageToken: null,
|
|
335
|
+
currentPageToken: searchPageToken,
|
|
336
|
+
},
|
|
337
|
+
}));
|
|
338
|
+
} finally {
|
|
339
|
+
if (!isCancelled) {
|
|
340
|
+
setLoading((prev) => ({ ...prev, [objectApiName]: false }));
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
};
|
|
344
|
+
|
|
345
|
+
if (searchPageToken === "0") {
|
|
346
|
+
debounceTimeout.current = setTimeout(() => {
|
|
347
|
+
fetchResults();
|
|
348
|
+
}, 300);
|
|
349
|
+
} else {
|
|
350
|
+
fetchResults();
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
return () => {
|
|
354
|
+
isCancelled = true;
|
|
355
|
+
abortController.abort();
|
|
356
|
+
if (debounceTimeout.current) {
|
|
357
|
+
clearTimeout(debounceTimeout.current);
|
|
358
|
+
debounceTimeout.current = null;
|
|
359
|
+
}
|
|
360
|
+
if (abortControllerRef.current === abortController) {
|
|
361
|
+
abortControllerRef.current = null;
|
|
362
|
+
}
|
|
363
|
+
};
|
|
364
|
+
}, [objectApiName, searchQuery, searchPageSize, searchPageToken, filtersKey, sortBy]);
|
|
365
|
+
|
|
366
|
+
return {
|
|
367
|
+
results: objectApiName ? resultsCache[objectApiName]?.results || [] : [],
|
|
368
|
+
nextPageToken: objectApiName ? resultsCache[objectApiName]?.nextPageToken || null : null,
|
|
369
|
+
previousPageToken: objectApiName
|
|
370
|
+
? resultsCache[objectApiName]?.previousPageToken || null
|
|
371
|
+
: null,
|
|
372
|
+
currentPageToken: objectApiName ? resultsCache[objectApiName]?.currentPageToken || "0" : "0",
|
|
373
|
+
resultsLoading: objectApiName ? loading[objectApiName] || false : false,
|
|
374
|
+
resultsError: objectApiName ? error[objectApiName] || null : null,
|
|
375
|
+
};
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
/**
|
|
379
|
+
* Hook: useObjectFilters
|
|
380
|
+
* Thin wrapper over useObjectListMetadata for backward compatibility.
|
|
381
|
+
*/
|
|
382
|
+
export function useObjectFilters(objectApiName: string | null) {
|
|
383
|
+
const { filters, picklistValues, loading, error } = useObjectListMetadata(objectApiName);
|
|
384
|
+
const filtersData: Record<string, FiltersData> = objectApiName
|
|
385
|
+
? {
|
|
386
|
+
[objectApiName]: {
|
|
387
|
+
filters,
|
|
388
|
+
picklistValues,
|
|
389
|
+
loading,
|
|
390
|
+
error,
|
|
391
|
+
},
|
|
392
|
+
}
|
|
393
|
+
: {};
|
|
394
|
+
return { filtersData };
|
|
395
|
+
}
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
import { useState, useEffect, useRef } from "react";
|
|
2
|
+
import { objectDetailService } from "../api/objectDetailService";
|
|
3
|
+
import type { LayoutResponse } from "../types/recordDetail/recordDetail";
|
|
4
|
+
import type { ObjectInfoResult } from "../types/objectInfo/objectInfo";
|
|
5
|
+
import type { GraphQLRecordNode } from "../api/recordListGraphQLService";
|
|
6
|
+
|
|
7
|
+
export interface UseRecordDetailLayoutReturn {
|
|
8
|
+
layout: LayoutResponse | null;
|
|
9
|
+
record: GraphQLRecordNode | null;
|
|
10
|
+
objectMetadata: ObjectInfoResult | null;
|
|
11
|
+
loading: boolean;
|
|
12
|
+
error: string | null;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export interface UseRecordDetailLayoutParams {
|
|
16
|
+
objectApiName: string | null;
|
|
17
|
+
recordId: string | null;
|
|
18
|
+
recordTypeId?: string | null;
|
|
19
|
+
/** When provided, skips the fetch and uses this data (avoids duplicate API calls when parent already fetched). Callers should memoize this (e.g. useMemo) to avoid unnecessary effect runs. */
|
|
20
|
+
initialData?: {
|
|
21
|
+
layout: LayoutResponse;
|
|
22
|
+
record: GraphQLRecordNode;
|
|
23
|
+
objectMetadata: ObjectInfoResult;
|
|
24
|
+
} | null;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const MAX_CACHE_SIZE = 50;
|
|
28
|
+
/** Cache entries older than this are treated as stale and refetched. */
|
|
29
|
+
const CACHE_TTL_MS = 5 * 60 * 1000;
|
|
30
|
+
|
|
31
|
+
type CacheEntry = {
|
|
32
|
+
layout: LayoutResponse;
|
|
33
|
+
record: GraphQLRecordNode;
|
|
34
|
+
objectMetadata: ObjectInfoResult;
|
|
35
|
+
cachedAt: number;
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Detail page data: layout (REST), object metadata (GraphQL), single record (GraphQL).
|
|
40
|
+
*
|
|
41
|
+
* Calls objectDetailService.getRecordDetail once per objectApiName/recordId/recordTypeId.
|
|
42
|
+
* Caches result in memory (TTL 5min, max 50 entries). Used by DetailPage and UiApiDetailForm.
|
|
43
|
+
*
|
|
44
|
+
* @param objectApiName - Object API name.
|
|
45
|
+
* @param recordId - Record Id.
|
|
46
|
+
* @param recordTypeId - Optional record type (default master).
|
|
47
|
+
* @returns { layout, record, objectMetadata, loading, error }.
|
|
48
|
+
*/
|
|
49
|
+
export function useRecordDetailLayout({
|
|
50
|
+
objectApiName,
|
|
51
|
+
recordId,
|
|
52
|
+
recordTypeId = null,
|
|
53
|
+
initialData = null,
|
|
54
|
+
}: UseRecordDetailLayoutParams): UseRecordDetailLayoutReturn {
|
|
55
|
+
const [layout, setLayout] = useState<LayoutResponse | null>(initialData?.layout ?? null);
|
|
56
|
+
const [record, setRecord] = useState<GraphQLRecordNode | null>(initialData?.record ?? null);
|
|
57
|
+
const [objectMetadata, setObjectMetadata] = useState<ObjectInfoResult | null>(
|
|
58
|
+
initialData?.objectMetadata ?? null,
|
|
59
|
+
);
|
|
60
|
+
const [loading, setLoading] = useState(!initialData);
|
|
61
|
+
const [error, setError] = useState<string | null>(null);
|
|
62
|
+
|
|
63
|
+
const cacheKey =
|
|
64
|
+
objectApiName && recordId ? `${objectApiName}:${recordId}:${recordTypeId ?? "default"}` : null;
|
|
65
|
+
const cacheRef = useRef<Map<string, CacheEntry>>(new Map());
|
|
66
|
+
|
|
67
|
+
useEffect(() => {
|
|
68
|
+
if (!objectApiName || !recordId) {
|
|
69
|
+
setError("Invalid object or record ID");
|
|
70
|
+
setLoading(false);
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// Skip fetch when parent already provided data (avoids duplicate API calls)
|
|
75
|
+
if (
|
|
76
|
+
initialData?.layout != null &&
|
|
77
|
+
initialData?.record != null &&
|
|
78
|
+
initialData?.objectMetadata != null
|
|
79
|
+
) {
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const cached = cacheRef.current.get(cacheKey!);
|
|
84
|
+
const now = Date.now();
|
|
85
|
+
if (cached && now - cached.cachedAt < CACHE_TTL_MS) {
|
|
86
|
+
setLayout(cached.layout);
|
|
87
|
+
setRecord(cached.record);
|
|
88
|
+
setObjectMetadata(cached.objectMetadata);
|
|
89
|
+
setLoading(false);
|
|
90
|
+
setError(null);
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
let isCancelled = false;
|
|
95
|
+
const abortController = new AbortController();
|
|
96
|
+
|
|
97
|
+
const fetchDetail = async () => {
|
|
98
|
+
setLoading(true);
|
|
99
|
+
setError(null);
|
|
100
|
+
|
|
101
|
+
try {
|
|
102
|
+
const {
|
|
103
|
+
layout: layoutData,
|
|
104
|
+
record: recordData,
|
|
105
|
+
objectMetadata: objectMetadataData,
|
|
106
|
+
} = await objectDetailService.getRecordDetail(
|
|
107
|
+
objectApiName,
|
|
108
|
+
recordId,
|
|
109
|
+
recordTypeId ?? undefined,
|
|
110
|
+
abortController.signal,
|
|
111
|
+
);
|
|
112
|
+
|
|
113
|
+
if (isCancelled) return;
|
|
114
|
+
|
|
115
|
+
const cache = cacheRef.current;
|
|
116
|
+
if (cache.size >= MAX_CACHE_SIZE) {
|
|
117
|
+
const firstKey = cache.keys().next().value;
|
|
118
|
+
if (firstKey != null) cache.delete(firstKey);
|
|
119
|
+
}
|
|
120
|
+
cache.set(cacheKey!, {
|
|
121
|
+
layout: layoutData,
|
|
122
|
+
record: recordData,
|
|
123
|
+
objectMetadata: objectMetadataData,
|
|
124
|
+
cachedAt: Date.now(),
|
|
125
|
+
});
|
|
126
|
+
setLayout(layoutData);
|
|
127
|
+
setRecord(recordData);
|
|
128
|
+
setObjectMetadata(objectMetadataData);
|
|
129
|
+
} catch (err) {
|
|
130
|
+
if (isCancelled || (err instanceof Error && err.name === "AbortError")) {
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
setError("Failed to load record details");
|
|
134
|
+
} finally {
|
|
135
|
+
if (!isCancelled) {
|
|
136
|
+
setLoading(false);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
fetchDetail();
|
|
142
|
+
|
|
143
|
+
return () => {
|
|
144
|
+
isCancelled = true;
|
|
145
|
+
abortController.abort();
|
|
146
|
+
};
|
|
147
|
+
}, [objectApiName, recordId, recordTypeId, cacheKey, initialData]);
|
|
148
|
+
|
|
149
|
+
return {
|
|
150
|
+
layout,
|
|
151
|
+
record,
|
|
152
|
+
objectMetadata,
|
|
153
|
+
loading,
|
|
154
|
+
error,
|
|
155
|
+
};
|
|
156
|
+
}
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Record list hook: GraphQL records with filter, sort, pagination, search.
|
|
3
|
+
* Use for list/search views; detail view uses useRecordDetailLayout instead.
|
|
4
|
+
*
|
|
5
|
+
* @module hooks/useRecordListGraphQL
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { useState, useEffect, useCallback } from "react";
|
|
9
|
+
import { useObjectColumns } from "./useObjectSearchData";
|
|
10
|
+
import {
|
|
11
|
+
getRecordsGraphQL,
|
|
12
|
+
buildOrderByFromSort,
|
|
13
|
+
type RecordListGraphQLResult,
|
|
14
|
+
} from "../api/recordListGraphQLService";
|
|
15
|
+
import type { Column } from "../types/search/searchResults";
|
|
16
|
+
import type { FilterCriteria } from "../types/filters/filters";
|
|
17
|
+
|
|
18
|
+
const EMPTY_FILTERS: FilterCriteria[] = [];
|
|
19
|
+
|
|
20
|
+
export interface UseRecordListGraphQLOptions {
|
|
21
|
+
objectApiName: string;
|
|
22
|
+
first?: number;
|
|
23
|
+
after?: string | null;
|
|
24
|
+
filters?: FilterCriteria[];
|
|
25
|
+
sortBy?: string;
|
|
26
|
+
searchQuery?: string;
|
|
27
|
+
/** When provided, skips useObjectColumns (use from parent e.g. useObjectListMetadata). */
|
|
28
|
+
columns?: Column[];
|
|
29
|
+
columnsLoading?: boolean;
|
|
30
|
+
columnsError?: string | null;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export interface UseRecordListGraphQLReturn {
|
|
34
|
+
data: RecordListGraphQLResult | null;
|
|
35
|
+
edges: Array<{ node?: Record<string, unknown> }>;
|
|
36
|
+
pageInfo: {
|
|
37
|
+
hasNextPage?: boolean;
|
|
38
|
+
hasPreviousPage?: boolean;
|
|
39
|
+
endCursor?: string | null;
|
|
40
|
+
startCursor?: string | null;
|
|
41
|
+
} | null;
|
|
42
|
+
loading: boolean;
|
|
43
|
+
error: string | null;
|
|
44
|
+
columnsLoading: boolean;
|
|
45
|
+
columnsError: string | null;
|
|
46
|
+
refetch: () => void;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Fetches records via GraphQL for the given object with filter, sort, pagination, and search.
|
|
51
|
+
*/
|
|
52
|
+
export function useRecordListGraphQL(
|
|
53
|
+
options: UseRecordListGraphQLOptions,
|
|
54
|
+
): UseRecordListGraphQLReturn {
|
|
55
|
+
const {
|
|
56
|
+
objectApiName,
|
|
57
|
+
first = 50,
|
|
58
|
+
after = null,
|
|
59
|
+
filters = EMPTY_FILTERS,
|
|
60
|
+
sortBy = "",
|
|
61
|
+
searchQuery = "",
|
|
62
|
+
columns: columnsProp,
|
|
63
|
+
columnsLoading: columnsLoadingProp,
|
|
64
|
+
columnsError: columnsErrorProp,
|
|
65
|
+
} = options;
|
|
66
|
+
|
|
67
|
+
const fromParent = columnsProp !== undefined;
|
|
68
|
+
const fromHook = useObjectColumns(fromParent ? null : objectApiName);
|
|
69
|
+
|
|
70
|
+
const columns = fromParent ? columnsProp : fromHook.columns;
|
|
71
|
+
const columnsLoading = fromParent ? (columnsLoadingProp ?? false) : fromHook.columnsLoading;
|
|
72
|
+
const columnsError = fromParent ? (columnsErrorProp ?? null) : fromHook.columnsError;
|
|
73
|
+
|
|
74
|
+
const [data, setData] = useState<RecordListGraphQLResult | null>(null);
|
|
75
|
+
const [loading, setLoading] = useState(false);
|
|
76
|
+
const [error, setError] = useState<string | null>(null);
|
|
77
|
+
|
|
78
|
+
const fetchRecords = useCallback(() => {
|
|
79
|
+
if (columnsLoading || columnsError || columns.length === 0) return;
|
|
80
|
+
|
|
81
|
+
setLoading(true);
|
|
82
|
+
setError(null);
|
|
83
|
+
const orderBy = buildOrderByFromSort(sortBy);
|
|
84
|
+
|
|
85
|
+
getRecordsGraphQL({
|
|
86
|
+
objectApiName,
|
|
87
|
+
columns,
|
|
88
|
+
first,
|
|
89
|
+
after,
|
|
90
|
+
filters,
|
|
91
|
+
orderBy,
|
|
92
|
+
searchQuery: searchQuery.trim() || undefined,
|
|
93
|
+
})
|
|
94
|
+
.then((result) => {
|
|
95
|
+
setData(result);
|
|
96
|
+
})
|
|
97
|
+
.catch((err) => {
|
|
98
|
+
setError(err instanceof Error ? err.message : "Failed to load records");
|
|
99
|
+
})
|
|
100
|
+
.finally(() => {
|
|
101
|
+
setLoading(false);
|
|
102
|
+
});
|
|
103
|
+
}, [
|
|
104
|
+
objectApiName,
|
|
105
|
+
columns,
|
|
106
|
+
columnsLoading,
|
|
107
|
+
columnsError,
|
|
108
|
+
first,
|
|
109
|
+
after,
|
|
110
|
+
filters,
|
|
111
|
+
sortBy,
|
|
112
|
+
searchQuery,
|
|
113
|
+
]);
|
|
114
|
+
|
|
115
|
+
useEffect(() => {
|
|
116
|
+
if (!objectApiName || columnsLoading || columnsError) return;
|
|
117
|
+
if (columns.length === 0 && !columnsLoading) return;
|
|
118
|
+
fetchRecords();
|
|
119
|
+
}, [objectApiName, columns, columnsLoading, columnsError, fetchRecords]);
|
|
120
|
+
|
|
121
|
+
const objectData = data?.uiapi?.query?.[objectApiName];
|
|
122
|
+
const edges = objectData?.edges ?? [];
|
|
123
|
+
const pageInfo = objectData?.pageInfo ?? null;
|
|
124
|
+
|
|
125
|
+
return {
|
|
126
|
+
data,
|
|
127
|
+
edges,
|
|
128
|
+
pageInfo,
|
|
129
|
+
loading: columnsLoading || loading,
|
|
130
|
+
error: columnsError || error,
|
|
131
|
+
columnsLoading,
|
|
132
|
+
columnsError,
|
|
133
|
+
refetch: fetchRecords,
|
|
134
|
+
};
|
|
135
|
+
}
|