@aglyn/plugins-crm 1.0.0-beta.143
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 +201 -0
- package/README.md +7 -0
- package/package.json +57 -0
- package/src/index.d.ts +21 -0
- package/src/index.js +29 -0
- package/src/index.js.map +1 -0
- package/src/lib/components/activity-list.d.ts +98 -0
- package/src/lib/components/activity-list.js +321 -0
- package/src/lib/components/activity-list.js.map +1 -0
- package/src/lib/components/activity-queries.d.ts +117 -0
- package/src/lib/components/activity-queries.js +198 -0
- package/src/lib/components/activity-queries.js.map +1 -0
- package/src/lib/components/add-to-list-button.d.ts +25 -0
- package/src/lib/components/add-to-list-button.js +64 -0
- package/src/lib/components/add-to-list-button.js.map +1 -0
- package/src/lib/components/add-to-list-dialog.d.ts +24 -0
- package/src/lib/components/add-to-list-dialog.js +327 -0
- package/src/lib/components/add-to-list-dialog.js.map +1 -0
- package/src/lib/components/assignment-rule-drawer.d.ts +43 -0
- package/src/lib/components/assignment-rule-drawer.js +293 -0
- package/src/lib/components/assignment-rule-drawer.js.map +1 -0
- package/src/lib/components/companies-bulk-bar.d.ts +29 -0
- package/src/lib/components/companies-bulk-bar.js +274 -0
- package/src/lib/components/companies-bulk-bar.js.map +1 -0
- package/src/lib/components/companies-section.d.ts +54 -0
- package/src/lib/components/companies-section.js +522 -0
- package/src/lib/components/companies-section.js.map +1 -0
- package/src/lib/components/company-contacts-card.d.ts +49 -0
- package/src/lib/components/company-contacts-card.js +435 -0
- package/src/lib/components/company-contacts-card.js.map +1 -0
- package/src/lib/components/company-deals-card.d.ts +20 -0
- package/src/lib/components/company-deals-card.js +38 -0
- package/src/lib/components/company-deals-card.js.map +1 -0
- package/src/lib/components/company-detail-page.d.ts +20 -0
- package/src/lib/components/company-detail-page.js +165 -0
- package/src/lib/components/company-detail-page.js.map +1 -0
- package/src/lib/components/company-edit-drawer.d.ts +65 -0
- package/src/lib/components/company-edit-drawer.js +433 -0
- package/src/lib/components/company-edit-drawer.js.map +1 -0
- package/src/lib/components/company-import-drawer.d.ts +42 -0
- package/src/lib/components/company-import-drawer.js +99 -0
- package/src/lib/components/company-import-drawer.js.map +1 -0
- package/src/lib/components/company-picker.d.ts +127 -0
- package/src/lib/components/company-picker.js +323 -0
- package/src/lib/components/company-picker.js.map +1 -0
- package/src/lib/components/company-properties-card.d.ts +47 -0
- package/src/lib/components/company-properties-card.js +289 -0
- package/src/lib/components/company-properties-card.js.map +1 -0
- package/src/lib/components/contact-address-fields.d.ts +29 -0
- package/src/lib/components/contact-address-fields.js +149 -0
- package/src/lib/components/contact-address-fields.js.map +1 -0
- package/src/lib/components/contact-associations-card.d.ts +72 -0
- package/src/lib/components/contact-associations-card.js +296 -0
- package/src/lib/components/contact-associations-card.js.map +1 -0
- package/src/lib/components/contact-custom-columns.d.ts +38 -0
- package/src/lib/components/contact-custom-columns.js +102 -0
- package/src/lib/components/contact-custom-columns.js.map +1 -0
- package/src/lib/components/contact-custom-fields-card.d.ts +39 -0
- package/src/lib/components/contact-custom-fields-card.js +204 -0
- package/src/lib/components/contact-custom-fields-card.js.map +1 -0
- package/src/lib/components/contact-deals-card.d.ts +20 -0
- package/src/lib/components/contact-deals-card.js +38 -0
- package/src/lib/components/contact-deals-card.js.map +1 -0
- package/src/lib/components/contact-detail-page.d.ts +46 -0
- package/src/lib/components/contact-detail-page.js +535 -0
- package/src/lib/components/contact-detail-page.js.map +1 -0
- package/src/lib/components/contact-duplicates-card.d.ts +42 -0
- package/src/lib/components/contact-duplicates-card.js +167 -0
- package/src/lib/components/contact-duplicates-card.js.map +1 -0
- package/src/lib/components/contact-field-drawer.d.ts +64 -0
- package/src/lib/components/contact-field-drawer.js +251 -0
- package/src/lib/components/contact-field-drawer.js.map +1 -0
- package/src/lib/components/contact-import-drawer.d.ts +46 -0
- package/src/lib/components/contact-import-drawer.js +149 -0
- package/src/lib/components/contact-import-drawer.js.map +1 -0
- package/src/lib/components/contact-known-by-card.d.ts +39 -0
- package/src/lib/components/contact-known-by-card.js +142 -0
- package/src/lib/components/contact-known-by-card.js.map +1 -0
- package/src/lib/components/contact-list-columns.d.ts +53 -0
- package/src/lib/components/contact-list-columns.js +288 -0
- package/src/lib/components/contact-list-columns.js.map +1 -0
- package/src/lib/components/contact-merge-dialog.d.ts +79 -0
- package/src/lib/components/contact-merge-dialog.js +405 -0
- package/src/lib/components/contact-merge-dialog.js.map +1 -0
- package/src/lib/components/contact-properties-card.d.ts +89 -0
- package/src/lib/components/contact-properties-card.js +492 -0
- package/src/lib/components/contact-properties-card.js.map +1 -0
- package/src/lib/components/contact-timeline-card.d.ts +68 -0
- package/src/lib/components/contact-timeline-card.js +435 -0
- package/src/lib/components/contact-timeline-card.js.map +1 -0
- package/src/lib/components/contacts-bulk-bar.d.ts +91 -0
- package/src/lib/components/contacts-bulk-bar.js +493 -0
- package/src/lib/components/contacts-bulk-bar.js.map +1 -0
- package/src/lib/components/contacts-section.d.ts +26 -0
- package/src/lib/components/contacts-section.js +1025 -0
- package/src/lib/components/contacts-section.js.map +1 -0
- package/src/lib/components/copy-capture-address-button.d.ts +33 -0
- package/src/lib/components/copy-capture-address-button.js +60 -0
- package/src/lib/components/copy-capture-address-button.js.map +1 -0
- package/src/lib/components/crm-attribution-zone.d.ts +38 -0
- package/src/lib/components/crm-attribution-zone.js +36 -0
- package/src/lib/components/crm-attribution-zone.js.map +1 -0
- package/src/lib/components/crm-booking-zone.d.ts +61 -0
- package/src/lib/components/crm-booking-zone.js +50 -0
- package/src/lib/components/crm-booking-zone.js.map +1 -0
- package/src/lib/components/crm-bulk-bar-frame.d.ts +47 -0
- package/src/lib/components/crm-bulk-bar-frame.js +137 -0
- package/src/lib/components/crm-bulk-bar-frame.js.map +1 -0
- package/src/lib/components/crm-call-actions.d.ts +65 -0
- package/src/lib/components/crm-call-actions.js +110 -0
- package/src/lib/components/crm-call-actions.js.map +1 -0
- package/src/lib/components/crm-column-menu.d.ts +21 -0
- package/src/lib/components/crm-column-menu.js +103 -0
- package/src/lib/components/crm-column-menu.js.map +1 -0
- package/src/lib/components/crm-console-page.d.ts +19 -0
- package/src/lib/components/crm-console-page.js +151 -0
- package/src/lib/components/crm-console-page.js.map +1 -0
- package/src/lib/components/crm-console-sections.d.ts +52 -0
- package/src/lib/components/crm-console-sections.js +83 -0
- package/src/lib/components/crm-console-sections.js.map +1 -0
- package/src/lib/components/crm-custom-field-control.d.ts +26 -0
- package/src/lib/components/crm-custom-field-control.js +131 -0
- package/src/lib/components/crm-custom-field-control.js.map +1 -0
- package/src/lib/components/crm-email-template-tools.d.ts +69 -0
- package/src/lib/components/crm-email-template-tools.js +240 -0
- package/src/lib/components/crm-email-template-tools.js.map +1 -0
- package/src/lib/components/crm-export-all-button.d.ts +39 -0
- package/src/lib/components/crm-export-all-button.js +98 -0
- package/src/lib/components/crm-export-all-button.js.map +1 -0
- package/src/lib/components/crm-filter-bar.d.ts +53 -0
- package/src/lib/components/crm-filter-bar.js +294 -0
- package/src/lib/components/crm-filter-bar.js.map +1 -0
- package/src/lib/components/crm-glance-card.d.ts +54 -0
- package/src/lib/components/crm-glance-card.js +219 -0
- package/src/lib/components/crm-glance-card.js.map +1 -0
- package/src/lib/components/crm-next-activity-column.d.ts +35 -0
- package/src/lib/components/crm-next-activity-column.js +100 -0
- package/src/lib/components/crm-next-activity-column.js.map +1 -0
- package/src/lib/components/crm-record-header.d.ts +97 -0
- package/src/lib/components/crm-record-header.js +160 -0
- package/src/lib/components/crm-record-header.js.map +1 -0
- package/src/lib/components/crm-record-insights-zone.d.ts +50 -0
- package/src/lib/components/crm-record-insights-zone.js +169 -0
- package/src/lib/components/crm-record-insights-zone.js.map +1 -0
- package/src/lib/components/crm-record-picker.d.ts +42 -0
- package/src/lib/components/crm-record-picker.js +104 -0
- package/src/lib/components/crm-record-picker.js.map +1 -0
- package/src/lib/components/crm-send-email-button.d.ts +39 -0
- package/src/lib/components/crm-send-email-button.js +81 -0
- package/src/lib/components/crm-send-email-button.js.map +1 -0
- package/src/lib/components/crm-send-email-dialog.d.ts +61 -0
- package/src/lib/components/crm-send-email-dialog.js +851 -0
- package/src/lib/components/crm-send-email-dialog.js.map +1 -0
- package/src/lib/components/crm-site-picker.d.ts +61 -0
- package/src/lib/components/crm-site-picker.js +99 -0
- package/src/lib/components/crm-site-picker.js.map +1 -0
- package/src/lib/components/crm-suite-lock.d.ts +29 -0
- package/src/lib/components/crm-suite-lock.js +114 -0
- package/src/lib/components/crm-suite-lock.js.map +1 -0
- package/src/lib/components/crm-tasks-due-card.d.ts +42 -0
- package/src/lib/components/crm-tasks-due-card.js +225 -0
- package/src/lib/components/crm-tasks-due-card.js.map +1 -0
- package/src/lib/components/crm-views-control.d.ts +65 -0
- package/src/lib/components/crm-views-control.js +518 -0
- package/src/lib/components/crm-views-control.js.map +1 -0
- package/src/lib/components/csv-import-drawer.d.ts +132 -0
- package/src/lib/components/csv-import-drawer.js +746 -0
- package/src/lib/components/csv-import-drawer.js.map +1 -0
- package/src/lib/components/deal-board.d.ts +70 -0
- package/src/lib/components/deal-board.js +478 -0
- package/src/lib/components/deal-board.js.map +1 -0
- package/src/lib/components/deal-detail-page.d.ts +18 -0
- package/src/lib/components/deal-detail-page.js +323 -0
- package/src/lib/components/deal-detail-page.js.map +1 -0
- package/src/lib/components/deal-edit-drawer.d.ts +59 -0
- package/src/lib/components/deal-edit-drawer.js +640 -0
- package/src/lib/components/deal-edit-drawer.js.map +1 -0
- package/src/lib/components/deal-import-drawer.d.ts +24 -0
- package/src/lib/components/deal-import-drawer.js +83 -0
- package/src/lib/components/deal-import-drawer.js.map +1 -0
- package/src/lib/components/deal-products-card.d.ts +48 -0
- package/src/lib/components/deal-products-card.js +614 -0
- package/src/lib/components/deal-products-card.js.map +1 -0
- package/src/lib/components/deal-properties-card.d.ts +29 -0
- package/src/lib/components/deal-properties-card.js +144 -0
- package/src/lib/components/deal-properties-card.js.map +1 -0
- package/src/lib/components/deal-stage-card.d.ts +24 -0
- package/src/lib/components/deal-stage-card.js +199 -0
- package/src/lib/components/deal-stage-card.js.map +1 -0
- package/src/lib/components/deals-bulk-bar.d.ts +31 -0
- package/src/lib/components/deals-bulk-bar.js +340 -0
- package/src/lib/components/deals-bulk-bar.js.map +1 -0
- package/src/lib/components/deals-section.d.ts +49 -0
- package/src/lib/components/deals-section.js +767 -0
- package/src/lib/components/deals-section.js.map +1 -0
- package/src/lib/components/email-capture-card.d.ts +42 -0
- package/src/lib/components/email-capture-card.js +134 -0
- package/src/lib/components/email-capture-card.js.map +1 -0
- package/src/lib/components/email-template-drawer.d.ts +33 -0
- package/src/lib/components/email-template-drawer.js +209 -0
- package/src/lib/components/email-template-drawer.js.map +1 -0
- package/src/lib/components/email-templates-card.d.ts +33 -0
- package/src/lib/components/email-templates-card.js +370 -0
- package/src/lib/components/email-templates-card.js.map +1 -0
- package/src/lib/components/erase-person-action.d.ts +92 -0
- package/src/lib/components/erase-person-action.js +261 -0
- package/src/lib/components/erase-person-action.js.map +1 -0
- package/src/lib/components/fields-section.d.ts +37 -0
- package/src/lib/components/fields-section.js +641 -0
- package/src/lib/components/fields-section.js.map +1 -0
- package/src/lib/components/form-contact-fields-card.d.ts +46 -0
- package/src/lib/components/form-contact-fields-card.js +253 -0
- package/src/lib/components/form-contact-fields-card.js.map +1 -0
- package/src/lib/components/insert-link-at-caret.d.ts +28 -0
- package/src/lib/components/insert-link-at-caret.js +37 -0
- package/src/lib/components/insert-link-at-caret.js.map +1 -0
- package/src/lib/components/lead-convert-dialog.d.ts +32 -0
- package/src/lib/components/lead-convert-dialog.js +493 -0
- package/src/lib/components/lead-convert-dialog.js.map +1 -0
- package/src/lib/components/lead-detail-page.d.ts +16 -0
- package/src/lib/components/lead-detail-page.js +163 -0
- package/src/lib/components/lead-detail-page.js.map +1 -0
- package/src/lib/components/lead-history-card.d.ts +32 -0
- package/src/lib/components/lead-history-card.js +165 -0
- package/src/lib/components/lead-history-card.js.map +1 -0
- package/src/lib/components/lead-import-drawer.d.ts +24 -0
- package/src/lib/components/lead-import-drawer.js +95 -0
- package/src/lib/components/lead-import-drawer.js.map +1 -0
- package/src/lib/components/lead-owner-select.d.ts +35 -0
- package/src/lib/components/lead-owner-select.js +91 -0
- package/src/lib/components/lead-owner-select.js.map +1 -0
- package/src/lib/components/lead-properties-card.d.ts +61 -0
- package/src/lib/components/lead-properties-card.js +395 -0
- package/src/lib/components/lead-properties-card.js.map +1 -0
- package/src/lib/components/lead-status-chip.d.ts +12 -0
- package/src/lib/components/lead-status-chip.js +43 -0
- package/src/lib/components/lead-status-chip.js.map +1 -0
- package/src/lib/components/lead-surfaces-note.d.ts +126 -0
- package/src/lib/components/lead-surfaces-note.js +262 -0
- package/src/lib/components/lead-surfaces-note.js.map +1 -0
- package/src/lib/components/lead-unqualify-dialog.d.ts +24 -0
- package/src/lib/components/lead-unqualify-dialog.js +125 -0
- package/src/lib/components/lead-unqualify-dialog.js.map +1 -0
- package/src/lib/components/leads-bulk-bar.d.ts +58 -0
- package/src/lib/components/leads-bulk-bar.js +307 -0
- package/src/lib/components/leads-bulk-bar.js.map +1 -0
- package/src/lib/components/leads-section.d.ts +23 -0
- package/src/lib/components/leads-section.js +664 -0
- package/src/lib/components/leads-section.js.map +1 -0
- package/src/lib/components/linked-deals-card.d.ts +32 -0
- package/src/lib/components/linked-deals-card.js +163 -0
- package/src/lib/components/linked-deals-card.js.map +1 -0
- package/src/lib/components/log-activity-dialog.d.ts +60 -0
- package/src/lib/components/log-activity-dialog.js +368 -0
- package/src/lib/components/log-activity-dialog.js.map +1 -0
- package/src/lib/components/lost-reason-dialog.d.ts +26 -0
- package/src/lib/components/lost-reason-dialog.js +95 -0
- package/src/lib/components/lost-reason-dialog.js.map +1 -0
- package/src/lib/components/new-contact-drawer.d.ts +78 -0
- package/src/lib/components/new-contact-drawer.js +343 -0
- package/src/lib/components/new-contact-drawer.js.map +1 -0
- package/src/lib/components/org-lead-surfaces-note.d.ts +57 -0
- package/src/lib/components/org-lead-surfaces-note.js +172 -0
- package/src/lib/components/org-lead-surfaces-note.js.map +1 -0
- package/src/lib/components/owner-avatar.d.ts +18 -0
- package/src/lib/components/owner-avatar.js +61 -0
- package/src/lib/components/owner-avatar.js.map +1 -0
- package/src/lib/components/pipeline-stages-dialog.d.ts +43 -0
- package/src/lib/components/pipeline-stages-dialog.js +339 -0
- package/src/lib/components/pipeline-stages-dialog.js.map +1 -0
- package/src/lib/components/pipelines-dialog.d.ts +55 -0
- package/src/lib/components/pipelines-dialog.js +517 -0
- package/src/lib/components/pipelines-dialog.js.map +1 -0
- package/src/lib/components/recent-activity-feed.d.ts +39 -0
- package/src/lib/components/recent-activity-feed.js +103 -0
- package/src/lib/components/recent-activity-feed.js.map +1 -0
- package/src/lib/components/recipes-card.d.ts +39 -0
- package/src/lib/components/recipes-card.js +485 -0
- package/src/lib/components/recipes-card.js.map +1 -0
- package/src/lib/components/record-activity-card.d.ts +26 -0
- package/src/lib/components/record-activity-card.js +121 -0
- package/src/lib/components/record-activity-card.js.map +1 -0
- package/src/lib/components/record-files-card.d.ts +67 -0
- package/src/lib/components/record-files-card.js +290 -0
- package/src/lib/components/record-files-card.js.map +1 -0
- package/src/lib/components/record-tasks-card.d.ts +32 -0
- package/src/lib/components/record-tasks-card.js +306 -0
- package/src/lib/components/record-tasks-card.js.map +1 -0
- package/src/lib/components/reports/activity-card.d.ts +57 -0
- package/src/lib/components/reports/activity-card.js +281 -0
- package/src/lib/components/reports/activity-card.js.map +1 -0
- package/src/lib/components/reports/closed-deals-card.d.ts +20 -0
- package/src/lib/components/reports/closed-deals-card.js +194 -0
- package/src/lib/components/reports/closed-deals-card.js.map +1 -0
- package/src/lib/components/reports/contacts-mix-card.d.ts +27 -0
- package/src/lib/components/reports/contacts-mix-card.js +161 -0
- package/src/lib/components/reports/contacts-mix-card.js.map +1 -0
- package/src/lib/components/reports/contacts-trend-card.d.ts +31 -0
- package/src/lib/components/reports/contacts-trend-card.js +144 -0
- package/src/lib/components/reports/contacts-trend-card.js.map +1 -0
- package/src/lib/components/reports/forecast-card.d.ts +22 -0
- package/src/lib/components/reports/forecast-card.js +251 -0
- package/src/lib/components/reports/forecast-card.js.map +1 -0
- package/src/lib/components/reports/lead-counts.d.ts +32 -0
- package/src/lib/components/reports/lead-counts.js +44 -0
- package/src/lib/components/reports/lead-counts.js.map +1 -0
- package/src/lib/components/reports/lead-funnel-card.d.ts +38 -0
- package/src/lib/components/reports/lead-funnel-card.js +375 -0
- package/src/lib/components/reports/lead-funnel-card.js.map +1 -0
- package/src/lib/components/reports/pipeline-card.d.ts +19 -0
- package/src/lib/components/reports/pipeline-card.js +338 -0
- package/src/lib/components/reports/pipeline-card.js.map +1 -0
- package/src/lib/components/reports/report-bar-chart.d.ts +39 -0
- package/src/lib/components/reports/report-bar-chart.js +133 -0
- package/src/lib/components/reports/report-bar-chart.js.map +1 -0
- package/src/lib/components/reports/report-breakdown.d.ts +32 -0
- package/src/lib/components/reports/report-breakdown.js +105 -0
- package/src/lib/components/reports/report-breakdown.js.map +1 -0
- package/src/lib/components/reports/report-export.d.ts +37 -0
- package/src/lib/components/reports/report-export.js +66 -0
- package/src/lib/components/reports/report-export.js.map +1 -0
- package/src/lib/components/reports/report-format.d.ts +36 -0
- package/src/lib/components/reports/report-format.js +43 -0
- package/src/lib/components/reports/report-format.js.map +1 -0
- package/src/lib/components/reports/report-scope.d.ts +81 -0
- package/src/lib/components/reports/report-scope.js +58 -0
- package/src/lib/components/reports/report-scope.js.map +1 -0
- package/src/lib/components/reports/report-stat-tile.d.ts +47 -0
- package/src/lib/components/reports/report-stat-tile.js +96 -0
- package/src/lib/components/reports/report-stat-tile.js.map +1 -0
- package/src/lib/components/reports/source-conversion-card.d.ts +28 -0
- package/src/lib/components/reports/source-conversion-card.js +205 -0
- package/src/lib/components/reports/source-conversion-card.js.map +1 -0
- package/src/lib/components/reports/tasks-card.d.ts +26 -0
- package/src/lib/components/reports/tasks-card.js +279 -0
- package/src/lib/components/reports/tasks-card.js.map +1 -0
- package/src/lib/components/reports/use-aggregate-read.d.ts +99 -0
- package/src/lib/components/reports/use-aggregate-read.js +195 -0
- package/src/lib/components/reports/use-aggregate-read.js.map +1 -0
- package/src/lib/components/reports/won-lost-by-owner-card.d.ts +30 -0
- package/src/lib/components/reports/won-lost-by-owner-card.js +168 -0
- package/src/lib/components/reports/won-lost-by-owner-card.js.map +1 -0
- package/src/lib/components/reports-section.d.ts +42 -0
- package/src/lib/components/reports-section.js +308 -0
- package/src/lib/components/reports-section.js.map +1 -0
- package/src/lib/components/sending-addresses-card.d.ts +49 -0
- package/src/lib/components/sending-addresses-card.js +262 -0
- package/src/lib/components/sending-addresses-card.js.map +1 -0
- package/src/lib/components/settings-section.d.ts +151 -0
- package/src/lib/components/settings-section.js +783 -0
- package/src/lib/components/settings-section.js.map +1 -0
- package/src/lib/components/task-cells.d.ts +51 -0
- package/src/lib/components/task-cells.js +139 -0
- package/src/lib/components/task-cells.js.map +1 -0
- package/src/lib/components/task-edit-drawer.d.ts +53 -0
- package/src/lib/components/task-edit-drawer.js +483 -0
- package/src/lib/components/task-edit-drawer.js.map +1 -0
- package/src/lib/components/task-import-drawer.d.ts +24 -0
- package/src/lib/components/task-import-drawer.js +82 -0
- package/src/lib/components/task-import-drawer.js.map +1 -0
- package/src/lib/components/task-snooze-menu.d.ts +65 -0
- package/src/lib/components/task-snooze-menu.js +207 -0
- package/src/lib/components/task-snooze-menu.js.map +1 -0
- package/src/lib/components/tasks-bulk-bar.d.ts +25 -0
- package/src/lib/components/tasks-bulk-bar.js +348 -0
- package/src/lib/components/tasks-bulk-bar.js.map +1 -0
- package/src/lib/components/tasks-calendar.d.ts +38 -0
- package/src/lib/components/tasks-calendar.js +228 -0
- package/src/lib/components/tasks-calendar.js.map +1 -0
- package/src/lib/components/tasks-section.d.ts +27 -0
- package/src/lib/components/tasks-section.js +579 -0
- package/src/lib/components/tasks-section.js.map +1 -0
- package/src/lib/components/use-contact-campaign-emails.d.ts +32 -0
- package/src/lib/components/use-contact-campaign-emails.js +83 -0
- package/src/lib/components/use-contact-campaign-emails.js.map +1 -0
- package/src/lib/components/use-crm-api.d.ts +44 -0
- package/src/lib/components/use-crm-api.js +84 -0
- package/src/lib/components/use-crm-api.js.map +1 -0
- package/src/lib/components/use-crm-inbound-address.d.ts +60 -0
- package/src/lib/components/use-crm-inbound-address.js +124 -0
- package/src/lib/components/use-crm-inbound-address.js.map +1 -0
- package/src/lib/components/use-emails-hub-path.d.ts +24 -0
- package/src/lib/components/use-emails-hub-path.js +59 -0
- package/src/lib/components/use-emails-hub-path.js.map +1 -0
- package/src/lib/components/use-member-email-aliases.d.ts +54 -0
- package/src/lib/components/use-member-email-aliases.js +186 -0
- package/src/lib/components/use-member-email-aliases.js.map +1 -0
- package/src/lib/components/use-org-members.d.ts +40 -0
- package/src/lib/components/use-org-members.js +100 -0
- package/src/lib/components/use-org-members.js.map +1 -0
- package/src/lib/constants/api-routes.d.ts +109 -0
- package/src/lib/constants/api-routes.js +74 -0
- package/src/lib/constants/api-routes.js.map +1 -0
- package/src/lib/constants/bundle-common.d.ts +14 -0
- package/src/lib/constants/bundle-common.js +14 -0
- package/src/lib/constants/bundle-common.js.map +1 -0
- package/src/lib/constants/company-filters.d.ts +18 -0
- package/src/lib/constants/company-filters.js +51 -0
- package/src/lib/constants/company-filters.js.map +1 -0
- package/src/lib/constants/contact-filters.d.ts +38 -0
- package/src/lib/constants/contact-filters.js +294 -0
- package/src/lib/constants/contact-filters.js.map +1 -0
- package/src/lib/hooks/use-contact-field-definitions.d.ts +48 -0
- package/src/lib/hooks/use-contact-field-definitions.js +72 -0
- package/src/lib/hooks/use-contact-field-definitions.js.map +1 -0
- package/src/lib/hooks/use-contact-update.d.ts +25 -0
- package/src/lib/hooks/use-contact-update.js +80 -0
- package/src/lib/hooks/use-contact-update.js.map +1 -0
- package/src/lib/hooks/use-crm-activity-logger.d.ts +73 -0
- package/src/lib/hooks/use-crm-activity-logger.js +101 -0
- package/src/lib/hooks/use-crm-activity-logger.js.map +1 -0
- package/src/lib/hooks/use-crm-bulk-apply.d.ts +52 -0
- package/src/lib/hooks/use-crm-bulk-apply.js +112 -0
- package/src/lib/hooks/use-crm-bulk-apply.js.map +1 -0
- package/src/lib/hooks/use-crm-default-view.d.ts +24 -0
- package/src/lib/hooks/use-crm-default-view.js +64 -0
- package/src/lib/hooks/use-crm-default-view.js.map +1 -0
- package/src/lib/hooks/use-crm-email-templates.d.ts +59 -0
- package/src/lib/hooks/use-crm-email-templates.js +103 -0
- package/src/lib/hooks/use-crm-email-templates.js.map +1 -0
- package/src/lib/hooks/use-crm-hub-path.d.ts +29 -0
- package/src/lib/hooks/use-crm-hub-path.js +41 -0
- package/src/lib/hooks/use-crm-hub-path.js.map +1 -0
- package/src/lib/hooks/use-crm-org-mount.d.ts +97 -0
- package/src/lib/hooks/use-crm-org-mount.js +215 -0
- package/src/lib/hooks/use-crm-org-mount.js.map +1 -0
- package/src/lib/hooks/use-crm-record-names.d.ts +52 -0
- package/src/lib/hooks/use-crm-record-names.js +126 -0
- package/src/lib/hooks/use-crm-record-names.js.map +1 -0
- package/src/lib/hooks/use-crm-records-quota.d.ts +68 -0
- package/src/lib/hooks/use-crm-records-quota.js +118 -0
- package/src/lib/hooks/use-crm-records-quota.js.map +1 -0
- package/src/lib/hooks/use-crm-saved-view.d.ts +96 -0
- package/src/lib/hooks/use-crm-saved-view.js +329 -0
- package/src/lib/hooks/use-crm-saved-view.js.map +1 -0
- package/src/lib/hooks/use-crm-scope.d.ts +117 -0
- package/src/lib/hooks/use-crm-scope.js +147 -0
- package/src/lib/hooks/use-crm-scope.js.map +1 -0
- package/src/lib/hooks/use-crm-tasks.d.ts +85 -0
- package/src/lib/hooks/use-crm-tasks.js +153 -0
- package/src/lib/hooks/use-crm-tasks.js.map +1 -0
- package/src/lib/hooks/use-crm-view-grid.d.ts +55 -0
- package/src/lib/hooks/use-crm-view-grid.js +170 -0
- package/src/lib/hooks/use-crm-view-grid.js.map +1 -0
- package/src/lib/hooks/use-crm-views.d.ts +42 -0
- package/src/lib/hooks/use-crm-views.js +84 -0
- package/src/lib/hooks/use-crm-views.js.map +1 -0
- package/src/lib/hooks/use-deal-stage-api.d.ts +69 -0
- package/src/lib/hooks/use-deal-stage-api.js +78 -0
- package/src/lib/hooks/use-deal-stage-api.js.map +1 -0
- package/src/lib/hooks/use-deals.d.ts +47 -0
- package/src/lib/hooks/use-deals.js +105 -0
- package/src/lib/hooks/use-deals.js.map +1 -0
- package/src/lib/hooks/use-org-leads.d.ts +53 -0
- package/src/lib/hooks/use-org-leads.js +114 -0
- package/src/lib/hooks/use-org-leads.js.map +1 -0
- package/src/lib/hooks/use-org-member-directory.d.ts +36 -0
- package/src/lib/hooks/use-org-member-directory.js +116 -0
- package/src/lib/hooks/use-org-member-directory.js.map +1 -0
- package/src/lib/hooks/use-org-member-options.d.ts +38 -0
- package/src/lib/hooks/use-org-member-options.js +131 -0
- package/src/lib/hooks/use-org-member-options.js.map +1 -0
- package/src/lib/hooks/use-pipeline.d.ts +71 -0
- package/src/lib/hooks/use-pipeline.js +159 -0
- package/src/lib/hooks/use-pipeline.js.map +1 -0
- package/src/lib/model/companies-bulk-writes.d.ts +40 -0
- package/src/lib/model/companies-bulk-writes.js +103 -0
- package/src/lib/model/companies-bulk-writes.js.map +1 -0
- package/src/lib/model/companies-csv.d.ts +36 -0
- package/src/lib/model/companies-csv.js +38 -0
- package/src/lib/model/companies-csv.js.map +1 -0
- package/src/lib/model/companies.d.ts +99 -0
- package/src/lib/model/companies.js +168 -0
- package/src/lib/model/companies.js.map +1 -0
- package/src/lib/model/company-delete-route.d.ts +43 -0
- package/src/lib/model/company-delete-route.js +31 -0
- package/src/lib/model/company-delete-route.js.map +1 -0
- package/src/lib/model/company-delete.d.ts +42 -0
- package/src/lib/model/company-delete.js +52 -0
- package/src/lib/model/company-delete.js.map +1 -0
- package/src/lib/model/contact-duplicates.d.ts +58 -0
- package/src/lib/model/contact-duplicates.js +67 -0
- package/src/lib/model/contact-duplicates.js.map +1 -0
- package/src/lib/model/contact-record.d.ts +113 -0
- package/src/lib/model/contact-record.js +70 -0
- package/src/lib/model/contact-record.js.map +1 -0
- package/src/lib/model/contact-update.d.ts +93 -0
- package/src/lib/model/contact-update.js +50 -0
- package/src/lib/model/contact-update.js.map +1 -0
- package/src/lib/model/contacts-bulk-writes.d.ts +173 -0
- package/src/lib/model/contacts-bulk-writes.js +196 -0
- package/src/lib/model/contacts-bulk-writes.js.map +1 -0
- package/src/lib/model/contacts-csv.d.ts +54 -0
- package/src/lib/model/contacts-csv.js +67 -0
- package/src/lib/model/contacts-csv.js.map +1 -0
- package/src/lib/model/contacts-list-seed.d.ts +51 -0
- package/src/lib/model/contacts-list-seed.js +63 -0
- package/src/lib/model/contacts-list-seed.js.map +1 -0
- package/src/lib/model/crm-activity-report.d.ts +27 -0
- package/src/lib/model/crm-activity-report.js +56 -0
- package/src/lib/model/crm-activity-report.js.map +1 -0
- package/src/lib/model/crm-api.d.ts +49 -0
- package/src/lib/model/crm-api.js +47 -0
- package/src/lib/model/crm-api.js.map +1 -0
- package/src/lib/model/crm-bulk-writes.d.ts +147 -0
- package/src/lib/model/crm-bulk-writes.js +207 -0
- package/src/lib/model/crm-bulk-writes.js.map +1 -0
- package/src/lib/model/crm-company-import.d.ts +154 -0
- package/src/lib/model/crm-company-import.js +331 -0
- package/src/lib/model/crm-company-import.js.map +1 -0
- package/src/lib/model/crm-custom-draft.d.ts +62 -0
- package/src/lib/model/crm-custom-draft.js +67 -0
- package/src/lib/model/crm-custom-draft.js.map +1 -0
- package/src/lib/model/crm-deal-import.d.ts +112 -0
- package/src/lib/model/crm-deal-import.js +263 -0
- package/src/lib/model/crm-deal-import.js.map +1 -0
- package/src/lib/model/crm-import.d.ts +244 -0
- package/src/lib/model/crm-import.js +466 -0
- package/src/lib/model/crm-import.js.map +1 -0
- package/src/lib/model/crm-lead-import.d.ts +105 -0
- package/src/lib/model/crm-lead-import.js +255 -0
- package/src/lib/model/crm-lead-import.js.map +1 -0
- package/src/lib/model/crm-record-routes.d.ts +21 -0
- package/src/lib/model/crm-record-routes.js +70 -0
- package/src/lib/model/crm-record-routes.js.map +1 -0
- package/src/lib/model/crm-routes.d.ts +101 -0
- package/src/lib/model/crm-routes.js +92 -0
- package/src/lib/model/crm-routes.js.map +1 -0
- package/src/lib/model/crm-task-import.d.ts +94 -0
- package/src/lib/model/crm-task-import.js +275 -0
- package/src/lib/model/crm-task-import.js.map +1 -0
- package/src/lib/model/crm-view-param.d.ts +43 -0
- package/src/lib/model/crm-view-param.js +49 -0
- package/src/lib/model/crm-view-param.js.map +1 -0
- package/src/lib/model/deal-board-model.d.ts +241 -0
- package/src/lib/model/deal-board-model.js +439 -0
- package/src/lib/model/deal-board-model.js.map +1 -0
- package/src/lib/model/deal-form-model.d.ts +114 -0
- package/src/lib/model/deal-form-model.js +218 -0
- package/src/lib/model/deal-form-model.js.map +1 -0
- package/src/lib/model/deals-csv.d.ts +32 -0
- package/src/lib/model/deals-csv.js +37 -0
- package/src/lib/model/deals-csv.js.map +1 -0
- package/src/lib/model/import-column-shapes.d.ts +36 -0
- package/src/lib/model/import-column-shapes.js +76 -0
- package/src/lib/model/import-column-shapes.js.map +1 -0
- package/src/lib/model/lead-company-suggestion.d.ts +61 -0
- package/src/lib/model/lead-company-suggestion.js +65 -0
- package/src/lib/model/lead-company-suggestion.js.map +1 -0
- package/src/lib/model/lead-filters.d.ts +29 -0
- package/src/lib/model/lead-filters.js +39 -0
- package/src/lib/model/lead-filters.js.map +1 -0
- package/src/lib/model/lead-surfaces.d.ts +58 -0
- package/src/lib/model/lead-surfaces.js +67 -0
- package/src/lib/model/lead-surfaces.js.map +1 -0
- package/src/lib/model/leads-csv.d.ts +40 -0
- package/src/lib/model/leads-csv.js +40 -0
- package/src/lib/model/leads-csv.js.map +1 -0
- package/src/lib/model/next-activity-api.d.ts +31 -0
- package/src/lib/model/next-activity-api.js +57 -0
- package/src/lib/model/next-activity-api.js.map +1 -0
- package/src/lib/model/next-activity.d.ts +64 -0
- package/src/lib/model/next-activity.js +47 -0
- package/src/lib/model/next-activity.js.map +1 -0
- package/src/lib/model/person-key-web.d.ts +43 -0
- package/src/lib/model/person-key-web.js +52 -0
- package/src/lib/model/person-key-web.js.map +1 -0
- package/src/lib/model/record-facts.d.ts +282 -0
- package/src/lib/model/record-facts.js +434 -0
- package/src/lib/model/record-facts.js.map +1 -0
- package/src/lib/model/task-api.d.ts +28 -0
- package/src/lib/model/task-api.js +57 -0
- package/src/lib/model/task-api.js.map +1 -0
- package/src/lib/model/task-calendar.d.ts +108 -0
- package/src/lib/model/task-calendar.js +139 -0
- package/src/lib/model/task-calendar.js.map +1 -0
- package/src/lib/model/task-routes.d.ts +177 -0
- package/src/lib/model/task-routes.js +197 -0
- package/src/lib/model/task-routes.js.map +1 -0
- package/src/lib/model/task-scope.d.ts +45 -0
- package/src/lib/model/task-scope.js +51 -0
- package/src/lib/model/task-scope.js.map +1 -0
- package/src/lib/model/task-views.d.ts +149 -0
- package/src/lib/model/task-views.js +286 -0
- package/src/lib/model/task-views.js.map +1 -0
- package/src/lib/model/tasks-csv.d.ts +28 -0
- package/src/lib/model/tasks-csv.js +28 -0
- package/src/lib/model/tasks-csv.js.map +1 -0
- package/src/lib/plugin.d.ts +32 -0
- package/src/lib/plugin.js +208 -0
- package/src/lib/plugin.js.map +1 -0
- package/src/lib/server/companies-import.d.ts +57 -0
- package/src/lib/server/companies-import.js +242 -0
- package/src/lib/server/companies-import.js.map +1 -0
- package/src/lib/server/company-delete.d.ts +59 -0
- package/src/lib/server/company-delete.js +146 -0
- package/src/lib/server/company-delete.js.map +1 -0
- package/src/lib/server/contact-email-history.d.ts +82 -0
- package/src/lib/server/contact-email-history.js +264 -0
- package/src/lib/server/contact-email-history.js.map +1 -0
- package/src/lib/server/contact-profile.d.ts +41 -0
- package/src/lib/server/contact-profile.js +45 -0
- package/src/lib/server/contact-profile.js.map +1 -0
- package/src/lib/server/contact-update.d.ts +92 -0
- package/src/lib/server/contact-update.js +512 -0
- package/src/lib/server/contact-update.js.map +1 -0
- package/src/lib/server/contacts-import.d.ts +73 -0
- package/src/lib/server/contacts-import.js +263 -0
- package/src/lib/server/contacts-import.js.map +1 -0
- package/src/lib/server/contacts-merge.d.ts +86 -0
- package/src/lib/server/contacts-merge.js +206 -0
- package/src/lib/server/contacts-merge.js.map +1 -0
- package/src/lib/server/deals-import.d.ts +76 -0
- package/src/lib/server/deals-import.js +246 -0
- package/src/lib/server/deals-import.js.map +1 -0
- package/src/lib/server/email-send.d.ts +119 -0
- package/src/lib/server/email-send.js +667 -0
- package/src/lib/server/email-send.js.map +1 -0
- package/src/lib/server/email-template-duplicate.d.ts +19 -0
- package/src/lib/server/email-template-duplicate.js +206 -0
- package/src/lib/server/email-template-duplicate.js.map +1 -0
- package/src/lib/server/erase-person.d.ts +108 -0
- package/src/lib/server/erase-person.js +309 -0
- package/src/lib/server/erase-person.js.map +1 -0
- package/src/lib/server/import-context.d.ts +85 -0
- package/src/lib/server/import-context.js +181 -0
- package/src/lib/server/import-context.js.map +1 -0
- package/src/lib/server/inbound-address.d.ts +61 -0
- package/src/lib/server/inbound-address.js +188 -0
- package/src/lib/server/inbound-address.js.map +1 -0
- package/src/lib/server/lead-convert.d.ts +78 -0
- package/src/lib/server/lead-convert.js +250 -0
- package/src/lib/server/lead-convert.js.map +1 -0
- package/src/lib/server/leads-import.d.ts +84 -0
- package/src/lib/server/leads-import.js +261 -0
- package/src/lib/server/leads-import.js.map +1 -0
- package/src/lib/server/next-activity-routes.d.ts +33 -0
- package/src/lib/server/next-activity-routes.js +110 -0
- package/src/lib/server/next-activity-routes.js.map +1 -0
- package/src/lib/server/org-activity.d.ts +61 -0
- package/src/lib/server/org-activity.js +120 -0
- package/src/lib/server/org-activity.js.map +1 -0
- package/src/lib/server/org-caller.d.ts +110 -0
- package/src/lib/server/org-caller.js +154 -0
- package/src/lib/server/org-caller.js.map +1 -0
- package/src/lib/server/recipe-routes.d.ts +75 -0
- package/src/lib/server/recipe-routes.js +442 -0
- package/src/lib/server/recipe-routes.js.map +1 -0
- package/src/lib/server/record-facts.d.ts +65 -0
- package/src/lib/server/record-facts.js +337 -0
- package/src/lib/server/record-facts.js.map +1 -0
- package/src/lib/server/record-timeline.d.ts +51 -0
- package/src/lib/server/record-timeline.js +215 -0
- package/src/lib/server/record-timeline.js.map +1 -0
- package/src/lib/server/suite-gate.d.ts +42 -0
- package/src/lib/server/suite-gate.js +87 -0
- package/src/lib/server/suite-gate.js.map +1 -0
- package/src/lib/server/task-routes.d.ts +132 -0
- package/src/lib/server/task-routes.js +699 -0
- package/src/lib/server/task-routes.js.map +1 -0
- package/src/lib/server/tasks-import.d.ts +54 -0
- package/src/lib/server/tasks-import.js +157 -0
- package/src/lib/server/tasks-import.js.map +1 -0
- package/src/lib/server-deal-stage.d.ts +88 -0
- package/src/lib/server-deal-stage.js +316 -0
- package/src/lib/server-deal-stage.js.map +1 -0
- package/src/lib/server.d.ts +149 -0
- package/src/lib/server.js +615 -0
- package/src/lib/server.js.map +1 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../../libs/plugins/crm/src/lib/hooks/use-crm-scope.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n'use client'\n\nimport {\n type ConsentGroup,\n type ConsolePluginPageProps,\n consentGroupForHost,\n crmReadTokens,\n crmScopeTokens,\n type ScopeToken,\n} from '@aglyn/aglyn'\nimport { useOrgDataScope } from '@aglyn/tenant-feature-instance'\nimport { type QueryConstraint, where } from 'firebase/firestore'\nimport { useMemo } from 'react'\nimport { useCrmOrgMount } from './use-crm-org-mount'\n\n/**\n * The org document as a CRM surface receives it: the shell's typed billing\n * projection on a page, or the plain record a card was handed. Read as a\n * record at the one seam below, so no component casts it itself.\n */\nexport type CrmOrgDoc =\n | ConsolePluginPageProps['org']\n | Record<string, unknown>\n | null\n | undefined\n\n/** Where a CRM surface is mounted: under one site, or over the whole org. */\nexport type CrmScopeLevel = 'site' | 'org'\n\nexport interface CrmScope {\n /** The org data root, or `null` until the org lookup settles or when there is none. */\n scope: readonly ['orgs', string] | null\n /** The owning org, or null while the lookup runs or when there is none. */\n orgId: string | null\n /** Whether the org lookup has settled — `orgId` null after this means no org. */\n ready: boolean\n /** Under a site, or at the organization level (AGL-2630). */\n level: CrmScopeLevel\n /** The mounted site, or `null` at the organization level. */\n hostId: string | null\n /**\n * The controller this surface is being viewed as, or `null` at the org\n * level, where there is no one viewing site: a cross-holder reader\n * resolves each contact's own facet instead (`contactPrimaryGroup`).\n */\n consentGroup: ConsentGroup | null\n /**\n * What this viewer may LIST — every listener's `array-contains-any`\n * predicate, capped at what the operator accepts — or `null` at the org\n * level, where an org-wide member's listeners carry NO scope clause: the\n * rules' `canReadScoped()` short-circuits on `isOrgWideMember()`, so the\n * clause would only ever narrow what the reader is already allowed. Hand\n * it to {@link crmVisibleToClause}, which spells both cases. Stable across\n * renders for the same org and site, so it can sit in a query's\n * dependency list.\n */\n visibleTo: readonly ScopeToken[] | null\n /**\n * The site a record this viewer CREATES is captured by: the mounted site,\n * or at the org level the site the reader picked (`null` until they\n * have). A create must hold until this is known — the tokens below are\n * empty without it, and a record stamped with none is visible to nobody.\n */\n createHostId: string | null\n /** The consent group of {@link createHostId} — what a create records consent for. */\n createGroup: ConsentGroup | null\n /** What a record this viewer CREATES is stamped with; empty until {@link createHostId} is known. */\n createTokens: readonly ScopeToken[]\n}\n\nconst NO_TOKENS: readonly ScopeToken[] = Object.freeze([])\n\n/**\n * The scope facts every CRM surface needs, resolved once (AGL-2597, one\n * hook since AGL-2614, two levels since AGL-2630).\n *\n * A CRM surface — a list, a record page, a drawer, a card on somebody\n * else's page — resolves its consent group, builds the token list its\n * listener filters on, builds the tokens a create stamps, and looks up the\n * org root. Every section needs the same answers, and for a while the deals\n * had a hook of their own that answered them under different names\n * (`readTokens` for `visibleTo`), which is two chances to filter by one set\n * of tokens and stamp with another. This is the one place the expression\n * lives: a surface that spelled its own could omit the `'org'` token and\n * stop listing the org-wide records the rules would have let it read.\n *\n * ## Two levels, one call\n *\n * Under a site, `hostId` names it and everything follows from the org\n * document and that id, as it always has. At the ORGANIZATION level the\n * hub hands every surface `hostId: null`, and the org comes from the mount\n * the hub published (`useCrmOrgMount`): the org root is known at once,\n * reads are unscoped, and the site a create stamps from is the one the\n * reader picked. A surface written against `{ scope, visibleTo,\n * createTokens }` serves both levels without knowing which it is on — the\n * two differences it cannot ignore are that `visibleTo` and `consentGroup`\n * are `null` at the org level, and both are typed to say so.\n *\n * `visibleTo` and `createTokens` are different questions with different\n * answers. The first is the union of everything this viewer may see; the\n * second is where a new record lands, which `crmScopeTokens` decides from\n * the org's default and is narrower — a group of one site creates for that\n * site, and reads the org-wide rows beside its own.\n *\n * Pure over the org document the shell already passed, so it costs no read;\n * only the org lookup behind `useOrgDataScope` is asynchronous, and `ready`\n * is how a surface tells \"not yet\" from \"no org\".\n */\nexport function useCrmScope(props: {\n hostId: string | null | undefined\n org?: CrmOrgDoc\n}): CrmScope {\n const hostId = props.hostId || null\n const org = (props.org ?? null) as Record<string, unknown> | null\n const mount = useCrmOrgMount()\n // Under a site the org is looked up from the host index; at the org level\n // it is the mount's, known at once. A `null` host with no mount is a\n // surface mounted nowhere, and resolves to no org rather than guessing.\n const { scope, orgId, ready } = useOrgDataScope(\n hostId ? { hostId } : { orgId: mount?.orgId },\n )\n const level: CrmScopeLevel = hostId ? 'site' : 'org'\n const consentGroup = useMemo(\n () => (hostId ? consentGroupForHost(org, hostId) : null),\n [org, hostId],\n )\n const visibleTo = useMemo(\n () => (consentGroup ? crmReadTokens(consentGroup) : null),\n [consentGroup],\n )\n const createHostId = hostId ?? mount?.createHostId ?? null\n const createGroup = useMemo(\n () => (createHostId ? consentGroupForHost(org, createHostId) : null),\n [org, createHostId],\n )\n const createTokens = useMemo(\n () => (createGroup ? crmScopeTokens(org, createGroup) : NO_TOKENS),\n [org, createGroup],\n )\n return useMemo(\n () => ({\n scope,\n orgId,\n ready,\n level,\n hostId,\n consentGroup,\n visibleTo,\n createHostId,\n createGroup,\n createTokens,\n }),\n [\n scope,\n orgId,\n ready,\n level,\n hostId,\n consentGroup,\n visibleTo,\n createHostId,\n createGroup,\n createTokens,\n ],\n )\n}\n\n/**\n * The scope clause a CRM listener carries, spelled once for both levels\n * (AGL-2630).\n *\n * Under a site: `where('visibleTo', 'array-contains-any', tokens)`, the\n * predicate the rules evaluate with `hasAny`, which is what makes a\n * filtered query provable per document. At the org level: NOTHING — the\n * reader is an org-wide member, the rules admit them to every row, and a\n * query that kept the clause would need the org's whole site list on it\n * and still miss a site the list did not carry. Spread into the query, so\n * the two cases are one line at every listener: `...crmVisibleToClause(\n * scope.visibleTo)`.\n *\n * A query that drops an `array-contains-any` may need a composite index\n * the scoped form did not: the equality and range clauses beside it stay,\n * and Firestore composes them on their own. The org-level entries live in\n * `cloud/firebase-firestore.indexes.json` beside their scoped twins.\n */\nexport function crmVisibleToClause(\n visibleTo: readonly ScopeToken[] | readonly string[] | null | undefined,\n): QueryConstraint[] {\n if (!visibleTo) return []\n return [where('visibleTo', 'array-contains-any', [...visibleTo])]\n}\n\n/**\n * Whether a listener that filters on `visibleTo` has anything to ask for:\n * `true` at the org level (no clause is a complete question), and under a\n * site only when the token list is non-empty — an `array-contains-any`\n * over nothing is a query Firestore refuses.\n */\nexport function crmScopeListable(\n visibleTo: readonly ScopeToken[] | readonly string[] | null | undefined,\n): boolean {\n return visibleTo === null || visibleTo === undefined || visibleTo.length > 0\n}\n\nexport default useCrmScope\n"],"names":["consentGroupForHost","crmReadTokens","crmScopeTokens","useOrgDataScope","where","useMemo","useCrmOrgMount","NO_TOKENS","Object","freeze","useCrmScope","props","hostId","org","mount","scope","orgId","ready","level","consentGroup","visibleTo","createHostId","createGroup","createTokens","crmVisibleToClause","crmScopeListable","undefined","length"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GACD;AAEA,SAGEA,mBAAmB,EACnBC,aAAa,EACbC,cAAc,QAET,eAAc;AACrB,SAASC,eAAe,QAAQ,iCAAgC;AAChE,SAA+BC,KAAK,QAAQ,qBAAoB;AAChE,SAASC,OAAO,QAAQ,QAAO;AAC/B,SAASC,cAAc,QAAQ,yBAAqB;AAyDpD,MAAMC,YAAmCC,OAAOC,MAAM,CAAC,EAAE;AAEzD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAmCC,GACD,OAAO,SAASC,YAAYC,KAG3B;QAEcA,YAiBQC;IAlBrB,MAAMA,SAASD,MAAMC,MAAM,IAAI;IAC/B,MAAMC,OAAOF,aAAAA,MAAME,GAAG,YAATF,aAAa;IAC1B,MAAMG,QAAQR;IACd,0EAA0E;IAC1E,qEAAqE;IACrE,wEAAwE;IACxE,MAAM,EAAES,KAAK,EAAEC,KAAK,EAAEC,KAAK,EAAE,GAAGd,gBAC9BS,SAAS;QAAEA;IAAO,IAAI;QAAEI,KAAK,EAAEF,yBAAAA,MAAOE,KAAK;IAAC;IAE9C,MAAME,QAAuBN,SAAS,SAAS;IAC/C,MAAMO,eAAed,QACnB,IAAOO,SAASZ,oBAAoBa,KAAKD,UAAU,MACnD;QAACC;QAAKD;KAAO;IAEf,MAAMQ,YAAYf,QAChB,IAAOc,eAAelB,cAAckB,gBAAgB,MACpD;QAACA;KAAa;IAEhB,MAAME,gBAAeT,OAAAA,iBAAAA,SAAUE,yBAAAA,MAAOO,YAAY,YAA7BT,OAAiC;IACtD,MAAMU,cAAcjB,QAClB,IAAOgB,eAAerB,oBAAoBa,KAAKQ,gBAAgB,MAC/D;QAACR;QAAKQ;KAAa;IAErB,MAAME,eAAelB,QACnB,IAAOiB,cAAcpB,eAAeW,KAAKS,eAAef,WACxD;QAACM;QAAKS;KAAY;IAEpB,OAAOjB,QACL,IAAO,CAAA;YACLU;YACAC;YACAC;YACAC;YACAN;YACAO;YACAC;YACAC;YACAC;YACAC;QACF,CAAA,GACA;QACER;QACAC;QACAC;QACAC;QACAN;QACAO;QACAC;QACAC;QACAC;QACAC;KACD;AAEL;AAEA;;;;;;;;;;;;;;;;;CAiBC,GACD,OAAO,SAASC,mBACdJ,SAAuE;IAEvE,IAAI,CAACA,WAAW,OAAO,EAAE;IACzB,OAAO;QAAChB,MAAM,aAAa,sBAAsB;eAAIgB;SAAU;KAAE;AACnE;AAEA;;;;;CAKC,GACD,OAAO,SAASK,iBACdL,SAAuE;IAEvE,OAAOA,cAAc,QAAQA,cAAcM,aAAaN,UAAUO,MAAM,GAAG;AAC7E;AAEA,eAAejB,YAAW"}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2026 Aglyn LLC
|
|
4
|
+
*
|
|
5
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
* you may not use this file except in compliance with the License.
|
|
7
|
+
* You may obtain a copy of the License at
|
|
8
|
+
*
|
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
*
|
|
11
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
* See the License for the specific language governing permissions and
|
|
15
|
+
* limitations under the License.
|
|
16
|
+
*/
|
|
17
|
+
import { type CrmTask } from '@aglyn/aglyn';
|
|
18
|
+
import { type CrmTaskView } from '../model/task-views';
|
|
19
|
+
/** A task as the console lists it: the document plus its id. */
|
|
20
|
+
export type CrmTaskRow = CrmTask & {
|
|
21
|
+
$id: string;
|
|
22
|
+
};
|
|
23
|
+
/**
|
|
24
|
+
* The reader's clock, refreshed once a minute (AGL-2599).
|
|
25
|
+
*
|
|
26
|
+
* "Overdue" and "today" are computed at read time against this value, so a
|
|
27
|
+
* tab left open across midnight repaints yesterday's work red without a
|
|
28
|
+
* reload. A minute is coarse enough that the re-render is invisible and fine
|
|
29
|
+
* enough that a task due at 9:00 does not read as upcoming at 9:05.
|
|
30
|
+
*/
|
|
31
|
+
export declare function useNowMs(): number;
|
|
32
|
+
export interface CrmTaskListResult {
|
|
33
|
+
tasks: CrmTaskRow[];
|
|
34
|
+
status: 'loading' | 'success' | 'error';
|
|
35
|
+
/** The rows are unconfirmed by the server — what a guarded write reads. */
|
|
36
|
+
fromCache: boolean;
|
|
37
|
+
/** The window filled up; there are tasks this view is not showing. */
|
|
38
|
+
truncated: boolean;
|
|
39
|
+
scope: readonly [string, string] | null;
|
|
40
|
+
orgId: string | null | undefined;
|
|
41
|
+
/** The reader's tokens, or `null` at the organization level — no clause (AGL-2630). */
|
|
42
|
+
readTokens: readonly string[] | null;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* One view of the tasks section as a live, bounded listener.
|
|
46
|
+
*
|
|
47
|
+
* The plan comes from `crmTaskViewPlan`, so the hook holds no opinion about
|
|
48
|
+
* what "today" means; it translates a plan into constraints in the order the
|
|
49
|
+
* `crmTasks` indexes are declared and caps the window. "My tasks" opens no
|
|
50
|
+
* listener at all until the reader's uid is known — a query for
|
|
51
|
+
* `assigneeUid == ''` would be a real read that could only answer nothing.
|
|
52
|
+
*/
|
|
53
|
+
export declare function useCrmTaskList(options: {
|
|
54
|
+
/** The site the list is read under, or `null` at the organization level. */
|
|
55
|
+
hostId: string | null;
|
|
56
|
+
org?: Record<string, unknown> | null;
|
|
57
|
+
view: CrmTaskView;
|
|
58
|
+
uid: string | null | undefined;
|
|
59
|
+
nowMs: number;
|
|
60
|
+
}): CrmTaskListResult;
|
|
61
|
+
/**
|
|
62
|
+
* How many of one record's tasks a card reads. A person with more than fifty
|
|
63
|
+
* open tasks about one contact has a different problem than a short list.
|
|
64
|
+
*/
|
|
65
|
+
export declare const CRM_RECORD_TASK_LIMIT = 50;
|
|
66
|
+
/** Which record a task list is FOR — exactly one of the three. */
|
|
67
|
+
export interface CrmRecordRef {
|
|
68
|
+
contactId?: string;
|
|
69
|
+
companyId?: string;
|
|
70
|
+
dealId?: string;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* The tasks that hang off one contact, company or deal, open and done
|
|
74
|
+
* together, soonest due first.
|
|
75
|
+
*
|
|
76
|
+
* Rides the per-record indexes — `(visibleTo, contactId, dueAtMs)` and its
|
|
77
|
+
* two siblings — with no status clause, because the card shows the open ones
|
|
78
|
+
* and counts the rest, and two listeners for one short list is one too many.
|
|
79
|
+
*/
|
|
80
|
+
export declare function useCrmRecordTasks(options: {
|
|
81
|
+
/** The site the record is read under, or `null` at the organization level. */
|
|
82
|
+
hostId: string | null;
|
|
83
|
+
org?: Record<string, unknown> | null;
|
|
84
|
+
record: CrmRecordRef;
|
|
85
|
+
}): CrmTaskListResult;
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2026 Aglyn LLC
|
|
4
|
+
*
|
|
5
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
* you may not use this file except in compliance with the License.
|
|
7
|
+
* You may obtain a copy of the License at
|
|
8
|
+
*
|
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
*
|
|
11
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
* See the License for the specific language governing permissions and
|
|
15
|
+
* limitations under the License.
|
|
16
|
+
*/ import { CRM_COLLECTIONS } from "@aglyn/aglyn";
|
|
17
|
+
import { useFirestore, useFirestoreCollection } from "@aglyn/tenant-feature-instance";
|
|
18
|
+
import { collection, limit, orderBy, query, where } from "firebase/firestore";
|
|
19
|
+
import { useEffect, useMemo, useState } from "react";
|
|
20
|
+
import { CRM_TASK_VIEW_LIMIT, crmTaskViewPlan, orderTaskRows } from "../model/task-views.js";
|
|
21
|
+
import { crmVisibleToClause, useCrmScope } from "./use-crm-scope.js";
|
|
22
|
+
/**
|
|
23
|
+
* The reader's clock, refreshed once a minute (AGL-2599).
|
|
24
|
+
*
|
|
25
|
+
* "Overdue" and "today" are computed at read time against this value, so a
|
|
26
|
+
* tab left open across midnight repaints yesterday's work red without a
|
|
27
|
+
* reload. A minute is coarse enough that the re-render is invisible and fine
|
|
28
|
+
* enough that a task due at 9:00 does not read as upcoming at 9:05.
|
|
29
|
+
*/ export function useNowMs() {
|
|
30
|
+
const [nowMs, setNowMs] = useState(()=>Date.now());
|
|
31
|
+
useEffect(()=>{
|
|
32
|
+
const timer = setInterval(()=>setNowMs(Date.now()), 60000);
|
|
33
|
+
return ()=>clearInterval(timer);
|
|
34
|
+
}, []);
|
|
35
|
+
return nowMs;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* One view of the tasks section as a live, bounded listener.
|
|
39
|
+
*
|
|
40
|
+
* The plan comes from `crmTaskViewPlan`, so the hook holds no opinion about
|
|
41
|
+
* what "today" means; it translates a plan into constraints in the order the
|
|
42
|
+
* `crmTasks` indexes are declared and caps the window. "My tasks" opens no
|
|
43
|
+
* listener at all until the reader's uid is known — a query for
|
|
44
|
+
* `assigneeUid == ''` would be a real read that could only answer nothing.
|
|
45
|
+
*/ export function useCrmTaskList(options) {
|
|
46
|
+
var _ref;
|
|
47
|
+
const { hostId, org, view, uid, nowMs } = options;
|
|
48
|
+
const firestore = useFirestore();
|
|
49
|
+
// The org root and the reader's tokens from the one scope hook (AGL-2614)
|
|
50
|
+
// — the same expression the contacts list runs, so a task listed beside a
|
|
51
|
+
// contact is scoped by exactly the predicate that admitted the contact.
|
|
52
|
+
const { scope, orgId, visibleTo: readTokens } = useCrmScope({
|
|
53
|
+
hostId,
|
|
54
|
+
org
|
|
55
|
+
});
|
|
56
|
+
const plan = useMemo(()=>crmTaskViewPlan(view, {
|
|
57
|
+
nowMs,
|
|
58
|
+
uid
|
|
59
|
+
}), [
|
|
60
|
+
view,
|
|
61
|
+
nowMs,
|
|
62
|
+
uid
|
|
63
|
+
]);
|
|
64
|
+
const { data, status, fromCache } = useFirestoreCollection(()=>{
|
|
65
|
+
if (!scope) return null;
|
|
66
|
+
if (plan.assigneeUid !== undefined && !plan.assigneeUid) return null;
|
|
67
|
+
const constraints = [
|
|
68
|
+
...crmVisibleToClause(readTokens),
|
|
69
|
+
where('status', '==', plan.status)
|
|
70
|
+
];
|
|
71
|
+
if (plan.assigneeUid) {
|
|
72
|
+
constraints.push(where('assigneeUid', '==', plan.assigneeUid));
|
|
73
|
+
}
|
|
74
|
+
if (plan.dueFrom !== undefined) {
|
|
75
|
+
constraints.push(where('dueAtMs', '>=', plan.dueFrom));
|
|
76
|
+
}
|
|
77
|
+
if (plan.dueBefore !== undefined) {
|
|
78
|
+
constraints.push(where('dueAtMs', '<', plan.dueBefore));
|
|
79
|
+
}
|
|
80
|
+
return query(collection(firestore, scope[0], scope[1], CRM_COLLECTIONS.tasks), ...constraints, orderBy('dueAtMs', plan.direction), limit(CRM_TASK_VIEW_LIMIT));
|
|
81
|
+
}, [
|
|
82
|
+
firestore,
|
|
83
|
+
scope,
|
|
84
|
+
readTokens,
|
|
85
|
+
plan.status,
|
|
86
|
+
plan.assigneeUid,
|
|
87
|
+
plan.dueFrom,
|
|
88
|
+
plan.dueBefore,
|
|
89
|
+
plan.direction
|
|
90
|
+
], {
|
|
91
|
+
idField: '$id'
|
|
92
|
+
});
|
|
93
|
+
const tasks = useMemo(()=>orderTaskRows(data != null ? data : []), [
|
|
94
|
+
data
|
|
95
|
+
]);
|
|
96
|
+
return {
|
|
97
|
+
tasks,
|
|
98
|
+
status,
|
|
99
|
+
fromCache,
|
|
100
|
+
truncated: ((_ref = data == null ? void 0 : data.length) != null ? _ref : 0) >= CRM_TASK_VIEW_LIMIT,
|
|
101
|
+
scope,
|
|
102
|
+
orgId,
|
|
103
|
+
readTokens
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* How many of one record's tasks a card reads. A person with more than fifty
|
|
108
|
+
* open tasks about one contact has a different problem than a short list.
|
|
109
|
+
*/ export const CRM_RECORD_TASK_LIMIT = 50;
|
|
110
|
+
/**
|
|
111
|
+
* The tasks that hang off one contact, company or deal, open and done
|
|
112
|
+
* together, soonest due first.
|
|
113
|
+
*
|
|
114
|
+
* Rides the per-record indexes — `(visibleTo, contactId, dueAtMs)` and its
|
|
115
|
+
* two siblings — with no status clause, because the card shows the open ones
|
|
116
|
+
* and counts the rest, and two listeners for one short list is one too many.
|
|
117
|
+
*/ export function useCrmRecordTasks(options) {
|
|
118
|
+
var _ref;
|
|
119
|
+
const { hostId, org, record } = options;
|
|
120
|
+
const firestore = useFirestore();
|
|
121
|
+
const { scope, orgId, visibleTo: readTokens } = useCrmScope({
|
|
122
|
+
hostId,
|
|
123
|
+
org
|
|
124
|
+
});
|
|
125
|
+
const field = record.contactId ? 'contactId' : record.companyId ? 'companyId' : record.dealId ? 'dealId' : null;
|
|
126
|
+
const id = field ? record[field] : undefined;
|
|
127
|
+
const { data, status, fromCache } = useFirestoreCollection(()=>{
|
|
128
|
+
if (!scope || !field || !id) return null;
|
|
129
|
+
return query(collection(firestore, scope[0], scope[1], CRM_COLLECTIONS.tasks), ...crmVisibleToClause(readTokens), where(field, '==', id), orderBy('dueAtMs', 'asc'), limit(CRM_RECORD_TASK_LIMIT));
|
|
130
|
+
}, [
|
|
131
|
+
firestore,
|
|
132
|
+
scope,
|
|
133
|
+
readTokens,
|
|
134
|
+
field,
|
|
135
|
+
id
|
|
136
|
+
], {
|
|
137
|
+
idField: '$id'
|
|
138
|
+
});
|
|
139
|
+
const tasks = useMemo(()=>orderTaskRows(data != null ? data : []), [
|
|
140
|
+
data
|
|
141
|
+
]);
|
|
142
|
+
return {
|
|
143
|
+
tasks,
|
|
144
|
+
status,
|
|
145
|
+
fromCache,
|
|
146
|
+
truncated: ((_ref = data == null ? void 0 : data.length) != null ? _ref : 0) >= CRM_RECORD_TASK_LIMIT,
|
|
147
|
+
scope,
|
|
148
|
+
orgId,
|
|
149
|
+
readTokens
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
//# sourceMappingURL=use-crm-tasks.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../../libs/plugins/crm/src/lib/hooks/use-crm-tasks.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { CRM_COLLECTIONS, type CrmTask } from '@aglyn/aglyn'\nimport {\n useFirestore,\n useFirestoreCollection,\n} from '@aglyn/tenant-feature-instance'\nimport {\n collection,\n limit,\n orderBy,\n query,\n type QueryConstraint,\n where,\n} from 'firebase/firestore'\nimport { useEffect, useMemo, useState } from 'react'\nimport {\n CRM_TASK_VIEW_LIMIT,\n type CrmTaskView,\n crmTaskViewPlan,\n orderTaskRows,\n} from '../model/task-views'\nimport { crmVisibleToClause, useCrmScope } from './use-crm-scope'\n\n/** A task as the console lists it: the document plus its id. */\nexport type CrmTaskRow = CrmTask & { $id: string }\n\n/**\n * The reader's clock, refreshed once a minute (AGL-2599).\n *\n * \"Overdue\" and \"today\" are computed at read time against this value, so a\n * tab left open across midnight repaints yesterday's work red without a\n * reload. A minute is coarse enough that the re-render is invisible and fine\n * enough that a task due at 9:00 does not read as upcoming at 9:05.\n */\nexport function useNowMs(): number {\n const [nowMs, setNowMs] = useState(() => Date.now())\n useEffect(() => {\n const timer = setInterval(() => setNowMs(Date.now()), 60_000)\n return () => clearInterval(timer)\n }, [])\n return nowMs\n}\n\nexport interface CrmTaskListResult {\n tasks: CrmTaskRow[]\n status: 'loading' | 'success' | 'error'\n /** The rows are unconfirmed by the server — what a guarded write reads. */\n fromCache: boolean\n /** The window filled up; there are tasks this view is not showing. */\n truncated: boolean\n scope: readonly [string, string] | null\n orgId: string | null | undefined\n /** The reader's tokens, or `null` at the organization level — no clause (AGL-2630). */\n readTokens: readonly string[] | null\n}\n\n/**\n * One view of the tasks section as a live, bounded listener.\n *\n * The plan comes from `crmTaskViewPlan`, so the hook holds no opinion about\n * what \"today\" means; it translates a plan into constraints in the order the\n * `crmTasks` indexes are declared and caps the window. \"My tasks\" opens no\n * listener at all until the reader's uid is known — a query for\n * `assigneeUid == ''` would be a real read that could only answer nothing.\n */\nexport function useCrmTaskList(options: {\n /** The site the list is read under, or `null` at the organization level. */\n hostId: string | null\n org?: Record<string, unknown> | null\n view: CrmTaskView\n uid: string | null | undefined\n nowMs: number\n}): CrmTaskListResult {\n const { hostId, org, view, uid, nowMs } = options\n const firestore = useFirestore()\n // The org root and the reader's tokens from the one scope hook (AGL-2614)\n // — the same expression the contacts list runs, so a task listed beside a\n // contact is scoped by exactly the predicate that admitted the contact.\n const { scope, orgId, visibleTo: readTokens } = useCrmScope({ hostId, org })\n const plan = useMemo(\n () => crmTaskViewPlan(view, { nowMs, uid }),\n [view, nowMs, uid],\n )\n const { data, status, fromCache } = useFirestoreCollection<CrmTaskRow>(\n () => {\n if (!scope) return null\n if (plan.assigneeUid !== undefined && !plan.assigneeUid) return null\n const constraints: QueryConstraint[] = [\n ...crmVisibleToClause(readTokens),\n where('status', '==', plan.status),\n ]\n if (plan.assigneeUid) {\n constraints.push(where('assigneeUid', '==', plan.assigneeUid))\n }\n if (plan.dueFrom !== undefined) {\n constraints.push(where('dueAtMs', '>=', plan.dueFrom))\n }\n if (plan.dueBefore !== undefined) {\n constraints.push(where('dueAtMs', '<', plan.dueBefore))\n }\n return query(\n collection(firestore, scope[0], scope[1], CRM_COLLECTIONS.tasks),\n ...constraints,\n orderBy('dueAtMs', plan.direction),\n limit(CRM_TASK_VIEW_LIMIT),\n )\n },\n [\n firestore,\n scope,\n readTokens,\n plan.status,\n plan.assigneeUid,\n plan.dueFrom,\n plan.dueBefore,\n plan.direction,\n ],\n { idField: '$id' },\n )\n const tasks = useMemo(() => orderTaskRows(data ?? []), [data])\n return {\n tasks,\n status,\n fromCache,\n truncated: (data?.length ?? 0) >= CRM_TASK_VIEW_LIMIT,\n scope,\n orgId,\n readTokens,\n }\n}\n\n/**\n * How many of one record's tasks a card reads. A person with more than fifty\n * open tasks about one contact has a different problem than a short list.\n */\nexport const CRM_RECORD_TASK_LIMIT = 50\n\n/** Which record a task list is FOR — exactly one of the three. */\nexport interface CrmRecordRef {\n contactId?: string\n companyId?: string\n dealId?: string\n}\n\n/**\n * The tasks that hang off one contact, company or deal, open and done\n * together, soonest due first.\n *\n * Rides the per-record indexes — `(visibleTo, contactId, dueAtMs)` and its\n * two siblings — with no status clause, because the card shows the open ones\n * and counts the rest, and two listeners for one short list is one too many.\n */\nexport function useCrmRecordTasks(options: {\n /** The site the record is read under, or `null` at the organization level. */\n hostId: string | null\n org?: Record<string, unknown> | null\n record: CrmRecordRef\n}): CrmTaskListResult {\n const { hostId, org, record } = options\n const firestore = useFirestore()\n const { scope, orgId, visibleTo: readTokens } = useCrmScope({ hostId, org })\n const field = record.contactId\n ? 'contactId'\n : record.companyId\n ? 'companyId'\n : record.dealId\n ? 'dealId'\n : null\n const id = field ? record[field] : undefined\n const { data, status, fromCache } = useFirestoreCollection<CrmTaskRow>(\n () => {\n if (!scope || !field || !id) return null\n return query(\n collection(firestore, scope[0], scope[1], CRM_COLLECTIONS.tasks),\n ...crmVisibleToClause(readTokens),\n where(field, '==', id),\n orderBy('dueAtMs', 'asc'),\n limit(CRM_RECORD_TASK_LIMIT),\n )\n },\n [firestore, scope, readTokens, field, id],\n { idField: '$id' },\n )\n const tasks = useMemo(() => orderTaskRows(data ?? []), [data])\n return {\n tasks,\n status,\n fromCache,\n truncated: (data?.length ?? 0) >= CRM_RECORD_TASK_LIMIT,\n scope,\n orgId,\n readTokens,\n }\n}\n"],"names":["CRM_COLLECTIONS","useFirestore","useFirestoreCollection","collection","limit","orderBy","query","where","useEffect","useMemo","useState","CRM_TASK_VIEW_LIMIT","crmTaskViewPlan","orderTaskRows","crmVisibleToClause","useCrmScope","useNowMs","nowMs","setNowMs","Date","now","timer","setInterval","clearInterval","useCrmTaskList","options","hostId","org","view","uid","firestore","scope","orgId","visibleTo","readTokens","plan","data","status","fromCache","assigneeUid","undefined","constraints","push","dueFrom","dueBefore","tasks","direction","idField","truncated","length","CRM_RECORD_TASK_LIMIT","useCrmRecordTasks","record","field","contactId","companyId","dealId","id"],"mappings":"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"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import type { GridColDef, GridColumnVisibilityModel, GridSortModel } from '@mui/x-data-grid';
|
|
2
|
+
import type { CrmSavedViewController } from './use-crm-saved-view';
|
|
3
|
+
/**
|
|
4
|
+
* The visible columns as the view orders them, and the one way to move one.
|
|
5
|
+
*
|
|
6
|
+
* What the column menu's Move left / Move right read and call — see
|
|
7
|
+
* `crm-column-menu.tsx`. The grid itself cannot reorder a column (the MIT
|
|
8
|
+
* grid forces `disableColumnReorder`), so the order is the view's to keep
|
|
9
|
+
* and the hook's to apply.
|
|
10
|
+
*/
|
|
11
|
+
export interface CrmColumnOrder {
|
|
12
|
+
/** The visible, hideable columns by field, first to last as the grid shows them. */
|
|
13
|
+
order: readonly string[];
|
|
14
|
+
/** Swap a column with its visible neighbor: `-1` toward the front, `1` toward the end. */
|
|
15
|
+
move: (field: string, delta: -1 | 1) => void;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* The grid's columns, column and sort models, as a saved view holds them
|
|
19
|
+
* (AGL-2617).
|
|
20
|
+
*
|
|
21
|
+
* A view stores the VISIBLE columns by field, in order, and one sort; the
|
|
22
|
+
* grid speaks a column array, a visibility map and a sort array. This is
|
|
23
|
+
* the one translation, so all five lists hand the grid the same controlled
|
|
24
|
+
* models and read the same changes back. An empty column list means the
|
|
25
|
+
* list's own default — every hideable column shown, in the list's order —
|
|
26
|
+
* and a change that arrives back at that default is stored as the empty
|
|
27
|
+
* list rather than as a copy of today's columns, so a view saved before a
|
|
28
|
+
* column existed shows the new column too.
|
|
29
|
+
*
|
|
30
|
+
* ## The order is the view's
|
|
31
|
+
*
|
|
32
|
+
* `columns` is the caller's list re-arranged: the hideable columns take
|
|
33
|
+
* the view's order, and a column the list pins (`hideable: false`, an
|
|
34
|
+
* actions column) keeps the slot it was given. The grid rebuilds its own
|
|
35
|
+
* order from the array whenever it changes, so handing it the arranged
|
|
36
|
+
* array IS the reorder — and a change to the visible set keeps the order
|
|
37
|
+
* the reader had, rather than falling back to the list's.
|
|
38
|
+
*
|
|
39
|
+
* `hidden` is what the list keeps out of sight by default — the
|
|
40
|
+
* filter-only columns the contacts grammar declares, and an optional column
|
|
41
|
+
* a reader turns on when they want it — and is folded into the default
|
|
42
|
+
* model, so the empty list means the columns the list opens with rather than
|
|
43
|
+
* every column it has, and a view that shows an optional column stores it
|
|
44
|
+
* by name.
|
|
45
|
+
*/
|
|
46
|
+
export declare function useCrmViewGrid(controller: Pick<CrmSavedViewController, 'state' | 'setColumns' | 'setSort'>, columns: readonly GridColDef[], hidden?: Readonly<Record<string, boolean>>): {
|
|
47
|
+
/** The caller's columns, in the view's order. */
|
|
48
|
+
columns: GridColDef[];
|
|
49
|
+
columnVisibilityModel: GridColumnVisibilityModel;
|
|
50
|
+
onColumnVisibilityModelChange: (model: GridColumnVisibilityModel) => void;
|
|
51
|
+
columnOrder: CrmColumnOrder;
|
|
52
|
+
sortModel: GridSortModel;
|
|
53
|
+
onSortModelChange: (model: GridSortModel) => void;
|
|
54
|
+
};
|
|
55
|
+
export default useCrmViewGrid;
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2026 Aglyn LLC
|
|
4
|
+
*
|
|
5
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
* you may not use this file except in compliance with the License.
|
|
7
|
+
* You may obtain a copy of the License at
|
|
8
|
+
*
|
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
*
|
|
11
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
* See the License for the specific language governing permissions and
|
|
15
|
+
* limitations under the License.
|
|
16
|
+
*/ 'use client';
|
|
17
|
+
import { _ as _extends } from "@swc/helpers/_/_extends";
|
|
18
|
+
import { useCallback, useMemo } from "react";
|
|
19
|
+
/**
|
|
20
|
+
* Every hideable field in the view's order: the ones the view names, as it
|
|
21
|
+
* names them, then the rest in the list's own order.
|
|
22
|
+
*
|
|
23
|
+
* A column the view does not name is a hidden one (or one that did not
|
|
24
|
+
* exist when the view was saved), so its place is invisible until it is
|
|
25
|
+
* shown — and then it joins after the named ones, which is where the
|
|
26
|
+
* Manage columns panel listed it. A name the list no longer has is dropped
|
|
27
|
+
* rather than kept as a phantom slot.
|
|
28
|
+
*/ function orderFields(listFields, named) {
|
|
29
|
+
const known = new Set(listFields);
|
|
30
|
+
const placed = named.filter((field)=>known.has(field));
|
|
31
|
+
if (!placed.length) return [
|
|
32
|
+
...listFields
|
|
33
|
+
];
|
|
34
|
+
const taken = new Set(placed);
|
|
35
|
+
return [
|
|
36
|
+
...placed,
|
|
37
|
+
...listFields.filter((field)=>!taken.has(field))
|
|
38
|
+
];
|
|
39
|
+
}
|
|
40
|
+
const sameOrder = (a, b)=>a.length === b.length && a.every((field, index)=>field === b[index]);
|
|
41
|
+
/**
|
|
42
|
+
* The grid's columns, column and sort models, as a saved view holds them
|
|
43
|
+
* (AGL-2617).
|
|
44
|
+
*
|
|
45
|
+
* A view stores the VISIBLE columns by field, in order, and one sort; the
|
|
46
|
+
* grid speaks a column array, a visibility map and a sort array. This is
|
|
47
|
+
* the one translation, so all five lists hand the grid the same controlled
|
|
48
|
+
* models and read the same changes back. An empty column list means the
|
|
49
|
+
* list's own default — every hideable column shown, in the list's order —
|
|
50
|
+
* and a change that arrives back at that default is stored as the empty
|
|
51
|
+
* list rather than as a copy of today's columns, so a view saved before a
|
|
52
|
+
* column existed shows the new column too.
|
|
53
|
+
*
|
|
54
|
+
* ## The order is the view's
|
|
55
|
+
*
|
|
56
|
+
* `columns` is the caller's list re-arranged: the hideable columns take
|
|
57
|
+
* the view's order, and a column the list pins (`hideable: false`, an
|
|
58
|
+
* actions column) keeps the slot it was given. The grid rebuilds its own
|
|
59
|
+
* order from the array whenever it changes, so handing it the arranged
|
|
60
|
+
* array IS the reorder — and a change to the visible set keeps the order
|
|
61
|
+
* the reader had, rather than falling back to the list's.
|
|
62
|
+
*
|
|
63
|
+
* `hidden` is what the list keeps out of sight by default — the
|
|
64
|
+
* filter-only columns the contacts grammar declares, and an optional column
|
|
65
|
+
* a reader turns on when they want it — and is folded into the default
|
|
66
|
+
* model, so the empty list means the columns the list opens with rather than
|
|
67
|
+
* every column it has, and a view that shows an optional column stores it
|
|
68
|
+
* by name.
|
|
69
|
+
*/ export function useCrmViewGrid(controller, columns, hidden = {}) {
|
|
70
|
+
const { state, setColumns, setSort } = controller;
|
|
71
|
+
const hideable = useMemo(()=>columns.filter((column)=>column.hideable !== false).map((column)=>column.field), [
|
|
72
|
+
columns
|
|
73
|
+
]);
|
|
74
|
+
/** Every hideable field, in the view's order. */ const ordered = useMemo(()=>orderFields(hideable, state.columns), [
|
|
75
|
+
hideable,
|
|
76
|
+
state.columns
|
|
77
|
+
]);
|
|
78
|
+
const orderedColumns = useMemo(()=>{
|
|
79
|
+
const byField = new Map(columns.map((column)=>[
|
|
80
|
+
column.field,
|
|
81
|
+
column
|
|
82
|
+
]));
|
|
83
|
+
let next = 0;
|
|
84
|
+
// A pinned column keeps its slot; each hideable slot is refilled in order.
|
|
85
|
+
return columns.map((column)=>{
|
|
86
|
+
var _byField_get;
|
|
87
|
+
return column.hideable === false ? column : (_byField_get = byField.get(ordered[next++])) != null ? _byField_get : column;
|
|
88
|
+
});
|
|
89
|
+
}, [
|
|
90
|
+
columns,
|
|
91
|
+
ordered
|
|
92
|
+
]);
|
|
93
|
+
const columnVisibilityModel = useMemo(()=>{
|
|
94
|
+
const model = _extends({}, hidden);
|
|
95
|
+
if (!state.columns.length) return model;
|
|
96
|
+
for (const field of hideable)model[field] = state.columns.includes(field);
|
|
97
|
+
return model;
|
|
98
|
+
}, [
|
|
99
|
+
hidden,
|
|
100
|
+
state.columns,
|
|
101
|
+
hideable
|
|
102
|
+
]);
|
|
103
|
+
/** The columns the list opens with: every hideable one not hidden by default, in list order. */ const defaultVisible = useMemo(()=>hideable.filter((field)=>hidden[field] !== false), [
|
|
104
|
+
hideable,
|
|
105
|
+
hidden
|
|
106
|
+
]);
|
|
107
|
+
/** The visible columns in the view's order — what a store writes back. */ const visibleInOrder = useMemo(()=>ordered.filter((field)=>columnVisibilityModel[field] !== false), [
|
|
108
|
+
ordered,
|
|
109
|
+
columnVisibilityModel
|
|
110
|
+
]);
|
|
111
|
+
const store = useCallback((visible)=>setColumns(sameOrder(visible, defaultVisible) ? [] : visible), [
|
|
112
|
+
setColumns,
|
|
113
|
+
defaultVisible
|
|
114
|
+
]);
|
|
115
|
+
const onColumnVisibilityModelChange = useCallback((model)=>{
|
|
116
|
+
store(ordered.filter((field)=>model[field] !== false));
|
|
117
|
+
}, [
|
|
118
|
+
ordered,
|
|
119
|
+
store
|
|
120
|
+
]);
|
|
121
|
+
const move = useCallback((field, delta)=>{
|
|
122
|
+
const from = visibleInOrder.indexOf(field);
|
|
123
|
+
const to = from + delta;
|
|
124
|
+
if (from === -1 || to < 0 || to >= visibleInOrder.length) return;
|
|
125
|
+
const next = [
|
|
126
|
+
...visibleInOrder
|
|
127
|
+
];
|
|
128
|
+
next[from] = visibleInOrder[to];
|
|
129
|
+
next[to] = field;
|
|
130
|
+
store(next);
|
|
131
|
+
}, [
|
|
132
|
+
visibleInOrder,
|
|
133
|
+
store
|
|
134
|
+
]);
|
|
135
|
+
const columnOrder = useMemo(()=>({
|
|
136
|
+
order: visibleInOrder,
|
|
137
|
+
move
|
|
138
|
+
}), [
|
|
139
|
+
visibleInOrder,
|
|
140
|
+
move
|
|
141
|
+
]);
|
|
142
|
+
const sortModel = useMemo(()=>state.sort ? [
|
|
143
|
+
{
|
|
144
|
+
field: state.sort.field,
|
|
145
|
+
sort: state.sort.direction
|
|
146
|
+
}
|
|
147
|
+
] : [], [
|
|
148
|
+
state.sort
|
|
149
|
+
]);
|
|
150
|
+
const onSortModelChange = useCallback((model)=>{
|
|
151
|
+
const first = model[0];
|
|
152
|
+
setSort(first && first.sort ? {
|
|
153
|
+
field: first.field,
|
|
154
|
+
direction: first.sort === 'desc' ? 'desc' : 'asc'
|
|
155
|
+
} : null);
|
|
156
|
+
}, [
|
|
157
|
+
setSort
|
|
158
|
+
]);
|
|
159
|
+
return {
|
|
160
|
+
columns: orderedColumns,
|
|
161
|
+
columnVisibilityModel,
|
|
162
|
+
onColumnVisibilityModelChange,
|
|
163
|
+
columnOrder,
|
|
164
|
+
sortModel,
|
|
165
|
+
onSortModelChange
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
export default useCrmViewGrid;
|
|
169
|
+
|
|
170
|
+
//# sourceMappingURL=use-crm-view-grid.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../../libs/plugins/crm/src/lib/hooks/use-crm-view-grid.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n'use client'\n\nimport type {\n GridColDef,\n GridColumnVisibilityModel,\n GridSortModel,\n} from '@mui/x-data-grid'\nimport { useCallback, useMemo } from 'react'\nimport type { CrmSavedViewController } from './use-crm-saved-view'\n\n/**\n * The visible columns as the view orders them, and the one way to move one.\n *\n * What the column menu's Move left / Move right read and call — see\n * `crm-column-menu.tsx`. The grid itself cannot reorder a column (the MIT\n * grid forces `disableColumnReorder`), so the order is the view's to keep\n * and the hook's to apply.\n */\nexport interface CrmColumnOrder {\n /** The visible, hideable columns by field, first to last as the grid shows them. */\n order: readonly string[]\n /** Swap a column with its visible neighbor: `-1` toward the front, `1` toward the end. */\n move: (field: string, delta: -1 | 1) => void\n}\n\n/**\n * Every hideable field in the view's order: the ones the view names, as it\n * names them, then the rest in the list's own order.\n *\n * A column the view does not name is a hidden one (or one that did not\n * exist when the view was saved), so its place is invisible until it is\n * shown — and then it joins after the named ones, which is where the\n * Manage columns panel listed it. A name the list no longer has is dropped\n * rather than kept as a phantom slot.\n */\nfunction orderFields(listFields: readonly string[], named: readonly string[]): string[] {\n const known = new Set(listFields)\n const placed = named.filter((field) => known.has(field))\n if (!placed.length) return [...listFields]\n const taken = new Set(placed)\n return [...placed, ...listFields.filter((field) => !taken.has(field))]\n}\n\nconst sameOrder = (a: readonly string[], b: readonly string[]): boolean =>\n a.length === b.length && a.every((field, index) => field === b[index])\n\n/**\n * The grid's columns, column and sort models, as a saved view holds them\n * (AGL-2617).\n *\n * A view stores the VISIBLE columns by field, in order, and one sort; the\n * grid speaks a column array, a visibility map and a sort array. This is\n * the one translation, so all five lists hand the grid the same controlled\n * models and read the same changes back. An empty column list means the\n * list's own default — every hideable column shown, in the list's order —\n * and a change that arrives back at that default is stored as the empty\n * list rather than as a copy of today's columns, so a view saved before a\n * column existed shows the new column too.\n *\n * ## The order is the view's\n *\n * `columns` is the caller's list re-arranged: the hideable columns take\n * the view's order, and a column the list pins (`hideable: false`, an\n * actions column) keeps the slot it was given. The grid rebuilds its own\n * order from the array whenever it changes, so handing it the arranged\n * array IS the reorder — and a change to the visible set keeps the order\n * the reader had, rather than falling back to the list's.\n *\n * `hidden` is what the list keeps out of sight by default — the\n * filter-only columns the contacts grammar declares, and an optional column\n * a reader turns on when they want it — and is folded into the default\n * model, so the empty list means the columns the list opens with rather than\n * every column it has, and a view that shows an optional column stores it\n * by name.\n */\nexport function useCrmViewGrid(\n controller: Pick<CrmSavedViewController, 'state' | 'setColumns' | 'setSort'>,\n columns: readonly GridColDef[],\n hidden: Readonly<Record<string, boolean>> = {},\n): {\n /** The caller's columns, in the view's order. */\n columns: GridColDef[]\n columnVisibilityModel: GridColumnVisibilityModel\n onColumnVisibilityModelChange: (model: GridColumnVisibilityModel) => void\n columnOrder: CrmColumnOrder\n sortModel: GridSortModel\n onSortModelChange: (model: GridSortModel) => void\n} {\n const { state, setColumns, setSort } = controller\n const hideable = useMemo(\n () => columns.filter((column) => column.hideable !== false).map((column) => column.field),\n [columns],\n )\n\n /** Every hideable field, in the view's order. */\n const ordered = useMemo(() => orderFields(hideable, state.columns), [hideable, state.columns])\n\n const orderedColumns = useMemo(() => {\n const byField = new Map(columns.map((column) => [column.field, column]))\n let next = 0\n // A pinned column keeps its slot; each hideable slot is refilled in order.\n return columns.map((column) =>\n column.hideable === false ? column : (byField.get(ordered[next++]) ?? column),\n )\n }, [columns, ordered])\n\n const columnVisibilityModel = useMemo<GridColumnVisibilityModel>(() => {\n const model: GridColumnVisibilityModel = { ...hidden }\n if (!state.columns.length) return model\n for (const field of hideable) model[field] = state.columns.includes(field)\n return model\n }, [hidden, state.columns, hideable])\n\n /** The columns the list opens with: every hideable one not hidden by default, in list order. */\n const defaultVisible = useMemo(\n () => hideable.filter((field) => hidden[field] !== false),\n [hideable, hidden],\n )\n\n /** The visible columns in the view's order — what a store writes back. */\n const visibleInOrder = useMemo(\n () => ordered.filter((field) => columnVisibilityModel[field] !== false),\n [ordered, columnVisibilityModel],\n )\n\n const store = useCallback(\n (visible: string[]) => setColumns(sameOrder(visible, defaultVisible) ? [] : visible),\n [setColumns, defaultVisible],\n )\n\n const onColumnVisibilityModelChange = useCallback(\n (model: GridColumnVisibilityModel) => {\n store(ordered.filter((field) => model[field] !== false))\n },\n [ordered, store],\n )\n\n const move = useCallback(\n (field: string, delta: -1 | 1) => {\n const from = visibleInOrder.indexOf(field)\n const to = from + delta\n if (from === -1 || to < 0 || to >= visibleInOrder.length) return\n const next = [...visibleInOrder]\n next[from] = visibleInOrder[to]\n next[to] = field\n store(next)\n },\n [visibleInOrder, store],\n )\n\n const columnOrder = useMemo<CrmColumnOrder>(\n () => ({ order: visibleInOrder, move }),\n [visibleInOrder, move],\n )\n\n const sortModel = useMemo<GridSortModel>(\n () => (state.sort ? [{ field: state.sort.field, sort: state.sort.direction }] : []),\n [state.sort],\n )\n\n const onSortModelChange = useCallback(\n (model: GridSortModel) => {\n const first = model[0]\n setSort(\n first && first.sort\n ? { field: first.field, direction: first.sort === 'desc' ? 'desc' : 'asc' }\n : null,\n )\n },\n [setSort],\n )\n\n return {\n columns: orderedColumns,\n columnVisibilityModel,\n onColumnVisibilityModelChange,\n columnOrder,\n sortModel,\n onSortModelChange,\n }\n}\n\nexport default useCrmViewGrid\n"],"names":["useCallback","useMemo","orderFields","listFields","named","known","Set","placed","filter","field","has","length","taken","sameOrder","a","b","every","index","useCrmViewGrid","controller","columns","hidden","state","setColumns","setSort","hideable","column","map","ordered","orderedColumns","byField","Map","next","get","columnVisibilityModel","model","includes","defaultVisible","visibleInOrder","store","visible","onColumnVisibilityModelChange","move","delta","from","indexOf","to","columnOrder","order","sortModel","sort","direction","onSortModelChange","first"],"mappings":"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"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { type CrmSavedView, type CrmViewSection } from '@aglyn/aglyn';
|
|
2
|
+
/** One saved view as the menu lists it: the document, held to shape, with its id. */
|
|
3
|
+
export interface CrmSavedViewRow extends CrmSavedView {
|
|
4
|
+
$id: string;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* The menu's window.
|
|
8
|
+
*
|
|
9
|
+
* A LOOKUP, not a list: nothing pages this, a reader opens a menu rather
|
|
10
|
+
* than walking it, and a hundred named views for one section of one org is
|
|
11
|
+
* past what anybody scrolls. Bounded so the listen cannot grow with the
|
|
12
|
+
* org; a view past the window is still reachable by its address, which
|
|
13
|
+
* resolves through the same rows and so reads as "not listed" rather than
|
|
14
|
+
* as missing — see the controller.
|
|
15
|
+
*/
|
|
16
|
+
export declare const CRM_VIEWS_LIMIT = 100;
|
|
17
|
+
/**
|
|
18
|
+
* The saved views of one section, mine and shared (AGL-2617).
|
|
19
|
+
*
|
|
20
|
+
* ONE listener, filtered on the reader's own tokens like every CRM read,
|
|
21
|
+
* narrowed to the section and ordered by name — the `(visibleTo, section,
|
|
22
|
+
* name)` index. What the rules admit is wider than what the menu shows: a
|
|
23
|
+
* colleague's private view is readable under the contacts predicate and
|
|
24
|
+
* hidden here by `crmViewIsListed`, because the privacy of a working
|
|
25
|
+
* arrangement is a courtesy between colleagues rather than a disclosure
|
|
26
|
+
* boundary, and a rule per reader would need a query per reader.
|
|
27
|
+
*
|
|
28
|
+
* `orderBy('name')` also FILTERS: a view written without a name would be
|
|
29
|
+
* missing from its own menu. The controller refuses an empty name, which is
|
|
30
|
+
* the only writer.
|
|
31
|
+
*/
|
|
32
|
+
export declare function useCrmViews(options: {
|
|
33
|
+
scope: readonly ['orgs', string] | null;
|
|
34
|
+
/** The reader's tokens, or `null` at the organization level — no clause (AGL-2630). */
|
|
35
|
+
visibleTo: readonly string[] | null;
|
|
36
|
+
section: CrmViewSection;
|
|
37
|
+
uid: string | null | undefined;
|
|
38
|
+
}): {
|
|
39
|
+
views: CrmSavedViewRow[];
|
|
40
|
+
ready: boolean;
|
|
41
|
+
};
|
|
42
|
+
export default useCrmViews;
|