@salesforce/templates 66.3.1 → 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/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,61 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Type definitions and Zod schemas for Record Detail APIs:
|
|
5
|
+
* - Layout API (layout/{objectApiName}?layoutType=Full&mode=View&recordTypeId=...)
|
|
6
|
+
* - Record API (records/{recordId}?optionalFields=...)
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
const LayoutComponentSchema = z.object({
|
|
10
|
+
apiName: z.string().nullable(),
|
|
11
|
+
behavior: z.string().optional(),
|
|
12
|
+
componentType: z.enum(["Field", "CustomLink", "EmptySpace"]),
|
|
13
|
+
customLinkUrl: z.string().optional(),
|
|
14
|
+
label: z.string().optional(),
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
export type LayoutComponent = z.infer<typeof LayoutComponentSchema>;
|
|
18
|
+
|
|
19
|
+
const LayoutItemSchema = z.object({
|
|
20
|
+
editableForNew: z.boolean(),
|
|
21
|
+
editableForUpdate: z.boolean(),
|
|
22
|
+
label: z.string(),
|
|
23
|
+
layoutComponents: z.array(LayoutComponentSchema),
|
|
24
|
+
lookupIdApiName: z.string().nullable(),
|
|
25
|
+
required: z.boolean(),
|
|
26
|
+
sortable: z.boolean(),
|
|
27
|
+
uiBehavior: z.string().nullable(),
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
export type LayoutItem = z.infer<typeof LayoutItemSchema>;
|
|
31
|
+
|
|
32
|
+
const LayoutRowSchema = z.object({
|
|
33
|
+
layoutItems: z.array(LayoutItemSchema),
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
const LayoutSectionSchema = z.object({
|
|
37
|
+
collapsible: z.boolean(),
|
|
38
|
+
columns: z.number(),
|
|
39
|
+
heading: z.string(),
|
|
40
|
+
id: z.string(),
|
|
41
|
+
layoutRows: z.array(LayoutRowSchema),
|
|
42
|
+
rows: z.number(),
|
|
43
|
+
tabOrder: z.string(),
|
|
44
|
+
useHeading: z.boolean(),
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
export type LayoutSection = z.infer<typeof LayoutSectionSchema>;
|
|
48
|
+
|
|
49
|
+
export const LayoutResponseSchema = z.object({
|
|
50
|
+
eTag: z.string(),
|
|
51
|
+
id: z.string(),
|
|
52
|
+
layoutType: z.string(),
|
|
53
|
+
mode: z.string(),
|
|
54
|
+
objectApiName: z.string(),
|
|
55
|
+
recordTypeId: z.string(),
|
|
56
|
+
saveOptions: z.array(z.unknown()).optional(),
|
|
57
|
+
sections: z.array(LayoutSectionSchema),
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
export type LayoutResponse = z.infer<typeof LayoutResponseSchema>;
|
|
61
|
+
export type LayoutRow = z.infer<typeof LayoutRowSchema>;
|
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Type definitions for search results and column structures.
|
|
5
|
+
* * ARCHITECTURE NOTE:
|
|
6
|
+
* We define recursive interfaces MANUALLY first.
|
|
7
|
+
* If we rely on z.infer<typeof LazySchema> where the schema is z.ZodTypeAny,
|
|
8
|
+
* TypeScript defaults the type to 'any', destroying type safety.
|
|
9
|
+
*/
|
|
10
|
+
export type ComplexFieldValue = {
|
|
11
|
+
apiName?: string;
|
|
12
|
+
childRelationships?: Record<string, unknown>;
|
|
13
|
+
eTag?: string;
|
|
14
|
+
fields?: Record<string, FieldValue>; // Recursive reference
|
|
15
|
+
id?: string;
|
|
16
|
+
lastModifiedById?: string | null;
|
|
17
|
+
lastModifiedDate?: string | null;
|
|
18
|
+
recordTypeId?: string | null;
|
|
19
|
+
recordTypeInfo?: unknown;
|
|
20
|
+
systemModstamp?: string | null;
|
|
21
|
+
weakEtag?: number;
|
|
22
|
+
};
|
|
23
|
+
export type FieldValue = {
|
|
24
|
+
displayValue: string | null;
|
|
25
|
+
value: string | number | boolean | null | ComplexFieldValue; // Recursive union
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
// Zod Schema for Inline Edit Attributes
|
|
29
|
+
export const InlineEditAttributesSchema = z.record(
|
|
30
|
+
z.string(),
|
|
31
|
+
z.object({
|
|
32
|
+
editable: z.boolean(),
|
|
33
|
+
required: z.boolean(),
|
|
34
|
+
}),
|
|
35
|
+
);
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Inline edit attributes for a field
|
|
39
|
+
*/
|
|
40
|
+
export type InlineEditAttributes = z.infer<typeof InlineEditAttributesSchema>;
|
|
41
|
+
|
|
42
|
+
// Zod Schema for Column
|
|
43
|
+
export const ColumnSchema = z.object({
|
|
44
|
+
fieldApiName: z.string(),
|
|
45
|
+
inlineEditAttributes: InlineEditAttributesSchema.optional(),
|
|
46
|
+
label: z.string(),
|
|
47
|
+
lookupId: z.string().nullish(),
|
|
48
|
+
searchable: z.boolean(),
|
|
49
|
+
sortable: z.boolean(),
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Column definition for list/result UI. Can be derived from Filter[] via targetFieldPath and label
|
|
54
|
+
* (e.g. filters.map(f => ({ fieldApiName: f.targetFieldPath, label: f.label, searchable: true, sortable: true }))).
|
|
55
|
+
*/
|
|
56
|
+
export type Column = z.infer<typeof ColumnSchema>;
|
|
57
|
+
|
|
58
|
+
// Export schema for validation
|
|
59
|
+
export const ColumnArraySchema = z.array(ColumnSchema);
|
|
60
|
+
|
|
61
|
+
// Zod Schema for Complex Field Value (recursive structure)
|
|
62
|
+
// Using z.lazy() to handle circular reference with FieldValueSchema
|
|
63
|
+
// Note: This schema is exported for advanced use cases but should be used carefully
|
|
64
|
+
// due to potential performance implications with deeply nested structures
|
|
65
|
+
export const ComplexFieldValueSchema: z.ZodType<ComplexFieldValue> = z.lazy(() =>
|
|
66
|
+
z.object({
|
|
67
|
+
apiName: z.string().optional(),
|
|
68
|
+
childRelationships: z.record(z.string(), z.unknown()).optional(),
|
|
69
|
+
eTag: z.string().optional(),
|
|
70
|
+
fields: z.record(z.string(), FieldValueSchema).optional(),
|
|
71
|
+
id: z.string().optional(),
|
|
72
|
+
lastModifiedById: z.string().nullish(),
|
|
73
|
+
lastModifiedDate: z.string().nullish(),
|
|
74
|
+
recordTypeId: z.string().nullish(),
|
|
75
|
+
recordTypeInfo: z.unknown().optional(),
|
|
76
|
+
systemModstamp: z.string().nullish(),
|
|
77
|
+
weakEtag: z.number().optional(),
|
|
78
|
+
}),
|
|
79
|
+
);
|
|
80
|
+
|
|
81
|
+
// Zod Schema for Field Value (using z.lazy() to handle circular reference)
|
|
82
|
+
// Note: This schema is exported for validating individual field values on-demand
|
|
83
|
+
// Use FieldValueValidationSchema alias for clarity
|
|
84
|
+
// Using z.union([z.string(), z.null()]) instead of .nullish() to match FieldValue type definition
|
|
85
|
+
export const FieldValueSchema: z.ZodType<FieldValue> = z.lazy(() =>
|
|
86
|
+
z.object({
|
|
87
|
+
displayValue: z.union([z.string(), z.null()]),
|
|
88
|
+
value: z.union([
|
|
89
|
+
z.string(),
|
|
90
|
+
z.number(),
|
|
91
|
+
z.boolean(),
|
|
92
|
+
z.null(),
|
|
93
|
+
ComplexFieldValueSchema as z.ZodType<ComplexFieldValue>,
|
|
94
|
+
]),
|
|
95
|
+
}),
|
|
96
|
+
);
|
|
97
|
+
|
|
98
|
+
// Zod Schema for Search Result Record Data (lightweight validation)
|
|
99
|
+
// Using z.unknown() for fields to avoid expensive recursive validation of every field value
|
|
100
|
+
// This prevents UI freezing when validating large result sets (e.g., 100 records × 50 fields = 5,000 validations)
|
|
101
|
+
// Individual fields can be validated later when needed using FieldValueSchema
|
|
102
|
+
// Note: z.unknown() is safer than z.any() as it requires explicit type checking before use
|
|
103
|
+
export const SearchResultRecordDataSchema = z.object({
|
|
104
|
+
apiName: z.string(),
|
|
105
|
+
childRelationships: z.record(z.string(), z.unknown()),
|
|
106
|
+
eTag: z.string(),
|
|
107
|
+
fields: z.record(z.string(), z.unknown()), // Lightweight: avoids recursive validation, uses unknown for type safety
|
|
108
|
+
id: z.string(),
|
|
109
|
+
lastModifiedById: z.string().nullish(),
|
|
110
|
+
lastModifiedDate: z.string().nullish(),
|
|
111
|
+
recordTypeId: z.string().nullish(),
|
|
112
|
+
recordTypeInfo: z.unknown().nullish(),
|
|
113
|
+
systemModstamp: z.string().nullish(),
|
|
114
|
+
weakEtag: z.number(),
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
// Full validation schema for individual field values (use when validating specific fields)
|
|
118
|
+
// This can be used to validate a single field value when needed
|
|
119
|
+
export const FieldValueValidationSchema = FieldValueSchema;
|
|
120
|
+
|
|
121
|
+
// Zod Schema for Highlight Info
|
|
122
|
+
export const HighlightInfoSchema = z.object({
|
|
123
|
+
fields: z.record(z.string(), z.unknown()),
|
|
124
|
+
snippet: z.string().nullish(),
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
// Zod Schema for Search Info
|
|
128
|
+
export const SearchInfoSchema = z.object({
|
|
129
|
+
isPromoted: z.boolean(),
|
|
130
|
+
isSpellCorrected: z.boolean(),
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
// Zod Schema for Search Result Record
|
|
134
|
+
export const SearchResultRecordSchema = z.object({
|
|
135
|
+
highlightInfo: HighlightInfoSchema,
|
|
136
|
+
record: SearchResultRecordDataSchema,
|
|
137
|
+
searchInfo: SearchInfoSchema,
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Record structure within search results
|
|
142
|
+
* Note: The fields property is typed as Record<string, FieldValue> for type safety,
|
|
143
|
+
* but validation uses z.unknown() for performance (avoids recursive validation of all fields)
|
|
144
|
+
*/
|
|
145
|
+
export type SearchResultRecordData = Omit<
|
|
146
|
+
z.infer<typeof SearchResultRecordDataSchema>,
|
|
147
|
+
"fields"
|
|
148
|
+
> & {
|
|
149
|
+
fields: Record<string, FieldValue>;
|
|
150
|
+
};
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Highlight information for search results
|
|
154
|
+
*/
|
|
155
|
+
export type HighlightInfo = z.infer<typeof HighlightInfoSchema>;
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Search information for results
|
|
159
|
+
*/
|
|
160
|
+
export type SearchInfo = z.infer<typeof SearchInfoSchema>;
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Single record in search results (complete structure from API)
|
|
164
|
+
* Note: The record.fields property is typed as Record<string, FieldValue> for type safety,
|
|
165
|
+
* but validation uses z.unknown() for performance (avoids recursive validation of all fields)
|
|
166
|
+
*/
|
|
167
|
+
export type SearchResultRecord = Omit<z.infer<typeof SearchResultRecordSchema>, "record"> & {
|
|
168
|
+
record: SearchResultRecordData;
|
|
169
|
+
};
|
|
170
|
+
|
|
171
|
+
// Export schemas for validation
|
|
172
|
+
export const SearchResultRecordArraySchema = z.array(SearchResultRecordSchema);
|
|
173
|
+
|
|
174
|
+
// Zod Schema for Order By
|
|
175
|
+
export const OrderBySchema = z.object({
|
|
176
|
+
fieldApiName: z.string(),
|
|
177
|
+
isAscending: z.boolean(),
|
|
178
|
+
label: z.string(),
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* Order by configuration
|
|
183
|
+
*/
|
|
184
|
+
export type OrderBy = z.infer<typeof OrderBySchema>;
|
|
185
|
+
|
|
186
|
+
// Zod Schema for Keyword Search Result
|
|
187
|
+
export const KeywordSearchResultSchema = z.object({
|
|
188
|
+
currentPageToken: z.string(),
|
|
189
|
+
error: z.string().nullish(),
|
|
190
|
+
nextPageToken: z.string().nullish(),
|
|
191
|
+
objectApiName: z.string(),
|
|
192
|
+
orderBy: z.array(OrderBySchema),
|
|
193
|
+
pageSize: z.number(),
|
|
194
|
+
previousPageToken: z.string().nullish(),
|
|
195
|
+
records: z.array(SearchResultRecordSchema),
|
|
196
|
+
relatedObjectApiNames: z.array(z.string()),
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* Keyword search result structure
|
|
201
|
+
*/
|
|
202
|
+
export type KeywordSearchResult = z.infer<typeof KeywordSearchResultSchema>;
|
|
203
|
+
|
|
204
|
+
// Zod Schema for Search Results Response
|
|
205
|
+
export const SearchResultsResponseSchema = z.object({
|
|
206
|
+
configurationName: z.string().nullish(),
|
|
207
|
+
keywordSearchResult: KeywordSearchResultSchema,
|
|
208
|
+
objectApiName: z.string(),
|
|
209
|
+
query: z.string(),
|
|
210
|
+
queryId: z.string(),
|
|
211
|
+
});
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* Search results response structure
|
|
215
|
+
*/
|
|
216
|
+
export type SearchResultsResponse = z.infer<typeof SearchResultsResponseSchema>;
|
|
217
|
+
|
|
218
|
+
// Zod Schema for Column Info Response
|
|
219
|
+
export const ColumnInfoResponseSchema = z.record(z.string(), z.unknown()).and(
|
|
220
|
+
z.object({
|
|
221
|
+
columns: ColumnArraySchema.optional(),
|
|
222
|
+
fields: ColumnArraySchema.optional(),
|
|
223
|
+
}),
|
|
224
|
+
);
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* Column info response structure
|
|
228
|
+
*/
|
|
229
|
+
export type ColumnInfoResponse = z.infer<typeof ColumnInfoResponseSchema>;
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* API Utilities
|
|
3
|
+
*
|
|
4
|
+
* Generic utility functions for API requests, validation, and URL handling.
|
|
5
|
+
* These utilities are framework-agnostic and can be reused across different API services.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import type { ZodSchema } from "zod";
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Options for fetchAndValidate utility function
|
|
12
|
+
*/
|
|
13
|
+
export interface FetchAndValidateOptions<T> {
|
|
14
|
+
/** Zod schema for validation */
|
|
15
|
+
schema: ZodSchema<T>;
|
|
16
|
+
/** Error context for better error messages (e.g., "object info batch", "list info") */
|
|
17
|
+
errorContext: string;
|
|
18
|
+
/** Optional function to extract/transform data from response before validation */
|
|
19
|
+
extractData?: (data: unknown) => unknown;
|
|
20
|
+
/** Optional AbortSignal to cancel the request */
|
|
21
|
+
signal?: AbortSignal;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Generic utility function to fetch, parse, and validate API responses.
|
|
26
|
+
* Handles common patterns: fetch -> check status -> parse JSON -> validate Zod -> handle errors
|
|
27
|
+
*
|
|
28
|
+
* @param fetchFn - Function that returns a Promise<Response> (e.g., uiApiClient.get or uiApiClient.post)
|
|
29
|
+
* @param options - Configuration options including schema, error context, optional data extraction, and AbortSignal
|
|
30
|
+
* @returns Promise resolving to validated data of type T
|
|
31
|
+
*
|
|
32
|
+
* @remarks
|
|
33
|
+
* - Handles abort signals properly to prevent race conditions
|
|
34
|
+
* - Provides detailed error messages with context
|
|
35
|
+
* - Validates responses using Zod schemas for type safety
|
|
36
|
+
* - Supports data extraction/transformation before validation
|
|
37
|
+
*
|
|
38
|
+
* @example
|
|
39
|
+
* ```tsx
|
|
40
|
+
* const data = await fetchAndValidate(
|
|
41
|
+
* (signal) => apiClient.get('/endpoint', { signal }),
|
|
42
|
+
* {
|
|
43
|
+
* schema: MySchema,
|
|
44
|
+
* errorContext: 'user data',
|
|
45
|
+
* extractData: (data) => data.items,
|
|
46
|
+
* signal: abortController.signal
|
|
47
|
+
* }
|
|
48
|
+
* );
|
|
49
|
+
* ```
|
|
50
|
+
*/
|
|
51
|
+
export async function fetchAndValidate<T>(
|
|
52
|
+
fetchFn: (signal?: AbortSignal) => Promise<Response>,
|
|
53
|
+
options: FetchAndValidateOptions<T>,
|
|
54
|
+
): Promise<T> {
|
|
55
|
+
const { schema, errorContext, extractData, signal } = options;
|
|
56
|
+
|
|
57
|
+
try {
|
|
58
|
+
const response = await fetchFn(signal);
|
|
59
|
+
|
|
60
|
+
if (signal?.aborted) {
|
|
61
|
+
throw new DOMException("The operation was aborted.", "AbortError");
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
if (!response.ok) {
|
|
65
|
+
throw new Error(`Failed to fetch ${errorContext}: ${response.status} ${response.statusText}`);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const data = await response.json();
|
|
69
|
+
|
|
70
|
+
if (signal?.aborted) {
|
|
71
|
+
throw new DOMException("The operation was aborted.", "AbortError");
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const dataToValidate = extractData ? extractData(data) : data;
|
|
75
|
+
|
|
76
|
+
const validationResult = schema.safeParse(dataToValidate);
|
|
77
|
+
|
|
78
|
+
if (!validationResult.success) {
|
|
79
|
+
throw new Error(`Invalid ${errorContext} response format: ${validationResult.error.message}`);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
return validationResult.data;
|
|
83
|
+
} catch (error) {
|
|
84
|
+
if (error instanceof DOMException && error.name === "AbortError") {
|
|
85
|
+
throw error;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
if (error instanceof Error && error.name === "AbortError") {
|
|
89
|
+
throw error;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
if (error instanceof Error && error.name === "ZodError") {
|
|
93
|
+
throw new Error(`Invalid ${errorContext} response format: ${error.message}`);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
if (
|
|
97
|
+
error instanceof Error &&
|
|
98
|
+
(error.message.includes("Failed to fetch") || error.message.includes("Invalid"))
|
|
99
|
+
) {
|
|
100
|
+
throw error;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
throw new Error(
|
|
104
|
+
`Error fetching ${errorContext}: ${
|
|
105
|
+
error instanceof Error ? error.message : (error?.toString() ?? "Unknown error")
|
|
106
|
+
}`,
|
|
107
|
+
);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Helper to safely encode path components for URLs
|
|
113
|
+
* Wraps encodeURIComponent for better semantic meaning
|
|
114
|
+
*
|
|
115
|
+
* @param segment - The path segment to encode
|
|
116
|
+
* @returns URL-encoded path segment
|
|
117
|
+
*
|
|
118
|
+
* @example
|
|
119
|
+
* ```tsx
|
|
120
|
+
* const safePath = safeEncodePath('Account Name'); // 'Account%20Name'
|
|
121
|
+
* ```
|
|
122
|
+
*/
|
|
123
|
+
export function safeEncodePath(segment: string): string {
|
|
124
|
+
return encodeURIComponent(segment);
|
|
125
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cache Utilities
|
|
3
|
+
*
|
|
4
|
+
* Utility functions for creating deterministic cache keys and managing cache operations.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import type { FilterCriteria } from "../types/filters/filters";
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Creates a deterministic cache key from filter criteria array.
|
|
11
|
+
* Sorts filters and their values to ensure consistent keys regardless of input order.
|
|
12
|
+
*
|
|
13
|
+
* @param filters - Array of filter criteria (FilterCriteria[])
|
|
14
|
+
* @returns Deterministic string key for caching
|
|
15
|
+
*
|
|
16
|
+
* @remarks
|
|
17
|
+
* - Sorts filters by objectApiName, then fieldPath, then operator
|
|
18
|
+
* - Sorts values within each filter to ensure consistency
|
|
19
|
+
* - Handles null/undefined values safely
|
|
20
|
+
* - Prevents cache key collisions from different object ordering
|
|
21
|
+
*
|
|
22
|
+
* Why is sorting required?
|
|
23
|
+
* If a user filters by "Name" then "Date", the array is [Name, Date].
|
|
24
|
+
* If they filter by "Date" then "Name", the array is [Date, Name].
|
|
25
|
+
* - Without sorting, these would generate different cache keys ("Name-Date" vs "Date-Name"),
|
|
26
|
+
* causing the app to re-fetch data it actually already has. Sorting ensures that
|
|
27
|
+
* the order of user clicks doesn't invalidate the cache.
|
|
28
|
+
*
|
|
29
|
+
|
|
30
|
+
* @example
|
|
31
|
+
* ```tsx
|
|
32
|
+
* const cacheKey = createFiltersKey(filters);
|
|
33
|
+
* ```
|
|
34
|
+
*/
|
|
35
|
+
export function createFiltersKey(filters: FilterCriteria[]): string {
|
|
36
|
+
if (!Array.isArray(filters) || filters.length === 0) {
|
|
37
|
+
return "[]";
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const normalized = filters
|
|
41
|
+
.map((filter) => {
|
|
42
|
+
if (!filter || typeof filter !== "object") {
|
|
43
|
+
return null;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const f = filter as FilterCriteria;
|
|
47
|
+
|
|
48
|
+
const sortedValues =
|
|
49
|
+
Array.isArray(f.values) && f.values.length > 0
|
|
50
|
+
? [...f.values].sort((a, b) => {
|
|
51
|
+
const aStr = a.toString();
|
|
52
|
+
const bStr = b.toString();
|
|
53
|
+
return aStr.localeCompare(bStr);
|
|
54
|
+
})
|
|
55
|
+
: [];
|
|
56
|
+
|
|
57
|
+
return {
|
|
58
|
+
objectApiName: f.objectApiName ?? "",
|
|
59
|
+
fieldPath: f.fieldPath ?? "",
|
|
60
|
+
operator: f.operator ?? "",
|
|
61
|
+
values: sortedValues,
|
|
62
|
+
};
|
|
63
|
+
})
|
|
64
|
+
.filter((f): f is NonNullable<typeof f> => f !== null)
|
|
65
|
+
.sort((a, b) => {
|
|
66
|
+
const objectCompare = a.objectApiName.localeCompare(b.objectApiName);
|
|
67
|
+
if (objectCompare !== 0) return objectCompare;
|
|
68
|
+
|
|
69
|
+
const fieldCompare = a.fieldPath.localeCompare(b.fieldPath);
|
|
70
|
+
if (fieldCompare !== 0) return fieldCompare;
|
|
71
|
+
|
|
72
|
+
return a.operator.localeCompare(b.operator);
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
return JSON.stringify(normalized);
|
|
76
|
+
}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Debounce Utility
|
|
3
|
+
*
|
|
4
|
+
* Provides debouncing functionality for functions with React-safe cleanup methods.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Interface for the debounced function, exposing utility methods.
|
|
9
|
+
*/
|
|
10
|
+
export interface DebouncedFunc<T extends (...args: any[]) => any> {
|
|
11
|
+
/**
|
|
12
|
+
* Call the original function, but delayed.
|
|
13
|
+
*/
|
|
14
|
+
(...args: Parameters<T>): void;
|
|
15
|
+
/**
|
|
16
|
+
* Cancel any pending execution.
|
|
17
|
+
*/
|
|
18
|
+
cancel: () => void;
|
|
19
|
+
/**
|
|
20
|
+
* Immediately execute the pending function (if any) and clear the timer.
|
|
21
|
+
* Useful for saving data before unmounting.
|
|
22
|
+
*/
|
|
23
|
+
flush: () => void;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Creates a debounced function that delays invoking func until after wait milliseconds
|
|
28
|
+
* have elapsed since the last time the debounced function was invoked.
|
|
29
|
+
*
|
|
30
|
+
* @param func - The function to debounce
|
|
31
|
+
* @param wait - The number of milliseconds to delay
|
|
32
|
+
* @returns A debounced function with .cancel() and .flush() methods
|
|
33
|
+
*
|
|
34
|
+
* @remarks
|
|
35
|
+
* - Includes .cancel() method for cleanup in React useEffects
|
|
36
|
+
* - Includes .flush() method to immediately execute pending calls
|
|
37
|
+
* - Preserves function context (this binding)
|
|
38
|
+
* - Type-safe with TypeScript generics
|
|
39
|
+
*
|
|
40
|
+
* @example
|
|
41
|
+
* ```tsx
|
|
42
|
+
* const debouncedSearch = debounce((query: string) => {
|
|
43
|
+
* performSearch(query);
|
|
44
|
+
* }, 300);
|
|
45
|
+
*
|
|
46
|
+
* // In useEffect cleanup
|
|
47
|
+
* return () => debouncedSearch.cancel();
|
|
48
|
+
* ```
|
|
49
|
+
*/
|
|
50
|
+
export function debounce<T extends (...args: any[]) => any>(
|
|
51
|
+
func: T,
|
|
52
|
+
wait: number,
|
|
53
|
+
): DebouncedFunc<T> {
|
|
54
|
+
// 1. Type Safety: Use a generic return type compatible with Browser and Node
|
|
55
|
+
let timeoutId: ReturnType<typeof setTimeout> | null = null;
|
|
56
|
+
let lastContext: ThisParameterType<T> | null = null;
|
|
57
|
+
let lastArgs: Parameters<T> | null = null;
|
|
58
|
+
function debounced(this: ThisParameterType<T>, ...args: Parameters<T>) {
|
|
59
|
+
// 2. Context Safety: Capture 'this' to support class methods
|
|
60
|
+
lastContext = this;
|
|
61
|
+
lastArgs = args;
|
|
62
|
+
if (timeoutId) {
|
|
63
|
+
clearTimeout(timeoutId);
|
|
64
|
+
}
|
|
65
|
+
timeoutId = setTimeout(() => {
|
|
66
|
+
func.apply(lastContext, lastArgs as Parameters<T>);
|
|
67
|
+
timeoutId = null;
|
|
68
|
+
lastArgs = null;
|
|
69
|
+
lastContext = null;
|
|
70
|
+
}, wait);
|
|
71
|
+
}
|
|
72
|
+
// 3. React Safety: Add a cancel method to clear pending timers
|
|
73
|
+
debounced.cancel = () => {
|
|
74
|
+
if (timeoutId) {
|
|
75
|
+
clearTimeout(timeoutId);
|
|
76
|
+
timeoutId = null;
|
|
77
|
+
}
|
|
78
|
+
lastArgs = null;
|
|
79
|
+
lastContext = null;
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
debounced.flush = () => {
|
|
83
|
+
if (timeoutId && lastArgs) {
|
|
84
|
+
func.apply(lastContext, lastArgs);
|
|
85
|
+
debounced.cancel();
|
|
86
|
+
}
|
|
87
|
+
};
|
|
88
|
+
return debounced;
|
|
89
|
+
}
|