@salesforce/ui-bundle-template-feature-angular-search 0.0.0-stage → 12.14.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE.txt +82 -0
- package/README.md +75 -2
- package/dist/.forceignore +15 -0
- package/dist/.husky/pre-commit +4 -0
- package/dist/.prettierignore +11 -0
- package/dist/.prettierrc +17 -0
- package/dist/CHANGELOG.md +5375 -0
- package/dist/README.md +83 -0
- package/dist/config/project-scratch-def.json +13 -0
- package/dist/eslint.config.js +7 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/.forceignore +15 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/.graphqlrc.yml +2 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/.postcssrc.json +5 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/.prettierignore +8 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/.prettierrc +12 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/CHANGELOG.md +4 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/README.md +85 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/angular.json +98 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/codegen.yml +95 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/components.json +6 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/e2e/app.spec.ts +15 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/esbuild/api-version.mjs +17 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/esbuild/graphql-codegen.mjs +13 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/eslint-plugin-angular-graphql.js +148 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/eslint.config.js +77 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/feature-angular-search.uibundle-meta.xml +7 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/middleware/html.mjs +3 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/middleware/proxy.mjs +12 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/package.json +69 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/playwright.config.ts +25 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/public/favicon.ico +0 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/scripts/get-graphql-schema.mjs +69 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/scripts/rewrite-e2e-assets.mjs +30 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/api/data-client.service.spec.ts +184 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/api/data-client.service.ts +74 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/app.config.ts +20 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/app.html +1 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/app.routes.ts +27 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/app.spec.ts +18 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/app.ts +15 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/components/layout/app-layout/app-layout.html +51 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/components/layout/app-layout/app-layout.spec.ts +63 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/components/layout/app-layout/app-layout.ts +27 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/components/ui/alert/alert.html +27 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/components/ui/alert/alert.ts +41 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/components/ui/button/button.html +27 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/components/ui/button/button.ts +59 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/components/ui/card/card.ts +100 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/components/ui/collapsible/collapsible.html +38 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/components/ui/collapsible/collapsible.ts +21 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/components/ui/date-picker/date-picker.html +20 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/components/ui/date-picker/date-picker.ts +49 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/components/ui/date-range-picker/date-range-picker.html +20 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/components/ui/date-range-picker/date-range-picker.ts +69 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/components/ui/dialog/dialog.html +20 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/components/ui/dialog/dialog.ts +40 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/components/ui/dropdown-menu/dropdown-menu.html +20 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/components/ui/dropdown-menu/dropdown-menu.ts +100 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/components/ui/field/field.html +15 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/components/ui/field/field.ts +28 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/components/ui/field-appearance.ts +8 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/components/ui/field-size.ts +8 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/components/ui/icon/icon.ts +118 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/components/ui/input/input.html +34 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/components/ui/input/input.ts +79 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/components/ui/label/label.ts +21 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/components/ui/paginator/paginator.html +74 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/components/ui/paginator/paginator.ts +93 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/components/ui/paginator/types.ts +13 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/components/ui/popover/popover.html +13 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/components/ui/popover/popover.ts +37 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/components/ui/select/select.html +36 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/components/ui/select/select.ts +63 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/components/ui/separator/separator.ts +31 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/components/ui/skeleton/skeleton.ts +20 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/components/ui/spinner/spinner.ts +28 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/features/search/adapters/registry.ts +28 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/features/search/adapters/sobject/index.ts +19 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/features/search/adapters/sobject/parse-response.ts +57 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/features/search/adapters/sobject/query-fragment.ts +169 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/features/search/adapters/types.ts +44 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/features/search/api/search-response.spec.ts +114 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/features/search/api/search-response.ts +73 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/features/search/api/search.service.spec.ts +124 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/features/search/api/search.service.ts +80 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/features/search/components/active-filters/active-filters.html +23 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/features/search/components/active-filters/active-filters.spec.ts +73 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/features/search/components/active-filters/active-filters.ts +77 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/features/search/components/filter-panel/default-filter-panel.html +49 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/features/search/components/filter-panel/default-filter-panel.ts +87 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/features/search/components/filter-panel/filter-box.html +13 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/features/search/components/filter-panel/filter-box.ts +39 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/features/search/components/global-search-box/global-search-box.html +16 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/features/search/components/global-search-box/global-search-box.ts +50 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/features/search/components/results/default-result-row.html +19 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/features/search/components/results/default-result-row.ts +91 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/features/search/components/results/merged-search-results.html +99 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/features/search/components/results/merged-search-results.ts +145 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/features/search/components/results/result-item.ts +53 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/features/search/components/results/search-results.html +10 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/features/search/components/results/search-results.ts +33 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/features/search/components/results/source-section.html +84 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/features/search/components/results/source-section.ts +146 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/features/search/components/scope/scope-selector.html +9 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/features/search/components/scope/scope-selector.ts +45 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/features/search/components/search/search.html +55 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/features/search/components/search/search.ts +118 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/features/search/components/search-bar/search-bar.html +10 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/features/search/components/search-bar/search-bar.spec.ts +65 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/features/search/components/search-bar/search-bar.ts +72 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/features/search/components/sort-control/sort-control.html +24 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/features/search/components/sort-control/sort-control.spec.ts +67 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/features/search/components/sort-control/sort-control.ts +59 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/features/search/constants.ts +17 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/features/search/default-search-config.ts +83 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/features/search/directives/search-result-template/search-result-template.ts +44 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/features/search/filters/boolean-filter.html +8 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/features/search/filters/boolean-filter.spec.ts +41 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/features/search/filters/boolean-filter.ts +42 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/features/search/filters/date-filter.html +20 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/features/search/filters/date-filter.spec.ts +56 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/features/search/filters/date-filter.ts +78 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/features/search/filters/date-range-filter.html +43 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/features/search/filters/date-range-filter.spec.ts +70 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/features/search/filters/date-range-filter.ts +125 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/features/search/filters/filter-field-wrapper.html +16 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/features/search/filters/filter-field-wrapper.spec.ts +28 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/features/search/filters/filter-field-wrapper.ts +24 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/features/search/filters/filter-types.spec.ts +27 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/features/search/filters/filter-types.ts +64 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/features/search/filters/multi-select-filter.html +11 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/features/search/filters/multi-select-filter.spec.ts +42 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/features/search/filters/multi-select-filter.ts +42 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/features/search/filters/numeric-range-filter.html +32 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/features/search/filters/numeric-range-filter.spec.ts +75 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/features/search/filters/numeric-range-filter.ts +117 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/features/search/filters/select-filter.html +8 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/features/search/filters/select-filter.spec.ts +43 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/features/search/filters/select-filter.ts +40 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/features/search/filters/text-filter.html +9 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/features/search/filters/text-filter.spec.ts +54 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/features/search/filters/text-filter.ts +70 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/features/search/index.ts +55 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/features/search/query/build-search-query.spec.ts +157 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/features/search/query/build-search-query.ts +95 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/features/search/state/filter-mapping.ts +48 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/features/search/state/search-state.service.spec.ts +293 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/features/search/state/search-state.service.ts +735 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/features/search/state/search-state.types.ts +48 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/features/search/types/filter.types.ts +57 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/features/search/types/index.ts +11 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/features/search/types/scope.types.ts +10 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/features/search/types/search-config.types.ts +110 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/features/search/types/search-result.types.ts +68 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/features/search/types/sort.types.ts +15 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/features/search/utils/debounce.ts +23 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/features/search/utils/field-utils.ts +20 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/features/search/utils/filter-utils.spec.ts +335 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/features/search/utils/filter-utils.ts +354 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/features/search/utils/identifier.ts +19 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/features/search/utils/merge-utils.spec.ts +199 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/features/search/utils/merge-utils.ts +177 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/features/search/utils/scope-utils.ts +19 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/features/search/utils/sort-utils.ts +32 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/features/search/utils/validate-config.spec.ts +48 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/features/search/utils/validate-config.ts +34 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/pages/home/home.html +6 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/pages/home/home.spec.ts +23 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/pages/home/home.ts +13 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/pages/not-found/not-found.html +12 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/pages/not-found/not-found.spec.ts +33 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/pages/not-found/not-found.ts +15 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/pages/search/search-page.html +5 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/pages/search/search-page.ts +19 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/shared/alert/hlm-alert-action.ts +14 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/shared/alert/hlm-alert-description.ts +17 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/shared/alert/hlm-alert-title.ts +17 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/shared/alert/hlm-alert.ts +35 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/shared/alert/index.ts +16 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/shared/button/hlm-button.token.ts +22 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/shared/button/hlm-button.ts +72 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/shared/button/index.ts +6 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/shared/calendar/hlm-calendar-multi.ts +195 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/shared/calendar/hlm-calendar-range.ts +194 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/shared/calendar/hlm-calendar.ts +189 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/shared/calendar/hlm-month-year-calendar.ts +119 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/shared/calendar/index.ts +16 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/shared/card/hlm-card-action.ts +12 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/shared/card/hlm-card-avatar.ts +14 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/shared/card/hlm-card-content.ts +12 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/shared/card/hlm-card-description.ts +12 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/shared/card/hlm-card-footer.ts +12 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/shared/card/hlm-card-header.ts +15 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/shared/card/hlm-card-title.ts +12 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/shared/card/hlm-card.token.ts +19 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/shared/card/hlm-card.ts +22 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/shared/card/index.ts +28 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/shared/collapsible/hlm-collapsible-content.ts +14 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/shared/collapsible/hlm-collapsible-trigger.ts +9 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/shared/collapsible/hlm-collapsible.ts +15 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/shared/collapsible/index.ts +13 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/shared/date-picker/hlm-date-multi-input.ts +104 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/shared/date-picker/hlm-date-picker-anchor.ts +23 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/shared/date-picker/hlm-date-picker-input.ts +118 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/shared/date-picker/hlm-date-picker-multi.token.ts +109 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/shared/date-picker/hlm-date-picker-multi.ts +220 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/shared/date-picker/hlm-date-picker-trigger.ts +104 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/shared/date-picker/hlm-date-picker.token.ts +69 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/shared/date-picker/hlm-date-picker.ts +203 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/shared/date-picker/hlm-date-range-input.ts +120 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/shared/date-picker/hlm-date-range-picker.token.ts +86 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/shared/date-picker/hlm-date-range-picker.ts +252 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/shared/date-picker/hlm-month-year-input.ts +105 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/shared/date-picker/hlm-month-year-picker.token.ts +89 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/shared/date-picker/hlm-month-year-picker.ts +196 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/shared/date-picker/index.ts +38 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/shared/dialog/hlm-dialog-close.ts +9 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/shared/dialog/hlm-dialog-content.ts +74 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/shared/dialog/hlm-dialog-description.ts +17 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/shared/dialog/hlm-dialog-footer.ts +15 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/shared/dialog/hlm-dialog-header.ts +12 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/shared/dialog/hlm-dialog-overlay.ts +27 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/shared/dialog/hlm-dialog-portal.ts +8 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/shared/dialog/hlm-dialog-title.ts +14 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/shared/dialog/hlm-dialog-trigger.ts +14 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/shared/dialog/hlm-dialog.service.ts +46 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/shared/dialog/hlm-dialog.ts +24 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/shared/dialog/index.ts +35 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/shared/dropdown-menu/hlm-dropdown-menu-checkbox-indicator.ts +21 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/shared/dropdown-menu/hlm-dropdown-menu-checkbox.ts +54 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/shared/dropdown-menu/hlm-dropdown-menu-focus-on-hover.ts +35 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/shared/dropdown-menu/hlm-dropdown-menu-group.ts +14 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/shared/dropdown-menu/hlm-dropdown-menu-item-sub-indicator.ts +19 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/shared/dropdown-menu/hlm-dropdown-menu-item.ts +42 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/shared/dropdown-menu/hlm-dropdown-menu-label.ts +20 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/shared/dropdown-menu/hlm-dropdown-menu-radio-indicator.ts +21 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/shared/dropdown-menu/hlm-dropdown-menu-radio.ts +49 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/shared/dropdown-menu/hlm-dropdown-menu-separator.ts +12 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/shared/dropdown-menu/hlm-dropdown-menu-shortcut.ts +15 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/shared/dropdown-menu/hlm-dropdown-menu-sub-trigger.ts +52 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/shared/dropdown-menu/hlm-dropdown-menu-sub.ts +53 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/shared/dropdown-menu/hlm-dropdown-menu-token.ts +26 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/shared/dropdown-menu/hlm-dropdown-menu-trigger.ts +46 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/shared/dropdown-menu/hlm-dropdown-menu.ts +57 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/shared/dropdown-menu/index.ts +49 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/shared/field/hlm-field-content.ts +12 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/shared/field/hlm-field-description.ts +53 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/shared/field/hlm-field-error.ts +100 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/shared/field/hlm-field-group.ts +15 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/shared/field/hlm-field-label.ts +17 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/shared/field/hlm-field-legend.ts +19 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/shared/field/hlm-field-separator.ts +24 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/shared/field/hlm-field-set.ts +15 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/shared/field/hlm-field-title.ts +15 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/shared/field/hlm-field.ts +47 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/shared/field/index.ts +34 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/shared/input/hlm-input.ts +21 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/shared/input/index.ts +5 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/shared/input-group/hlm-input-group-addon.ts +40 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/shared/input-group/hlm-input-group-button.ts +47 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/shared/input-group/hlm-input-group-input.ts +17 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/shared/input-group/hlm-input-group-text.ts +14 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/shared/input-group/hlm-input-group.ts +18 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/shared/input-group/index.ts +19 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/shared/label/hlm-label.ts +17 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/shared/label/index.ts +5 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/shared/label/label.html +11 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/shared/pagination/hlm-numbered-pagination-query-params.ts +191 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/shared/pagination/hlm-numbered-pagination.ts +290 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/shared/pagination/hlm-pagination-content.ts +12 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/shared/pagination/hlm-pagination-ellipsis.ts +27 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/shared/pagination/hlm-pagination-item.ts +7 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/shared/pagination/hlm-pagination-link.ts +51 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/shared/pagination/hlm-pagination-next.ts +65 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/shared/pagination/hlm-pagination-previous.ts +65 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/shared/pagination/hlm-pagination.ts +19 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/shared/pagination/index.ts +31 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/shared/popover/hlm-popover-content.ts +25 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/shared/popover/hlm-popover-description.ts +12 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/shared/popover/hlm-popover-header.ts +12 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/shared/popover/hlm-popover-portal.ts +8 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/shared/popover/hlm-popover-title.ts +12 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/shared/popover/hlm-popover-trigger.ts +14 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/shared/popover/hlm-popover.ts +23 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/shared/popover/index.ts +25 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/shared/select/hlm-select-content.ts +44 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/shared/select/hlm-select-group.ts +14 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/shared/select/hlm-select-item.ts +36 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/shared/select/hlm-select-label.ts +14 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/shared/select/hlm-select-multiple.ts +37 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/shared/select/hlm-select-placeholder.ts +17 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/shared/select/hlm-select-portal.ts +8 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/shared/select/hlm-select-scroll-down.ts +22 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/shared/select/hlm-select-scroll-up.ts +22 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/shared/select/hlm-select-separator.ts +14 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/shared/select/hlm-select-trigger.ts +59 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/shared/select/hlm-select-value-template.ts +5 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/shared/select/hlm-select-value.ts +18 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/shared/select/hlm-select-values-content.ts +9 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/shared/select/hlm-select-values.ts +5 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/shared/select/hlm-select.ts +37 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/shared/select/index.ts +52 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/shared/separator/hlm-separator.ts +19 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/shared/separator/index.ts +5 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/shared/skeleton/hlm-skeleton.ts +14 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/shared/skeleton/index.ts +5 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/shared/spinner/hlm-spinner.ts +26 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/shared/spinner/index.ts +5 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/shared/utils/hlm.ts +313 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/shared/utils/index.ts +2 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/shared/utils/provide-spartan-hlm.ts +34 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/utils/async-data.ts +99 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/index.html +13 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/main.ts +5 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/styles.css +139 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/src/types/sf-globals.d.ts +9 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/tsconfig.app.json +11 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/tsconfig.json +36 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/tsconfig.spec.json +10 -0
- package/dist/force-app/main/default/uiBundles/feature-angular-search/ui-bundle.json +7 -0
- package/dist/jest.config.js +6 -0
- package/dist/package-lock.json +12554 -0
- package/dist/package.json +46 -0
- package/dist/scripts/apex/hello.apex +10 -0
- package/dist/scripts/gitignore-templates.json +4 -0
- package/dist/scripts/graphql-search.sh +191 -0
- package/dist/scripts/network-senders.mjs +84 -0
- package/dist/scripts/org-setup-config-schema.mjs +132 -0
- package/dist/scripts/org-setup-dev.mjs +114 -0
- package/dist/scripts/org-setup-url.mjs +108 -0
- package/dist/scripts/org-setup-utils.mjs +569 -0
- package/dist/scripts/org-setup-xml.mjs +283 -0
- package/dist/scripts/org-setup.config.json +5 -0
- package/dist/scripts/org-setup.mjs +2545 -0
- package/dist/scripts/sf-project-setup.mjs +103 -0
- package/dist/scripts/soql/account.soql +6 -0
- package/dist/scripts/validate-org-setup-config.mjs +38 -0
- package/dist/sfdx-project.json +12 -0
- package/package.json +43 -4
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2026, Salesforce, Inc.,
|
|
3
|
+
* All rights reserved.
|
|
4
|
+
* For full license text, see the LICENSE.txt file
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const IDENTIFIER_PATTERN = /^[A-Za-z_][A-Za-z0-9_]*$/;
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Throws unless `name` is a valid GraphQL identifier. Anything interpolated
|
|
11
|
+
* into a query document must pass this first.
|
|
12
|
+
*/
|
|
13
|
+
export function assertValidIdentifier(name: string, kind: string): void {
|
|
14
|
+
if (typeof name !== "string" || !IDENTIFIER_PATTERN.test(name)) {
|
|
15
|
+
throw new Error(
|
|
16
|
+
`Invalid ${kind} "${name}". Must match /^[A-Za-z_][A-Za-z0-9_]*$/ to be a valid GraphQL identifier.`,
|
|
17
|
+
);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2026, Salesforce, Inc.,
|
|
3
|
+
* All rights reserved.
|
|
4
|
+
* For full license text, see the LICENSE.txt file
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { describe, it, expect } from "vitest";
|
|
8
|
+
import {
|
|
9
|
+
computeMergedPagination,
|
|
10
|
+
computePerSourcePagination,
|
|
11
|
+
filterToGlobalPage,
|
|
12
|
+
mergeNodes,
|
|
13
|
+
mergedFetchSize,
|
|
14
|
+
resolvePagination,
|
|
15
|
+
validatePageSize,
|
|
16
|
+
windowMergedPage,
|
|
17
|
+
} from "./merge-utils";
|
|
18
|
+
import type { SearchConfig } from "../types/search-config.types";
|
|
19
|
+
|
|
20
|
+
const sources = [
|
|
21
|
+
{ key: "a", nodes: ["a1", "a2", "a3", "a4"], weight: 4 },
|
|
22
|
+
{ key: "b", nodes: ["b1", "b2"], weight: 2 },
|
|
23
|
+
];
|
|
24
|
+
|
|
25
|
+
const order = (items: { node: unknown }[]) => items.map((i) => i.node);
|
|
26
|
+
|
|
27
|
+
describe("resolvePagination", () => {
|
|
28
|
+
const base: SearchConfig = { sources: [] };
|
|
29
|
+
|
|
30
|
+
it("applies defaults when pagination is omitted", () => {
|
|
31
|
+
expect(resolvePagination(base)).toEqual({
|
|
32
|
+
mode: "per-source",
|
|
33
|
+
mergeOrder: "sequential",
|
|
34
|
+
pageSize: 10,
|
|
35
|
+
pageSizeOptions: [10, 25, 50],
|
|
36
|
+
});
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
it("uses the configured values", () => {
|
|
40
|
+
const resolved = resolvePagination({
|
|
41
|
+
...base,
|
|
42
|
+
pagination: {
|
|
43
|
+
mode: "merged",
|
|
44
|
+
mergeOrder: "proportional",
|
|
45
|
+
pageSize: 6,
|
|
46
|
+
pageSizeOptions: [6, 12],
|
|
47
|
+
},
|
|
48
|
+
});
|
|
49
|
+
expect(resolved).toMatchObject({ mode: "merged", mergeOrder: "proportional", pageSize: 6 });
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
it("falls back to the first option when pageSize is missing", () => {
|
|
53
|
+
const resolved = resolvePagination({
|
|
54
|
+
...base,
|
|
55
|
+
pagination: { pageSizeOptions: [5, 10] } as SearchConfig["pagination"],
|
|
56
|
+
});
|
|
57
|
+
expect(resolved.pageSize).toBe(5);
|
|
58
|
+
});
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
describe("validatePageSize", () => {
|
|
62
|
+
const pagination = resolvePagination({
|
|
63
|
+
sources: [],
|
|
64
|
+
pagination: { pageSize: 10, pageSizeOptions: [10, 25] },
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
it("keeps an allowed size and falls back to the default otherwise", () => {
|
|
68
|
+
expect(validatePageSize(pagination, 25)).toBe(25);
|
|
69
|
+
expect(validatePageSize(pagination, 7)).toBe(10);
|
|
70
|
+
});
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
describe("mergedFetchSize", () => {
|
|
74
|
+
it("fetches the whole front-anchored window", () => {
|
|
75
|
+
expect(mergedFetchSize(0, 6)).toBe(6);
|
|
76
|
+
expect(mergedFetchSize(2, 6)).toBe(18);
|
|
77
|
+
});
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
describe("mergeNodes", () => {
|
|
81
|
+
it("sequential: source by source in config order", () => {
|
|
82
|
+
expect(order(mergeNodes(sources, "sequential"))).toEqual(["a1", "a2", "a3", "a4", "b1", "b2"]);
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
it("interleaved: round-robin until the longer source is exhausted", () => {
|
|
86
|
+
expect(order(mergeNodes(sources, "interleaved"))).toEqual(["a1", "b1", "a2", "b2", "a3", "a4"]);
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
it("proportional: spreads sources by their weight", () => {
|
|
90
|
+
// keys: a = .125 .375 .625 .875, b = .25 .75
|
|
91
|
+
expect(order(mergeNodes(sources, "proportional"))).toEqual([
|
|
92
|
+
"a1",
|
|
93
|
+
"b1",
|
|
94
|
+
"a2",
|
|
95
|
+
"a3",
|
|
96
|
+
"b2",
|
|
97
|
+
"a4",
|
|
98
|
+
]);
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
it("proportional: treats a zero weight as 1 and breaks ties by source order", () => {
|
|
102
|
+
const merged = mergeNodes(
|
|
103
|
+
[
|
|
104
|
+
{ key: "a", nodes: ["a1"], weight: 0 },
|
|
105
|
+
{ key: "b", nodes: ["b1"], weight: 0 },
|
|
106
|
+
],
|
|
107
|
+
"proportional",
|
|
108
|
+
);
|
|
109
|
+
expect(order(merged)).toEqual(["a1", "b1"]);
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
it("tags each node with its source key", () => {
|
|
113
|
+
expect(mergeNodes(sources, "sequential")[4]).toEqual({ sourceKey: "b", node: "b1" });
|
|
114
|
+
});
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
describe("merged pagination", () => {
|
|
118
|
+
it("computes page count and navigation flags", () => {
|
|
119
|
+
expect(computeMergedPagination(13, 6, 1, [6, 12])).toEqual({
|
|
120
|
+
pageIndex: 1,
|
|
121
|
+
pageCount: 3,
|
|
122
|
+
pageSize: 6,
|
|
123
|
+
pageSizeOptions: [6, 12],
|
|
124
|
+
hasNextPage: true,
|
|
125
|
+
hasPreviousPage: true,
|
|
126
|
+
totalCount: 13,
|
|
127
|
+
});
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
it("clamps the page index when the total shrinks", () => {
|
|
131
|
+
const state = computeMergedPagination(7, 6, 5, [6]);
|
|
132
|
+
expect(state.pageIndex).toBe(1);
|
|
133
|
+
expect(state.hasNextPage).toBe(false);
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
it("reports zero pages for no results", () => {
|
|
137
|
+
expect(computeMergedPagination(0, 6, 3, [6])).toMatchObject({
|
|
138
|
+
pageIndex: 0,
|
|
139
|
+
pageCount: 0,
|
|
140
|
+
hasNextPage: false,
|
|
141
|
+
hasPreviousPage: false,
|
|
142
|
+
});
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
it("windows the merged list into a page", () => {
|
|
146
|
+
const items = mergeNodes(sources, "sequential");
|
|
147
|
+
expect(order(windowMergedPage(items, 0, 4))).toEqual(["a1", "a2", "a3", "a4"]);
|
|
148
|
+
expect(order(windowMergedPage(items, 1, 4))).toEqual(["b1", "b2"]);
|
|
149
|
+
});
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
describe("per-source pagination", () => {
|
|
153
|
+
it("uses the furthest source for the page index and the widest span for the count", () => {
|
|
154
|
+
const state = computePerSourcePagination(
|
|
155
|
+
[
|
|
156
|
+
{ key: "a", pageIndex: 1, hasNextPage: true, totalCount: 35, nodeCount: 10 },
|
|
157
|
+
{ key: "b", pageIndex: 0, hasNextPage: false, totalCount: 4, nodeCount: 4 },
|
|
158
|
+
],
|
|
159
|
+
10,
|
|
160
|
+
[10, 25],
|
|
161
|
+
);
|
|
162
|
+
|
|
163
|
+
expect(state).toMatchObject({
|
|
164
|
+
pageIndex: 1,
|
|
165
|
+
pageCount: 4,
|
|
166
|
+
totalCount: 39,
|
|
167
|
+
hasNextPage: true,
|
|
168
|
+
hasPreviousPage: true,
|
|
169
|
+
});
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
it("estimates a lower bound when totalCount is absent", () => {
|
|
173
|
+
const state = computePerSourcePagination(
|
|
174
|
+
[{ key: "a", pageIndex: 1, hasNextPage: true, totalCount: null, nodeCount: 10 }],
|
|
175
|
+
10,
|
|
176
|
+
[10],
|
|
177
|
+
);
|
|
178
|
+
|
|
179
|
+
expect(state.pageCount).toBe(3);
|
|
180
|
+
expect(state.totalCount).toBe(10);
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
it("reports zero pages for no results", () => {
|
|
184
|
+
const state = computePerSourcePagination(
|
|
185
|
+
[{ key: "a", pageIndex: 0, hasNextPage: false, totalCount: 0, nodeCount: 0 }],
|
|
186
|
+
10,
|
|
187
|
+
[10],
|
|
188
|
+
);
|
|
189
|
+
|
|
190
|
+
expect(state.pageCount).toBe(0);
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
it("drops nodes from sources left behind the global page", () => {
|
|
194
|
+
const items = mergeNodes(sources, "sequential");
|
|
195
|
+
const filtered = filterToGlobalPage(items, { a: 1, b: 0 }, 1);
|
|
196
|
+
|
|
197
|
+
expect(order(filtered)).toEqual(["a1", "a2", "a3", "a4"]);
|
|
198
|
+
});
|
|
199
|
+
});
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2026, Salesforce, Inc.,
|
|
3
|
+
* All rights reserved.
|
|
4
|
+
* For full license text, see the LICENSE.txt file
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Pure pagination/merge logic for multi-source search.
|
|
9
|
+
*
|
|
10
|
+
* Merged mode treats the cumulative result set as one list windowed into fixed
|
|
11
|
+
* pages: every in-scope source fetches its first `(page + 1) * pageSize` rows
|
|
12
|
+
* (no cursor), the rows are ordered per `mergeOrder`, and the page slice is
|
|
13
|
+
* taken. Per-source mode keeps independent cursors per source.
|
|
14
|
+
*/
|
|
15
|
+
import { DEFAULT_PAGE_SIZE, DEFAULT_PAGE_SIZE_OPTIONS } from "../constants";
|
|
16
|
+
import type { MergeOrder, PaginationMode, SearchConfig } from "../types/search-config.types";
|
|
17
|
+
import type { GlobalPaginationState, MergedResultItem } from "../types/search-result.types";
|
|
18
|
+
|
|
19
|
+
export interface ResolvedPagination {
|
|
20
|
+
mode: PaginationMode;
|
|
21
|
+
mergeOrder: MergeOrder;
|
|
22
|
+
pageSize: number;
|
|
23
|
+
pageSizeOptions: number[];
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/** Resolves the single global pagination config, filling in defaults. */
|
|
27
|
+
export function resolvePagination(config: SearchConfig): ResolvedPagination {
|
|
28
|
+
const p = config.pagination;
|
|
29
|
+
const pageSizeOptions =
|
|
30
|
+
p?.pageSizeOptions && p.pageSizeOptions.length > 0
|
|
31
|
+
? p.pageSizeOptions
|
|
32
|
+
: DEFAULT_PAGE_SIZE_OPTIONS;
|
|
33
|
+
return {
|
|
34
|
+
mode: p?.mode ?? "per-source",
|
|
35
|
+
mergeOrder: p?.mergeOrder ?? "sequential",
|
|
36
|
+
pageSize: p?.pageSize ?? pageSizeOptions[0] ?? DEFAULT_PAGE_SIZE,
|
|
37
|
+
pageSizeOptions,
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/** Clamps a requested size to the configured options. */
|
|
42
|
+
export function validatePageSize(pagination: ResolvedPagination, size: number): number {
|
|
43
|
+
const valid = pagination.pageSizeOptions;
|
|
44
|
+
if (valid.length === 0) return size;
|
|
45
|
+
return valid.includes(size) ? size : pagination.pageSize;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/** Rows each source must fetch (from its front) to compute merged page `pageIndex`. */
|
|
49
|
+
export function mergedFetchSize(pageIndex: number, pageSize: number): number {
|
|
50
|
+
return (pageIndex + 1) * pageSize;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export interface MergeSourceInput {
|
|
54
|
+
key: string;
|
|
55
|
+
nodes: unknown[];
|
|
56
|
+
/** Proportional weight: the source's true total, else the fetched length. */
|
|
57
|
+
weight: number;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Flattens every source's fetched nodes into one list ordered per `order`:
|
|
62
|
+
* - sequential: all of source 1, then source 2, ... (config order).
|
|
63
|
+
* - interleaved: round-robin, one node per source per round.
|
|
64
|
+
* - proportional: each node gets key (i + 0.5) / weight; sorting by key
|
|
65
|
+
* spreads each source evenly in proportion to its size.
|
|
66
|
+
*/
|
|
67
|
+
export function mergeNodes(sources: MergeSourceInput[], order: MergeOrder): MergedResultItem[] {
|
|
68
|
+
const out: MergedResultItem[] = [];
|
|
69
|
+
|
|
70
|
+
if (order === "interleaved") {
|
|
71
|
+
const maxLen = sources.reduce((m, l) => Math.max(m, l.nodes.length), 0);
|
|
72
|
+
for (let round = 0; round < maxLen; round++) {
|
|
73
|
+
for (const l of sources) {
|
|
74
|
+
if (round < l.nodes.length) out.push({ sourceKey: l.key, node: l.nodes[round] });
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
} else if (order === "proportional") {
|
|
78
|
+
const tagged = sources.flatMap((l, sIdx) =>
|
|
79
|
+
l.nodes.map((node, i) => ({
|
|
80
|
+
sourceKey: l.key,
|
|
81
|
+
node,
|
|
82
|
+
sIdx,
|
|
83
|
+
i,
|
|
84
|
+
sortKey: (i + 0.5) / (l.weight > 0 ? l.weight : 1),
|
|
85
|
+
})),
|
|
86
|
+
);
|
|
87
|
+
tagged.sort((a, b) => a.sortKey - b.sortKey || a.sIdx - b.sIdx || a.i - b.i);
|
|
88
|
+
for (const t of tagged) out.push({ sourceKey: t.sourceKey, node: t.node });
|
|
89
|
+
} else {
|
|
90
|
+
for (const l of sources) {
|
|
91
|
+
for (const node of l.nodes) out.push({ sourceKey: l.key, node });
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
return out;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/** Merged-mode pagination data; `pageIndex` is clamped if `totalCount` shrank. */
|
|
98
|
+
export function computeMergedPagination(
|
|
99
|
+
totalCount: number,
|
|
100
|
+
pageSize: number,
|
|
101
|
+
requestedPageIndex: number,
|
|
102
|
+
pageSizeOptions: readonly number[],
|
|
103
|
+
): GlobalPaginationState {
|
|
104
|
+
const pageCount = totalCount === 0 ? 0 : Math.ceil(totalCount / pageSize);
|
|
105
|
+
const pageIndex = pageCount === 0 ? 0 : Math.min(requestedPageIndex, pageCount - 1);
|
|
106
|
+
return {
|
|
107
|
+
pageIndex,
|
|
108
|
+
pageCount,
|
|
109
|
+
pageSize,
|
|
110
|
+
pageSizeOptions,
|
|
111
|
+
hasNextPage: pageIndex + 1 < pageCount,
|
|
112
|
+
hasPreviousPage: pageIndex > 0,
|
|
113
|
+
totalCount,
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/** The page-`pageIndex` slice of the merged list. */
|
|
118
|
+
export function windowMergedPage(
|
|
119
|
+
items: MergedResultItem[],
|
|
120
|
+
pageIndex: number,
|
|
121
|
+
pageSize: number,
|
|
122
|
+
): MergedResultItem[] {
|
|
123
|
+
const start = pageIndex * pageSize;
|
|
124
|
+
return items.slice(start, start + pageSize);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
export interface PerSourcePageInput {
|
|
128
|
+
key: string;
|
|
129
|
+
pageIndex: number;
|
|
130
|
+
hasNextPage: boolean;
|
|
131
|
+
totalCount: number | null;
|
|
132
|
+
nodeCount: number;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Per-source mode: a "global page" is the furthest-advanced in-scope source's
|
|
137
|
+
* page. `pageCount` is the max pages any source spans (from `totalCount`, else
|
|
138
|
+
* a lower bound from its own position).
|
|
139
|
+
*/
|
|
140
|
+
export function computePerSourcePagination(
|
|
141
|
+
sources: PerSourcePageInput[],
|
|
142
|
+
pageSize: number,
|
|
143
|
+
pageSizeOptions: readonly number[],
|
|
144
|
+
): GlobalPaginationState {
|
|
145
|
+
const pageIndex = sources.reduce((max, c) => Math.max(max, c.pageIndex), 0);
|
|
146
|
+
const totalCount = sources.reduce((sum, c) => sum + (c.totalCount ?? c.nodeCount), 0);
|
|
147
|
+
|
|
148
|
+
const pageCount = sources.reduce((max, c) => {
|
|
149
|
+
const span =
|
|
150
|
+
c.totalCount != null && pageSize > 0
|
|
151
|
+
? Math.max(1, Math.ceil(c.totalCount / pageSize))
|
|
152
|
+
: c.pageIndex + (c.hasNextPage ? 2 : 1);
|
|
153
|
+
return Math.max(max, span);
|
|
154
|
+
}, 0);
|
|
155
|
+
|
|
156
|
+
return {
|
|
157
|
+
pageIndex,
|
|
158
|
+
pageCount: totalCount === 0 ? 0 : pageCount,
|
|
159
|
+
pageSize,
|
|
160
|
+
pageSizeOptions,
|
|
161
|
+
hasNextPage: sources.some((c) => c.hasNextPage),
|
|
162
|
+
hasPreviousPage: pageIndex > 0,
|
|
163
|
+
totalCount,
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* Per-source mode: keeps only nodes from sources caught up to the current
|
|
169
|
+
* global page; a left-behind source already showed its final page earlier.
|
|
170
|
+
*/
|
|
171
|
+
export function filterToGlobalPage(
|
|
172
|
+
items: MergedResultItem[],
|
|
173
|
+
pageIndexBySource: Record<string, number>,
|
|
174
|
+
globalPageIndex: number,
|
|
175
|
+
): MergedResultItem[] {
|
|
176
|
+
return items.filter((item) => pageIndexBySource[item.sourceKey] === globalPageIndex);
|
|
177
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2026, Salesforce, Inc.,
|
|
3
|
+
* All rights reserved.
|
|
4
|
+
* For full license text, see the LICENSE.txt file
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import type { SearchConfig } from "../types/search-config.types";
|
|
8
|
+
import { ALL_SCOPE, type SearchScope } from "../types/scope.types";
|
|
9
|
+
|
|
10
|
+
/** True when `sourceKey` participates in the current scope. */
|
|
11
|
+
export function isSourceInScope(scope: SearchScope, sourceKey: string): boolean {
|
|
12
|
+
return scope === ALL_SCOPE || scope === sourceKey;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/** Returns `raw` when it is "all" or a configured source key, else "all". */
|
|
16
|
+
export function validateScope(config: SearchConfig, raw: string): SearchScope {
|
|
17
|
+
if (raw === ALL_SCOPE) return ALL_SCOPE;
|
|
18
|
+
return config.sources.some((s) => s.key === raw) ? raw : ALL_SCOPE;
|
|
19
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2026, Salesforce, Inc.,
|
|
3
|
+
* All rights reserved.
|
|
4
|
+
* For full license text, see the LICENSE.txt file
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import type { SortState } from "../types/sort.types";
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Sort state and order-by builder for search.
|
|
11
|
+
*
|
|
12
|
+
* The order-by output shape matches the Salesforce uiapi GraphQL convention:
|
|
13
|
+
* { [field]: { order: ASC|DESC, nulls: LAST } }
|
|
14
|
+
*
|
|
15
|
+
* The constants are stringly-typed here (rather than imported from codegen)
|
|
16
|
+
* because search builds its query at runtime and isn't tied to a
|
|
17
|
+
* specific generated schema.
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
const ORDER_ASC = "ASC";
|
|
21
|
+
const ORDER_DESC = "DESC";
|
|
22
|
+
const NULLS_LAST = "LAST";
|
|
23
|
+
|
|
24
|
+
export function buildOrderBy(sort: SortState | null): unknown {
|
|
25
|
+
if (!sort) return undefined;
|
|
26
|
+
return {
|
|
27
|
+
[sort.field]: {
|
|
28
|
+
order: sort.direction === "ASC" ? ORDER_ASC : ORDER_DESC,
|
|
29
|
+
nulls: NULLS_LAST,
|
|
30
|
+
},
|
|
31
|
+
};
|
|
32
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2026, Salesforce, Inc.,
|
|
3
|
+
* All rights reserved.
|
|
4
|
+
* For full license text, see the LICENSE.txt file
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { describe, it, expect } from "vitest";
|
|
8
|
+
import { validateSearchConfig } from "./validate-config";
|
|
9
|
+
import type { SearchConfig, SObjectSourceConfig } from "../types/search-config.types";
|
|
10
|
+
|
|
11
|
+
const source = (key: string, extra: Partial<SObjectSourceConfig> = {}): SObjectSourceConfig => ({
|
|
12
|
+
kind: "sobject",
|
|
13
|
+
key,
|
|
14
|
+
label: key,
|
|
15
|
+
objectName: "Account",
|
|
16
|
+
displayFields: ["Name"],
|
|
17
|
+
searchableFields: ["Name"],
|
|
18
|
+
...extra,
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
describe("validateSearchConfig", () => {
|
|
22
|
+
it("accepts a valid config", () => {
|
|
23
|
+
expect(() =>
|
|
24
|
+
validateSearchConfig({ sources: [source("a"), source("b")] } as SearchConfig),
|
|
25
|
+
).not.toThrow();
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
it("rejects an empty source list", () => {
|
|
29
|
+
expect(() => validateSearchConfig({ sources: [] } as unknown as SearchConfig)).toThrow(
|
|
30
|
+
/at least one/,
|
|
31
|
+
);
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
it("rejects duplicate keys and reserved prefixes", () => {
|
|
35
|
+
expect(() =>
|
|
36
|
+
validateSearchConfig({ sources: [source("a"), source("a")] } as SearchConfig),
|
|
37
|
+
).toThrow(/Duplicate source key/);
|
|
38
|
+
expect(() => validateSearchConfig({ sources: [source("__a")] } as SearchConfig)).toThrow(
|
|
39
|
+
/Invalid source key/,
|
|
40
|
+
);
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
it("rejects unsafe identifiers", () => {
|
|
44
|
+
expect(() =>
|
|
45
|
+
validateSearchConfig({ sources: [source("a", { objectName: "Account }" })] } as SearchConfig),
|
|
46
|
+
).toThrow(/Invalid objectName/);
|
|
47
|
+
});
|
|
48
|
+
});
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2026, Salesforce, Inc.,
|
|
3
|
+
* All rights reserved.
|
|
4
|
+
* For full license text, see the LICENSE.txt file
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { getAdapter } from "../adapters/registry";
|
|
8
|
+
import type { SearchConfig } from "../types/search-config.types";
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Validates a {@link SearchConfig} up front: at least one source, unique source
|
|
12
|
+
* keys, and every name that is interpolated into a query document. Throws on the
|
|
13
|
+
* first problem so a bad config fails at startup, not at first search.
|
|
14
|
+
*/
|
|
15
|
+
export function validateSearchConfig(config: SearchConfig): void {
|
|
16
|
+
if (config.sources.length === 0) {
|
|
17
|
+
throw new Error("SearchConfig requires at least one source.");
|
|
18
|
+
}
|
|
19
|
+
const keys = new Set<string>();
|
|
20
|
+
for (const source of config.sources) {
|
|
21
|
+
if (keys.has(source.key)) {
|
|
22
|
+
throw new Error(`Duplicate source key "${source.key}". Source keys must be unique.`);
|
|
23
|
+
}
|
|
24
|
+
keys.add(source.key);
|
|
25
|
+
getAdapter(source.kind).validateSource(source);
|
|
26
|
+
}
|
|
27
|
+
const p = config.pagination;
|
|
28
|
+
if (p) {
|
|
29
|
+
if (!(p.pageSize > 0)) throw new Error("pagination.pageSize must be greater than 0.");
|
|
30
|
+
if (p.pageSizeOptions.some((n) => !(n > 0))) {
|
|
31
|
+
throw new Error("pagination.pageSizeOptions must contain only positive numbers.");
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/pages/home/home.spec.ts
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { TestBed } from '@angular/core/testing';
|
|
2
|
+
import { HomeComponent } from './home';
|
|
3
|
+
|
|
4
|
+
describe('HomeComponent', () => {
|
|
5
|
+
beforeEach(async () => {
|
|
6
|
+
await TestBed.configureTestingModule({
|
|
7
|
+
imports: [HomeComponent],
|
|
8
|
+
}).compileComponents();
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
it('should create the component', () => {
|
|
12
|
+
const fixture = TestBed.createComponent(HomeComponent);
|
|
13
|
+
const component = fixture.componentInstance;
|
|
14
|
+
expect(component).toBeTruthy();
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
it('should render main landmark', async () => {
|
|
18
|
+
const fixture = TestBed.createComponent(HomeComponent);
|
|
19
|
+
await fixture.whenStable();
|
|
20
|
+
const compiled = fixture.nativeElement as HTMLElement;
|
|
21
|
+
expect(compiled.querySelector('main')).toBeTruthy();
|
|
22
|
+
});
|
|
23
|
+
});
|
package/dist/force-app/main/default/uiBundles/feature-angular-search/src/app/pages/home/home.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2026, Salesforce, Inc.,
|
|
3
|
+
* All rights reserved.
|
|
4
|
+
* For full license text, see the LICENSE.txt file
|
|
5
|
+
*/
|
|
6
|
+
import { ChangeDetectionStrategy, Component } from '@angular/core';
|
|
7
|
+
|
|
8
|
+
@Component({
|
|
9
|
+
selector: 'app-home',
|
|
10
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
11
|
+
templateUrl: './home.html',
|
|
12
|
+
})
|
|
13
|
+
export class HomeComponent {}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
<main class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-12">
|
|
2
|
+
<div class="text-center">
|
|
3
|
+
<h1 class="text-4xl font-bold text-gray-900 mb-4">404</h1>
|
|
4
|
+
<p class="text-lg text-gray-600 mb-8">Page not found</p>
|
|
5
|
+
<a
|
|
6
|
+
routerLink="/"
|
|
7
|
+
class="inline-block px-4 py-2 bg-blue-600 text-white rounded-md hover:bg-blue-700 transition-colors"
|
|
8
|
+
>
|
|
9
|
+
Go to Home
|
|
10
|
+
</a>
|
|
11
|
+
</div>
|
|
12
|
+
</main>
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { TestBed } from '@angular/core/testing';
|
|
2
|
+
import { provideRouter } from '@angular/router';
|
|
3
|
+
import { NotFoundComponent } from './not-found';
|
|
4
|
+
|
|
5
|
+
describe('NotFoundComponent', () => {
|
|
6
|
+
beforeEach(async () => {
|
|
7
|
+
await TestBed.configureTestingModule({
|
|
8
|
+
imports: [NotFoundComponent],
|
|
9
|
+
providers: [provideRouter([])],
|
|
10
|
+
}).compileComponents();
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
it('should create the component', () => {
|
|
14
|
+
const fixture = TestBed.createComponent(NotFoundComponent);
|
|
15
|
+
const component = fixture.componentInstance;
|
|
16
|
+
expect(component).toBeTruthy();
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
it('should render main landmark', async () => {
|
|
20
|
+
const fixture = TestBed.createComponent(NotFoundComponent);
|
|
21
|
+
await fixture.whenStable();
|
|
22
|
+
const compiled = fixture.nativeElement as HTMLElement;
|
|
23
|
+
expect(compiled.querySelector('main')).toBeTruthy();
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
it('should have a link to home', async () => {
|
|
27
|
+
const fixture = TestBed.createComponent(NotFoundComponent);
|
|
28
|
+
await fixture.whenStable();
|
|
29
|
+
const compiled = fixture.nativeElement as HTMLElement;
|
|
30
|
+
const link = compiled.querySelector('a');
|
|
31
|
+
expect(link?.getAttribute('href')).toBe('/');
|
|
32
|
+
});
|
|
33
|
+
});
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2026, Salesforce, Inc.,
|
|
3
|
+
* All rights reserved.
|
|
4
|
+
* For full license text, see the LICENSE.txt file
|
|
5
|
+
*/
|
|
6
|
+
import { ChangeDetectionStrategy, Component } from '@angular/core';
|
|
7
|
+
import { RouterLink } from '@angular/router';
|
|
8
|
+
|
|
9
|
+
@Component({
|
|
10
|
+
selector: 'app-not-found',
|
|
11
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
12
|
+
imports: [RouterLink],
|
|
13
|
+
templateUrl: './not-found.html',
|
|
14
|
+
})
|
|
15
|
+
export class NotFoundComponent {}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2026, Salesforce, Inc.,
|
|
3
|
+
* All rights reserved.
|
|
4
|
+
* For full license text, see the LICENSE.txt file
|
|
5
|
+
*/
|
|
6
|
+
import { ChangeDetectionStrategy, Component } from "@angular/core";
|
|
7
|
+
import { SearchComponent } from "../../features/search/components/search/search";
|
|
8
|
+
import { defaultSearchConfig } from "../../features/search/default-search-config";
|
|
9
|
+
|
|
10
|
+
/** The `/search` route: the drop-in search over the starter config. */
|
|
11
|
+
@Component({
|
|
12
|
+
selector: "app-search-page",
|
|
13
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
14
|
+
imports: [SearchComponent],
|
|
15
|
+
templateUrl: "./search-page.html",
|
|
16
|
+
})
|
|
17
|
+
export class SearchPageComponent {
|
|
18
|
+
protected readonly config = defaultSearchConfig;
|
|
19
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { Directive } from '@angular/core';
|
|
2
|
+
import { classes } from '@spartan-ng/styles/utils';
|
|
3
|
+
|
|
4
|
+
@Directive({
|
|
5
|
+
selector: '[hlmAlertAction]',
|
|
6
|
+
host: {
|
|
7
|
+
'data-slot': 'alert-action',
|
|
8
|
+
},
|
|
9
|
+
})
|
|
10
|
+
export class HlmAlertAction {
|
|
11
|
+
constructor() {
|
|
12
|
+
classes(() => 'absolute end-2 top-2');
|
|
13
|
+
}
|
|
14
|
+
}
|