@open-mercato/core 0.4.2-canary-f821f89ef6 → 0.4.2-canary-3b5064ce72
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/dist/generated/entities/notification/index.js +57 -0
- package/dist/generated/entities/notification/index.js.map +7 -0
- package/dist/generated/entities.ids.generated.js +5 -2
- package/dist/generated/entities.ids.generated.js.map +2 -2
- package/dist/generated/entity-fields-registry.js +2 -2
- package/dist/generated/entity-fields-registry.js.map +2 -2
- package/dist/modules/api_docs/frontend/docs/api/page.js +3 -2
- package/dist/modules/api_docs/frontend/docs/api/page.js.map +2 -2
- package/dist/modules/api_keys/backend/api-keys/page.js +1 -1
- package/dist/modules/api_keys/backend/api-keys/page.js.map +2 -2
- package/dist/modules/attachments/components/AttachmentLibrary.js +4 -0
- package/dist/modules/attachments/components/AttachmentLibrary.js.map +2 -2
- package/dist/modules/attachments/components/AttachmentPartitionSettings.js +2 -0
- package/dist/modules/attachments/components/AttachmentPartitionSettings.js.map +2 -2
- package/dist/modules/auth/api/admin/nav.js +4 -3
- package/dist/modules/auth/api/admin/nav.js.map +2 -2
- package/dist/modules/auth/api/login.js +25 -6
- package/dist/modules/auth/api/login.js.map +2 -2
- package/dist/modules/auth/api/profile/route.js +157 -0
- package/dist/modules/auth/api/profile/route.js.map +7 -0
- package/dist/modules/auth/api/reset/confirm.js +25 -2
- package/dist/modules/auth/api/reset/confirm.js.map +2 -2
- package/dist/modules/auth/api/reset.js +23 -0
- package/dist/modules/auth/api/reset.js.map +2 -2
- package/dist/modules/auth/api/sidebar/preferences/route.js +14 -9
- package/dist/modules/auth/api/sidebar/preferences/route.js.map +2 -2
- package/dist/modules/auth/api/users/route.js +4 -2
- package/dist/modules/auth/api/users/route.js.map +2 -2
- package/dist/modules/auth/backend/auth/profile/page.js +141 -0
- package/dist/modules/auth/backend/auth/profile/page.js.map +7 -0
- package/dist/modules/auth/backend/auth/profile/page.meta.js +13 -0
- package/dist/modules/auth/backend/auth/profile/page.meta.js.map +7 -0
- package/dist/modules/auth/backend/roles/[id]/edit/page.js +4 -1
- package/dist/modules/auth/backend/roles/[id]/edit/page.js.map +2 -2
- package/dist/modules/auth/backend/roles/page.js +3 -3
- package/dist/modules/auth/backend/roles/page.js.map +2 -2
- package/dist/modules/auth/backend/users/[id]/edit/page.js +18 -3
- package/dist/modules/auth/backend/users/[id]/edit/page.js.map +2 -2
- package/dist/modules/auth/backend/users/create/page.js +15 -2
- package/dist/modules/auth/backend/users/create/page.js.map +2 -2
- package/dist/modules/auth/backend/users/page.js +3 -3
- package/dist/modules/auth/backend/users/page.js.map +2 -2
- package/dist/modules/auth/cli.js +25 -11
- package/dist/modules/auth/cli.js.map +2 -2
- package/dist/modules/auth/commands/users.js +59 -2
- package/dist/modules/auth/commands/users.js.map +2 -2
- package/dist/modules/auth/data/validators.js +6 -3
- package/dist/modules/auth/data/validators.js.map +2 -2
- package/dist/modules/auth/frontend/login.js +112 -3
- package/dist/modules/auth/frontend/login.js.map +2 -2
- package/dist/modules/auth/frontend/reset/[token]/page.js +20 -10
- package/dist/modules/auth/frontend/reset/[token]/page.js.map +2 -2
- package/dist/modules/auth/lib/setup-app.js +42 -8
- package/dist/modules/auth/lib/setup-app.js.map +2 -2
- package/dist/modules/auth/notifications.js +112 -0
- package/dist/modules/auth/notifications.js.map +7 -0
- package/dist/modules/auth/services/authService.js +24 -3
- package/dist/modules/auth/services/authService.js.map +2 -2
- package/dist/modules/business_rules/api/execute/route.js +7 -1
- package/dist/modules/business_rules/api/execute/route.js.map +2 -2
- package/dist/modules/business_rules/backend/rules/page.js +4 -0
- package/dist/modules/business_rules/backend/rules/page.js.map +2 -2
- package/dist/modules/business_rules/backend/sets/page.js +3 -0
- package/dist/modules/business_rules/backend/sets/page.js.map +2 -2
- package/dist/modules/business_rules/cli.js +2 -1
- package/dist/modules/business_rules/cli.js.map +2 -2
- package/dist/modules/business_rules/data/validators.js +0 -34
- package/dist/modules/business_rules/data/validators.js.map +2 -2
- package/dist/modules/business_rules/index.js +1 -21
- package/dist/modules/business_rules/index.js.map +2 -2
- package/dist/modules/business_rules/lib/rule-engine.js +34 -185
- package/dist/modules/business_rules/lib/rule-engine.js.map +2 -2
- package/dist/modules/business_rules/notifications.js +28 -0
- package/dist/modules/business_rules/notifications.js.map +7 -0
- package/dist/modules/business_rules/subscribers/rule-execution-failed-notification.js +37 -0
- package/dist/modules/business_rules/subscribers/rule-execution-failed-notification.js.map +7 -0
- package/dist/modules/catalog/components/PriceKindSettings.js +2 -0
- package/dist/modules/catalog/components/PriceKindSettings.js.map +2 -2
- package/dist/modules/catalog/components/categories/CategoriesDataTable.js +2 -2
- package/dist/modules/catalog/components/categories/CategoriesDataTable.js.map +2 -2
- package/dist/modules/catalog/components/products/ProductsDataTable.js +2 -0
- package/dist/modules/catalog/components/products/ProductsDataTable.js.map +2 -2
- package/dist/modules/catalog/notifications.js +28 -0
- package/dist/modules/catalog/notifications.js.map +7 -0
- package/dist/modules/catalog/subscribers/low-stock-notification.js +38 -0
- package/dist/modules/catalog/subscribers/low-stock-notification.js.map +7 -0
- package/dist/modules/configs/cli.js +6 -0
- package/dist/modules/configs/cli.js.map +2 -2
- package/dist/modules/configs/components/CachePanel.js +4 -4
- package/dist/modules/configs/components/CachePanel.js.map +2 -2
- package/dist/modules/configs/lib/system-status.js +48 -1
- package/dist/modules/configs/lib/system-status.js.map +2 -2
- package/dist/modules/configs/lib/upgrade-actions.js +18 -0
- package/dist/modules/configs/lib/upgrade-actions.js.map +2 -2
- package/dist/modules/currencies/backend/currencies/page.js +3 -0
- package/dist/modules/currencies/backend/currencies/page.js.map +2 -2
- package/dist/modules/currencies/backend/exchange-rates/page.js +2 -0
- package/dist/modules/currencies/backend/exchange-rates/page.js.map +2 -2
- package/dist/modules/customers/backend/customers/companies/page.js +3 -0
- package/dist/modules/customers/backend/customers/companies/page.js.map +2 -2
- package/dist/modules/customers/backend/customers/deals/page.js +3 -0
- package/dist/modules/customers/backend/customers/deals/page.js.map +2 -2
- package/dist/modules/customers/backend/customers/people/page.js +3 -0
- package/dist/modules/customers/backend/customers/people/page.js.map +2 -2
- package/dist/modules/customers/commands/deals.js +31 -0
- package/dist/modules/customers/commands/deals.js.map +2 -2
- package/dist/modules/customers/components/CustomerTodosTable.js +1 -0
- package/dist/modules/customers/components/CustomerTodosTable.js.map +2 -2
- package/dist/modules/customers/notifications.js +48 -0
- package/dist/modules/customers/notifications.js.map +7 -0
- package/dist/modules/customers/widgets/dashboard/customer-todos/widget.js +2 -1
- package/dist/modules/customers/widgets/dashboard/customer-todos/widget.js.map +2 -2
- package/dist/modules/customers/widgets/dashboard/new-customers/widget.js +2 -1
- package/dist/modules/customers/widgets/dashboard/new-customers/widget.js.map +2 -2
- package/dist/modules/customers/widgets/dashboard/new-deals/widget.js +2 -1
- package/dist/modules/customers/widgets/dashboard/new-deals/widget.js.map +2 -2
- package/dist/modules/customers/widgets/dashboard/next-interactions/widget.js +2 -1
- package/dist/modules/customers/widgets/dashboard/next-interactions/widget.js.map +2 -2
- package/dist/modules/dashboards/cli.js +44 -5
- package/dist/modules/dashboards/cli.js.map +2 -2
- package/dist/modules/dashboards/components/WidgetVisibilityEditor.js +16 -11
- package/dist/modules/dashboards/components/WidgetVisibilityEditor.js.map +3 -3
- package/dist/modules/dashboards/lib/role-widgets.js +58 -0
- package/dist/modules/dashboards/lib/role-widgets.js.map +7 -0
- package/dist/modules/dashboards/services/widgetDataService.js +139 -3
- package/dist/modules/dashboards/services/widgetDataService.js.map +2 -2
- package/dist/modules/dashboards/widgets/dashboard/aov-kpi/widget.js +2 -1
- package/dist/modules/dashboards/widgets/dashboard/aov-kpi/widget.js.map +2 -2
- package/dist/modules/dashboards/widgets/dashboard/new-customers-kpi/widget.js +2 -1
- package/dist/modules/dashboards/widgets/dashboard/new-customers-kpi/widget.js.map +2 -2
- package/dist/modules/dashboards/widgets/dashboard/orders-by-status/widget.js +2 -1
- package/dist/modules/dashboards/widgets/dashboard/orders-by-status/widget.js.map +2 -2
- package/dist/modules/dashboards/widgets/dashboard/orders-kpi/widget.js +2 -1
- package/dist/modules/dashboards/widgets/dashboard/orders-kpi/widget.js.map +2 -2
- package/dist/modules/dashboards/widgets/dashboard/pipeline-summary/widget.js +2 -1
- package/dist/modules/dashboards/widgets/dashboard/pipeline-summary/widget.js.map +2 -2
- package/dist/modules/dashboards/widgets/dashboard/revenue-kpi/widget.js +2 -1
- package/dist/modules/dashboards/widgets/dashboard/revenue-kpi/widget.js.map +2 -2
- package/dist/modules/dashboards/widgets/dashboard/revenue-trend/widget.js +2 -1
- package/dist/modules/dashboards/widgets/dashboard/revenue-trend/widget.js.map +2 -2
- package/dist/modules/dashboards/widgets/dashboard/sales-by-region/widget.js +2 -1
- package/dist/modules/dashboards/widgets/dashboard/sales-by-region/widget.js.map +2 -2
- package/dist/modules/dashboards/widgets/dashboard/top-customers/widget.js +2 -1
- package/dist/modules/dashboards/widgets/dashboard/top-customers/widget.js.map +2 -2
- package/dist/modules/dashboards/widgets/dashboard/top-products/widget.js +2 -1
- package/dist/modules/dashboards/widgets/dashboard/top-products/widget.js.map +2 -2
- package/dist/modules/dictionaries/components/DictionaryTable.js +2 -0
- package/dist/modules/dictionaries/components/DictionaryTable.js.map +2 -2
- package/dist/modules/directory/api/get/tenants/lookup.js +70 -0
- package/dist/modules/directory/api/get/tenants/lookup.js.map +7 -0
- package/dist/modules/directory/backend/directory/organizations/page.js +2 -2
- package/dist/modules/directory/backend/directory/organizations/page.js.map +2 -2
- package/dist/modules/directory/backend/directory/tenants/page.js +2 -2
- package/dist/modules/directory/backend/directory/tenants/page.js.map +2 -2
- package/dist/modules/entities/backend/entities/user/[entityId]/records/page.js +2 -2
- package/dist/modules/entities/backend/entities/user/[entityId]/records/page.js.map +2 -2
- package/dist/modules/entities/components/SystemEntitiesTable.js +1 -1
- package/dist/modules/entities/components/SystemEntitiesTable.js.map +2 -2
- package/dist/modules/entities/components/UserEntitiesTable.js +2 -2
- package/dist/modules/entities/components/UserEntitiesTable.js.map +2 -2
- package/dist/modules/feature_toggles/components/FeatureTogglesTable.js +3 -3
- package/dist/modules/feature_toggles/components/FeatureTogglesTable.js.map +2 -2
- package/dist/modules/feature_toggles/components/OverridesTable.js +1 -1
- package/dist/modules/feature_toggles/components/OverridesTable.js.map +2 -2
- package/dist/modules/notifications/acl.js +11 -0
- package/dist/modules/notifications/acl.js.map +7 -0
- package/dist/modules/notifications/api/[id]/action/route.js +74 -0
- package/dist/modules/notifications/api/[id]/action/route.js.map +7 -0
- package/dist/modules/notifications/api/[id]/dismiss/route.js +15 -0
- package/dist/modules/notifications/api/[id]/dismiss/route.js.map +7 -0
- package/dist/modules/notifications/api/[id]/read/route.js +15 -0
- package/dist/modules/notifications/api/[id]/read/route.js.map +7 -0
- package/dist/modules/notifications/api/[id]/restore/route.js +53 -0
- package/dist/modules/notifications/api/[id]/restore/route.js.map +7 -0
- package/dist/modules/notifications/api/batch/route.js +17 -0
- package/dist/modules/notifications/api/batch/route.js.map +7 -0
- package/dist/modules/notifications/api/feature/route.js +17 -0
- package/dist/modules/notifications/api/feature/route.js.map +7 -0
- package/dist/modules/notifications/api/mark-all-read/route.js +35 -0
- package/dist/modules/notifications/api/mark-all-read/route.js.map +7 -0
- package/dist/modules/notifications/api/openapi.js +76 -0
- package/dist/modules/notifications/api/openapi.js.map +7 -0
- package/dist/modules/notifications/api/role/route.js +17 -0
- package/dist/modules/notifications/api/role/route.js.map +7 -0
- package/dist/modules/notifications/api/route.js +85 -0
- package/dist/modules/notifications/api/route.js.map +7 -0
- package/dist/modules/notifications/api/settings/route.js +155 -0
- package/dist/modules/notifications/api/settings/route.js.map +7 -0
- package/dist/modules/notifications/api/unread-count/route.js +38 -0
- package/dist/modules/notifications/api/unread-count/route.js.map +7 -0
- package/dist/modules/notifications/backend/config/notifications/page.js +10 -0
- package/dist/modules/notifications/backend/config/notifications/page.js.map +7 -0
- package/dist/modules/notifications/backend/config/notifications/page.meta.js +24 -0
- package/dist/modules/notifications/backend/config/notifications/page.meta.js.map +7 -0
- package/dist/modules/notifications/cli.js +16 -0
- package/dist/modules/notifications/cli.js.map +7 -0
- package/dist/modules/notifications/data/entities.js +112 -0
- package/dist/modules/notifications/data/entities.js.map +7 -0
- package/dist/modules/notifications/data/validators.js +98 -0
- package/dist/modules/notifications/data/validators.js.map +7 -0
- package/dist/modules/notifications/di.js +13 -0
- package/dist/modules/notifications/di.js.map +7 -0
- package/dist/modules/notifications/emails/NotificationEmail.js +58 -0
- package/dist/modules/notifications/emails/NotificationEmail.js.map +7 -0
- package/dist/modules/notifications/frontend/NotificationInboxPageClient.js +44 -0
- package/dist/modules/notifications/frontend/NotificationInboxPageClient.js.map +7 -0
- package/dist/modules/notifications/frontend/NotificationSettingsPageClient.js +220 -0
- package/dist/modules/notifications/frontend/NotificationSettingsPageClient.js.map +7 -0
- package/dist/modules/notifications/index.js +14 -0
- package/dist/modules/notifications/index.js.map +7 -0
- package/dist/modules/notifications/lib/deliveryConfig.js +107 -0
- package/dist/modules/notifications/lib/deliveryConfig.js.map +7 -0
- package/dist/modules/notifications/lib/deliveryStrategies.js +14 -0
- package/dist/modules/notifications/lib/deliveryStrategies.js.map +7 -0
- package/dist/modules/notifications/lib/events.js +12 -0
- package/dist/modules/notifications/lib/events.js.map +7 -0
- package/dist/modules/notifications/lib/notificationBuilder.js +66 -0
- package/dist/modules/notifications/lib/notificationBuilder.js.map +7 -0
- package/dist/modules/notifications/lib/notificationFactory.js +54 -0
- package/dist/modules/notifications/lib/notificationFactory.js.map +7 -0
- package/dist/modules/notifications/lib/notificationMapper.js +34 -0
- package/dist/modules/notifications/lib/notificationMapper.js.map +7 -0
- package/dist/modules/notifications/lib/notificationRecipients.js +35 -0
- package/dist/modules/notifications/lib/notificationRecipients.js.map +7 -0
- package/dist/modules/notifications/lib/notificationService.js +279 -0
- package/dist/modules/notifications/lib/notificationService.js.map +7 -0
- package/dist/modules/notifications/lib/routeHelpers.js +101 -0
- package/dist/modules/notifications/lib/routeHelpers.js.map +7 -0
- package/dist/modules/notifications/lib/safeHref.js +24 -0
- package/dist/modules/notifications/lib/safeHref.js.map +7 -0
- package/dist/modules/notifications/migrations/Migration20260123000001.js +70 -0
- package/dist/modules/notifications/migrations/Migration20260123000001.js.map +7 -0
- package/dist/modules/notifications/migrations/Migration20260126150000.js +37 -0
- package/dist/modules/notifications/migrations/Migration20260126150000.js.map +7 -0
- package/dist/modules/notifications/migrations/Migration20260129082610.js +13 -0
- package/dist/modules/notifications/migrations/Migration20260129082610.js.map +7 -0
- package/dist/modules/notifications/subscribers/deliver-notification.js +165 -0
- package/dist/modules/notifications/subscribers/deliver-notification.js.map +7 -0
- package/dist/modules/notifications/workers/create-notification.worker.js +70 -0
- package/dist/modules/notifications/workers/create-notification.worker.js.map +7 -0
- package/dist/modules/planner/backend/planner/availability-rulesets/page.js +2 -2
- package/dist/modules/planner/backend/planner/availability-rulesets/page.js.map +2 -2
- package/dist/modules/query_index/cli.js +63 -7
- package/dist/modules/query_index/cli.js.map +2 -2
- package/dist/modules/query_index/components/QueryIndexesTable.js +7 -1
- package/dist/modules/query_index/components/QueryIndexesTable.js.map +2 -2
- package/dist/modules/resources/backend/resources/resource-types/page.js +2 -2
- package/dist/modules/resources/backend/resources/resource-types/page.js.map +2 -2
- package/dist/modules/resources/backend/resources/resources/page.js +2 -2
- package/dist/modules/resources/backend/resources/resources/page.js.map +2 -2
- package/dist/modules/sales/acl.js +0 -1
- package/dist/modules/sales/acl.js.map +2 -2
- package/dist/modules/sales/backend/sales/channels/offers/page.js +2 -0
- package/dist/modules/sales/backend/sales/channels/offers/page.js.map +2 -2
- package/dist/modules/sales/backend/sales/channels/page.js +2 -0
- package/dist/modules/sales/backend/sales/channels/page.js.map +2 -2
- package/dist/modules/sales/backend/sales/documents/[id]/page.js +0 -12
- package/dist/modules/sales/backend/sales/documents/[id]/page.js.map +2 -2
- package/dist/modules/sales/commands/documents.js +53 -62
- package/dist/modules/sales/commands/documents.js.map +2 -2
- package/dist/modules/sales/commands/payments.js +26 -0
- package/dist/modules/sales/commands/payments.js.map +2 -2
- package/dist/modules/sales/components/AdjustmentKindSettings.js +2 -2
- package/dist/modules/sales/components/AdjustmentKindSettings.js.map +2 -2
- package/dist/modules/sales/components/PaymentMethodsSettings.js +2 -2
- package/dist/modules/sales/components/PaymentMethodsSettings.js.map +2 -2
- package/dist/modules/sales/components/ShippingMethodsSettings.js +2 -2
- package/dist/modules/sales/components/ShippingMethodsSettings.js.map +2 -2
- package/dist/modules/sales/components/TaxRatesSettings.js +2 -2
- package/dist/modules/sales/components/TaxRatesSettings.js.map +2 -2
- package/dist/modules/sales/components/channels/SalesChannelOffersPanel.js +2 -0
- package/dist/modules/sales/components/channels/SalesChannelOffersPanel.js.map +2 -2
- package/dist/modules/sales/components/documents/AdjustmentsSection.js +2 -0
- package/dist/modules/sales/components/documents/AdjustmentsSection.js.map +2 -2
- package/dist/modules/sales/components/documents/PaymentsSection.js +2 -1
- package/dist/modules/sales/components/documents/PaymentsSection.js.map +2 -2
- package/dist/modules/sales/components/documents/SalesDocumentsTable.js +2 -0
- package/dist/modules/sales/components/documents/SalesDocumentsTable.js.map +2 -2
- package/dist/modules/sales/lib/dictionaries.js +0 -3
- package/dist/modules/sales/lib/dictionaries.js.map +2 -2
- package/dist/modules/sales/notifications.client.js +51 -0
- package/dist/modules/sales/notifications.client.js.map +7 -0
- package/dist/modules/sales/notifications.js +88 -0
- package/dist/modules/sales/notifications.js.map +7 -0
- package/dist/modules/sales/subscribers/quote-expiring-notification.js +38 -0
- package/dist/modules/sales/subscribers/quote-expiring-notification.js.map +7 -0
- package/dist/modules/sales/widgets/notifications/SalesOrderCreatedRenderer.js +137 -0
- package/dist/modules/sales/widgets/notifications/SalesOrderCreatedRenderer.js.map +7 -0
- package/dist/modules/sales/widgets/notifications/SalesQuoteCreatedRenderer.js +137 -0
- package/dist/modules/sales/widgets/notifications/SalesQuoteCreatedRenderer.js.map +7 -0
- package/dist/modules/sales/widgets/notifications/index.js +7 -0
- package/dist/modules/sales/widgets/notifications/index.js.map +7 -0
- package/dist/modules/sales/widgets/notifications/useSalesDocumentTotals.js +60 -0
- package/dist/modules/sales/widgets/notifications/useSalesDocumentTotals.js.map +7 -0
- package/dist/modules/staff/backend/staff/team-members/page.js +1 -1
- package/dist/modules/staff/backend/staff/team-members/page.js.map +2 -2
- package/dist/modules/staff/backend/staff/team-roles/page.js +2 -2
- package/dist/modules/staff/backend/staff/team-roles/page.js.map +2 -2
- package/dist/modules/staff/backend/staff/teams/[id]/edit/page.js +2 -2
- package/dist/modules/staff/backend/staff/teams/[id]/edit/page.js.map +2 -2
- package/dist/modules/staff/backend/staff/teams/page.js +2 -2
- package/dist/modules/staff/backend/staff/teams/page.js.map +2 -2
- package/dist/modules/staff/commands/leave-requests.js +79 -0
- package/dist/modules/staff/commands/leave-requests.js.map +2 -2
- package/dist/modules/staff/notifications.js +75 -0
- package/dist/modules/staff/notifications.js.map +7 -0
- package/dist/modules/workflows/acl.js +0 -2
- package/dist/modules/workflows/acl.js.map +2 -2
- package/dist/modules/workflows/api/instances/route.js +6 -18
- package/dist/modules/workflows/api/instances/route.js.map +2 -2
- package/dist/modules/workflows/api/tasks/route.js +1 -6
- package/dist/modules/workflows/api/tasks/route.js.map +2 -2
- package/dist/modules/workflows/backend/definitions/[id]/page.js +1 -9
- package/dist/modules/workflows/backend/definitions/[id]/page.js.map +2 -2
- package/dist/modules/workflows/backend/definitions/[id]/page.meta.js +1 -1
- package/dist/modules/workflows/backend/definitions/[id]/page.meta.js.map +2 -2
- package/dist/modules/workflows/backend/definitions/create/page.js +15 -24
- package/dist/modules/workflows/backend/definitions/create/page.js.map +2 -2
- package/dist/modules/workflows/backend/definitions/create/page.meta.js +1 -1
- package/dist/modules/workflows/backend/definitions/create/page.meta.js.map +2 -2
- package/dist/modules/workflows/backend/definitions/page.js +5 -0
- package/dist/modules/workflows/backend/definitions/page.js.map +2 -2
- package/dist/modules/workflows/backend/definitions/visual-editor/page.js +132 -150
- package/dist/modules/workflows/backend/definitions/visual-editor/page.js.map +2 -2
- package/dist/modules/workflows/backend/definitions/visual-editor/page.meta.js +1 -1
- package/dist/modules/workflows/backend/definitions/visual-editor/page.meta.js.map +2 -2
- package/dist/modules/workflows/backend/events/[id]/page.js +1 -1
- package/dist/modules/workflows/backend/events/[id]/page.js.map +2 -2
- package/dist/modules/workflows/backend/events/[id]/page.meta.js +2 -2
- package/dist/modules/workflows/backend/events/[id]/page.meta.js.map +2 -2
- package/dist/modules/workflows/backend/instances/[id]/page.meta.js +2 -2
- package/dist/modules/workflows/backend/instances/[id]/page.meta.js.map +2 -2
- package/dist/modules/workflows/backend/instances/page.js +3 -0
- package/dist/modules/workflows/backend/instances/page.js.map +2 -2
- package/dist/modules/workflows/backend/tasks/[id]/page.js +1 -1
- package/dist/modules/workflows/backend/tasks/[id]/page.js.map +2 -2
- package/dist/modules/workflows/backend/tasks/[id]/page.meta.js +2 -2
- package/dist/modules/workflows/backend/tasks/[id]/page.meta.js.map +2 -2
- package/dist/modules/workflows/backend/tasks/page.js +9 -5
- package/dist/modules/workflows/backend/tasks/page.js.map +2 -2
- package/dist/modules/workflows/cli.js +15 -93
- package/dist/modules/workflows/cli.js.map +3 -3
- package/dist/modules/workflows/data/entities.js +1 -64
- package/dist/modules/workflows/data/entities.js.map +2 -2
- package/dist/modules/workflows/data/validators.js +0 -115
- package/dist/modules/workflows/data/validators.js.map +2 -2
- package/dist/modules/workflows/examples/checkout-demo-definition.json +5 -1
- package/dist/modules/workflows/lib/activity-executor.js +13 -75
- package/dist/modules/workflows/lib/activity-executor.js.map +2 -2
- package/dist/modules/workflows/lib/graph-utils.js +2 -71
- package/dist/modules/workflows/lib/graph-utils.js.map +2 -2
- package/dist/modules/workflows/lib/seeds.js +5 -22
- package/dist/modules/workflows/lib/seeds.js.map +2 -2
- package/dist/modules/workflows/lib/start-validator.js +23 -33
- package/dist/modules/workflows/lib/start-validator.js.map +2 -2
- package/dist/modules/workflows/lib/transition-handler.js +57 -161
- package/dist/modules/workflows/lib/transition-handler.js.map +3 -3
- package/dist/modules/workflows/notifications.js +28 -0
- package/dist/modules/workflows/notifications.js.map +7 -0
- package/dist/modules/workflows/subscribers/task-assigned-notification.js +38 -0
- package/dist/modules/workflows/subscribers/task-assigned-notification.js.map +7 -0
- package/generated/entities/notification/index.ts +27 -0
- package/generated/entities.ids.generated.ts +5 -2
- package/generated/entity-fields-registry.ts +2 -2
- package/package.json +2 -2
- package/src/modules/api_docs/frontend/docs/api/page.tsx +3 -2
- package/src/modules/api_keys/backend/api-keys/page.tsx +1 -1
- package/src/modules/attachments/components/AttachmentLibrary.tsx +4 -0
- package/src/modules/attachments/components/AttachmentPartitionSettings.tsx +2 -0
- package/src/modules/auth/README.md +1 -1
- package/src/modules/auth/__tests__/cli-setup-acl.test.ts +1 -1
- package/src/modules/auth/api/__tests__/login.test.ts +2 -0
- package/src/modules/auth/api/admin/nav.ts +10 -6
- package/src/modules/auth/api/login.ts +26 -7
- package/src/modules/auth/api/profile/route.ts +163 -0
- package/src/modules/auth/api/reset/confirm.ts +25 -2
- package/src/modules/auth/api/reset.ts +23 -0
- package/src/modules/auth/api/sidebar/preferences/route.ts +21 -12
- package/src/modules/auth/api/users/route.ts +5 -2
- package/src/modules/auth/backend/auth/profile/page.meta.ts +9 -0
- package/src/modules/auth/backend/auth/profile/page.tsx +174 -0
- package/src/modules/auth/backend/roles/[id]/edit/page.tsx +4 -1
- package/src/modules/auth/backend/roles/page.tsx +3 -3
- package/src/modules/auth/backend/users/[id]/edit/page.tsx +22 -3
- package/src/modules/auth/backend/users/create/page.tsx +19 -2
- package/src/modules/auth/backend/users/page.tsx +3 -3
- package/src/modules/auth/cli.ts +38 -11
- package/src/modules/auth/commands/users.ts +73 -2
- package/src/modules/auth/data/validators.ts +6 -2
- package/src/modules/auth/frontend/login.tsx +134 -5
- package/src/modules/auth/frontend/reset/[token]/page.tsx +24 -11
- package/src/modules/auth/i18n/de.json +48 -1
- package/src/modules/auth/i18n/en.json +48 -1
- package/src/modules/auth/i18n/es.json +48 -1
- package/src/modules/auth/i18n/pl.json +48 -1
- package/src/modules/auth/lib/setup-app.ts +58 -9
- package/src/modules/auth/notifications.ts +109 -0
- package/src/modules/auth/services/authService.ts +27 -4
- package/src/modules/business_rules/api/execute/route.ts +8 -1
- package/src/modules/business_rules/backend/rules/page.tsx +4 -0
- package/src/modules/business_rules/backend/sets/page.tsx +3 -0
- package/src/modules/business_rules/cli.ts +2 -1
- package/src/modules/business_rules/data/validators.ts +0 -40
- package/src/modules/business_rules/i18n/en.json +3 -1
- package/src/modules/business_rules/index.ts +0 -25
- package/src/modules/business_rules/lib/__tests__/rule-engine.test.ts +51 -0
- package/src/modules/business_rules/lib/rule-engine.ts +51 -277
- package/src/modules/business_rules/notifications.ts +25 -0
- package/src/modules/business_rules/subscribers/rule-execution-failed-notification.ts +50 -0
- package/src/modules/catalog/components/PriceKindSettings.tsx +2 -0
- package/src/modules/catalog/components/categories/CategoriesDataTable.tsx +2 -2
- package/src/modules/catalog/components/products/ProductsDataTable.tsx +2 -0
- package/src/modules/catalog/i18n/en.json +3 -1
- package/src/modules/catalog/notifications.ts +25 -0
- package/src/modules/catalog/subscribers/low-stock-notification.ts +52 -0
- package/src/modules/configs/cli.ts +6 -0
- package/src/modules/configs/components/CachePanel.tsx +4 -4
- package/src/modules/configs/i18n/en.json +12 -2
- package/src/modules/configs/i18n/pl.json +12 -2
- package/src/modules/configs/lib/system-status.ts +48 -1
- package/src/modules/configs/lib/system-status.types.ts +1 -0
- package/src/modules/configs/lib/upgrade-actions.ts +18 -0
- package/src/modules/currencies/backend/currencies/page.tsx +3 -0
- package/src/modules/currencies/backend/exchange-rates/page.tsx +2 -0
- package/src/modules/customers/backend/customers/companies/page.tsx +3 -0
- package/src/modules/customers/backend/customers/deals/page.tsx +3 -0
- package/src/modules/customers/backend/customers/people/page.tsx +3 -0
- package/src/modules/customers/commands/deals.ts +39 -0
- package/src/modules/customers/components/CustomerTodosTable.tsx +1 -0
- package/src/modules/customers/i18n/en.json +5 -1
- package/src/modules/customers/notifications.ts +44 -0
- package/src/modules/customers/widgets/dashboard/customer-todos/widget.ts +2 -2
- package/src/modules/customers/widgets/dashboard/new-customers/widget.ts +2 -2
- package/src/modules/customers/widgets/dashboard/new-deals/widget.ts +2 -2
- package/src/modules/customers/widgets/dashboard/next-interactions/widget.ts +2 -2
- package/src/modules/dashboards/cli.ts +55 -5
- package/src/modules/dashboards/components/WidgetVisibilityEditor.tsx +22 -11
- package/src/modules/dashboards/lib/role-widgets.ts +80 -0
- package/src/modules/dashboards/services/widgetDataService.ts +164 -4
- package/src/modules/dashboards/widgets/dashboard/aov-kpi/widget.ts +2 -2
- package/src/modules/dashboards/widgets/dashboard/new-customers-kpi/widget.ts +2 -2
- package/src/modules/dashboards/widgets/dashboard/orders-by-status/widget.ts +2 -2
- package/src/modules/dashboards/widgets/dashboard/orders-kpi/widget.ts +2 -2
- package/src/modules/dashboards/widgets/dashboard/pipeline-summary/widget.ts +2 -2
- package/src/modules/dashboards/widgets/dashboard/revenue-kpi/widget.ts +2 -2
- package/src/modules/dashboards/widgets/dashboard/revenue-trend/widget.ts +2 -2
- package/src/modules/dashboards/widgets/dashboard/sales-by-region/widget.ts +2 -2
- package/src/modules/dashboards/widgets/dashboard/top-customers/widget.ts +2 -2
- package/src/modules/dashboards/widgets/dashboard/top-products/widget.ts +2 -2
- package/src/modules/dictionaries/components/DictionaryTable.tsx +2 -0
- package/src/modules/directory/api/get/tenants/lookup.ts +75 -0
- package/src/modules/directory/backend/directory/organizations/page.tsx +2 -2
- package/src/modules/directory/backend/directory/tenants/page.tsx +2 -2
- package/src/modules/entities/backend/entities/user/[entityId]/records/page.tsx +2 -2
- package/src/modules/entities/components/SystemEntitiesTable.tsx +1 -1
- package/src/modules/entities/components/UserEntitiesTable.tsx +2 -2
- package/src/modules/feature_toggles/components/FeatureTogglesTable.tsx +3 -4
- package/src/modules/feature_toggles/components/OverridesTable.tsx +1 -1
- package/src/modules/notifications/__tests__/deliver-notification.test.ts +195 -0
- package/src/modules/notifications/__tests__/deliveryStrategies.test.ts +19 -0
- package/src/modules/notifications/__tests__/notificationService.test.ts +208 -0
- package/src/modules/notifications/acl.ts +7 -0
- package/src/modules/notifications/api/[id]/action/route.ts +75 -0
- package/src/modules/notifications/api/[id]/dismiss/route.ts +12 -0
- package/src/modules/notifications/api/[id]/read/route.ts +12 -0
- package/src/modules/notifications/api/[id]/restore/route.ts +53 -0
- package/src/modules/notifications/api/batch/route.ts +14 -0
- package/src/modules/notifications/api/feature/route.ts +14 -0
- package/src/modules/notifications/api/mark-all-read/route.ts +34 -0
- package/src/modules/notifications/api/openapi.ts +76 -0
- package/src/modules/notifications/api/role/route.ts +14 -0
- package/src/modules/notifications/api/route.ts +92 -0
- package/src/modules/notifications/api/settings/route.ts +157 -0
- package/src/modules/notifications/api/unread-count/route.ts +38 -0
- package/src/modules/notifications/backend/config/notifications/page.meta.ts +22 -0
- package/src/modules/notifications/backend/config/notifications/page.tsx +12 -0
- package/src/modules/notifications/cli.ts +18 -0
- package/src/modules/notifications/data/entities.ts +99 -0
- package/src/modules/notifications/data/validators.ts +115 -0
- package/src/modules/notifications/di.ts +11 -0
- package/src/modules/notifications/emails/NotificationEmail.tsx +98 -0
- package/src/modules/notifications/frontend/NotificationInboxPageClient.tsx +42 -0
- package/src/modules/notifications/frontend/NotificationSettingsPageClient.tsx +233 -0
- package/src/modules/notifications/i18n/de.json +50 -0
- package/src/modules/notifications/i18n/en.json +50 -0
- package/src/modules/notifications/i18n/es.json +50 -0
- package/src/modules/notifications/i18n/pl.json +50 -0
- package/src/modules/notifications/index.ts +12 -0
- package/src/modules/notifications/lib/deliveryConfig.ts +153 -0
- package/src/modules/notifications/lib/deliveryStrategies.ts +50 -0
- package/src/modules/notifications/lib/events.ts +48 -0
- package/src/modules/notifications/lib/notificationBuilder.ts +121 -0
- package/src/modules/notifications/lib/notificationFactory.ts +76 -0
- package/src/modules/notifications/lib/notificationMapper.ts +33 -0
- package/src/modules/notifications/lib/notificationRecipients.ts +83 -0
- package/src/modules/notifications/lib/notificationService.ts +414 -0
- package/src/modules/notifications/lib/routeHelpers.ts +151 -0
- package/src/modules/notifications/lib/safeHref.ts +29 -0
- package/src/modules/notifications/migrations/.snapshot-open-mercato.json +336 -0
- package/src/modules/notifications/migrations/Migration20260123000001.ts +73 -0
- package/src/modules/notifications/migrations/Migration20260126150000.ts +39 -0
- package/src/modules/notifications/migrations/Migration20260129082610.ts +13 -0
- package/src/modules/notifications/subscribers/deliver-notification.ts +204 -0
- package/src/modules/notifications/workers/create-notification.worker.ts +122 -0
- package/src/modules/planner/backend/planner/availability-rulesets/page.tsx +2 -2
- package/src/modules/query_index/cli.ts +82 -13
- package/src/modules/query_index/components/QueryIndexesTable.tsx +8 -2
- package/src/modules/resources/backend/resources/resource-types/page.tsx +2 -2
- package/src/modules/resources/backend/resources/resources/page.tsx +2 -2
- package/src/modules/sales/acl.ts +0 -1
- package/src/modules/sales/backend/sales/channels/offers/page.tsx +2 -0
- package/src/modules/sales/backend/sales/channels/page.tsx +2 -0
- package/src/modules/sales/backend/sales/documents/[id]/page.tsx +0 -16
- package/src/modules/sales/commands/documents.ts +62 -70
- package/src/modules/sales/commands/payments.ts +33 -0
- package/src/modules/sales/components/AdjustmentKindSettings.tsx +2 -2
- package/src/modules/sales/components/PaymentMethodsSettings.tsx +2 -2
- package/src/modules/sales/components/ShippingMethodsSettings.tsx +2 -2
- package/src/modules/sales/components/TaxRatesSettings.tsx +2 -2
- package/src/modules/sales/components/channels/SalesChannelOffersPanel.tsx +2 -0
- package/src/modules/sales/components/documents/AdjustmentsSection.tsx +2 -0
- package/src/modules/sales/components/documents/PaymentsSection.tsx +2 -1
- package/src/modules/sales/components/documents/SalesDocumentsTable.tsx +2 -0
- package/src/modules/sales/i18n/de.json +20 -0
- package/src/modules/sales/i18n/en.json +25 -1
- package/src/modules/sales/i18n/es.json +20 -0
- package/src/modules/sales/i18n/pl.json +20 -0
- package/src/modules/sales/lib/dictionaries.ts +0 -3
- package/src/modules/sales/notifications.client.ts +65 -0
- package/src/modules/sales/notifications.ts +82 -0
- package/src/modules/sales/subscribers/quote-expiring-notification.ts +53 -0
- package/src/modules/sales/widgets/notifications/SalesOrderCreatedRenderer.tsx +156 -0
- package/src/modules/sales/widgets/notifications/SalesQuoteCreatedRenderer.tsx +156 -0
- package/src/modules/sales/widgets/notifications/index.ts +2 -0
- package/src/modules/sales/widgets/notifications/useSalesDocumentTotals.ts +81 -0
- package/src/modules/staff/backend/staff/team-members/page.tsx +1 -1
- package/src/modules/staff/backend/staff/team-roles/page.tsx +2 -2
- package/src/modules/staff/backend/staff/teams/[id]/edit/page.tsx +2 -2
- package/src/modules/staff/backend/staff/teams/page.tsx +2 -2
- package/src/modules/staff/commands/leave-requests.ts +94 -0
- package/src/modules/staff/i18n/de.json +4 -0
- package/src/modules/staff/i18n/en.json +9 -1
- package/src/modules/staff/i18n/es.json +4 -0
- package/src/modules/staff/i18n/pl.json +4 -0
- package/src/modules/staff/notifications.ts +71 -0
- package/src/modules/workflows/acl.ts +0 -2
- package/src/modules/workflows/api/__tests__/instances.route.test.ts +2 -5
- package/src/modules/workflows/api/instances/route.ts +7 -21
- package/src/modules/workflows/api/tasks/route.ts +1 -7
- package/src/modules/workflows/backend/definitions/[id]/page.meta.ts +1 -1
- package/src/modules/workflows/backend/definitions/[id]/page.tsx +0 -9
- package/src/modules/workflows/backend/definitions/create/page.meta.ts +1 -1
- package/src/modules/workflows/backend/definitions/create/page.tsx +0 -9
- package/src/modules/workflows/backend/definitions/page.tsx +5 -0
- package/src/modules/workflows/backend/definitions/visual-editor/page.meta.ts +1 -1
- package/src/modules/workflows/backend/definitions/visual-editor/page.tsx +3 -21
- package/src/modules/workflows/backend/events/[id]/page.meta.ts +2 -2
- package/src/modules/workflows/backend/events/[id]/page.tsx +1 -1
- package/src/modules/workflows/backend/instances/[id]/page.meta.ts +2 -2
- package/src/modules/workflows/backend/instances/page.tsx +4 -1
- package/src/modules/workflows/backend/tasks/[id]/page.meta.ts +2 -2
- package/src/modules/workflows/backend/tasks/[id]/page.tsx +1 -1
- package/src/modules/workflows/backend/tasks/page.tsx +10 -6
- package/src/modules/workflows/cli.ts +12 -123
- package/src/modules/workflows/data/entities.ts +0 -124
- package/src/modules/workflows/data/validators.ts +0 -138
- package/src/modules/workflows/examples/checkout-demo-definition.json +5 -1
- package/src/modules/workflows/i18n/en.json +3 -72
- package/src/modules/workflows/lib/__tests__/activity-executor.test.ts +36 -43
- package/src/modules/workflows/lib/__tests__/transition-handler.test.ts +90 -170
- package/src/modules/workflows/lib/activity-executor.ts +16 -129
- package/src/modules/workflows/lib/graph-utils.ts +2 -117
- package/src/modules/workflows/lib/seeds.ts +8 -34
- package/src/modules/workflows/lib/start-validator.ts +28 -38
- package/src/modules/workflows/lib/transition-handler.ts +71 -212
- package/src/modules/workflows/notifications.ts +25 -0
- package/src/modules/workflows/subscribers/task-assigned-notification.ts +53 -0
- package/dist/generated/entities/workflow_event_trigger/index.js +0 -33
- package/dist/generated/entities/workflow_event_trigger/index.js.map +0 -7
- package/dist/modules/auth/events.js +0 -30
- package/dist/modules/auth/events.js.map +0 -7
- package/dist/modules/business_rules/api/execute/[ruleId]/route.js +0 -145
- package/dist/modules/business_rules/api/execute/[ruleId]/route.js.map +0 -7
- package/dist/modules/catalog/events.js +0 -34
- package/dist/modules/catalog/events.js.map +0 -7
- package/dist/modules/customers/events.js +0 -49
- package/dist/modules/customers/events.js.map +0 -7
- package/dist/modules/directory/events.js +0 -23
- package/dist/modules/directory/events.js.map +0 -7
- package/dist/modules/sales/events.js +0 -63
- package/dist/modules/sales/events.js.map +0 -7
- package/dist/modules/sales/lib/frontend/documentDataEvents.js +0 -25
- package/dist/modules/sales/lib/frontend/documentDataEvents.js.map +0 -7
- package/dist/modules/workflows/components/DefinitionTriggersEditor.js +0 -481
- package/dist/modules/workflows/components/DefinitionTriggersEditor.js.map +0 -7
- package/dist/modules/workflows/components/EventTriggersEditor.js +0 -553
- package/dist/modules/workflows/components/EventTriggersEditor.js.map +0 -7
- package/dist/modules/workflows/events.js +0 -38
- package/dist/modules/workflows/events.js.map +0 -7
- package/dist/modules/workflows/examples/order-approval-definition.json +0 -257
- package/dist/modules/workflows/examples/order-approval-guard-rules.json +0 -32
- package/dist/modules/workflows/lib/event-trigger-service.js +0 -308
- package/dist/modules/workflows/lib/event-trigger-service.js.map +0 -7
- package/dist/modules/workflows/migrations/Migration20260123143500.js +0 -36
- package/dist/modules/workflows/migrations/Migration20260123143500.js.map +0 -7
- package/dist/modules/workflows/subscribers/event-trigger.js +0 -78
- package/dist/modules/workflows/subscribers/event-trigger.js.map +0 -7
- package/dist/modules/workflows/widgets/injection/order-approval/widget.client.js +0 -323
- package/dist/modules/workflows/widgets/injection/order-approval/widget.client.js.map +0 -7
- package/dist/modules/workflows/widgets/injection/order-approval/widget.js +0 -17
- package/dist/modules/workflows/widgets/injection/order-approval/widget.js.map +0 -7
- package/dist/modules/workflows/widgets/injection-table.js +0 -19
- package/dist/modules/workflows/widgets/injection-table.js.map +0 -7
- package/generated/entities/workflow_event_trigger/index.ts +0 -15
- package/src/modules/auth/events.ts +0 -39
- package/src/modules/business_rules/api/execute/[ruleId]/route.ts +0 -163
- package/src/modules/catalog/events.ts +0 -45
- package/src/modules/customers/events.ts +0 -63
- package/src/modules/directory/events.ts +0 -31
- package/src/modules/sales/events.ts +0 -82
- package/src/modules/sales/lib/frontend/documentDataEvents.ts +0 -28
- package/src/modules/workflows/components/DefinitionTriggersEditor.tsx +0 -581
- package/src/modules/workflows/components/EventTriggersEditor.tsx +0 -664
- package/src/modules/workflows/events.ts +0 -49
- package/src/modules/workflows/examples/order-approval-definition.json +0 -257
- package/src/modules/workflows/examples/order-approval-guard-rules.json +0 -32
- package/src/modules/workflows/lib/event-trigger-service.ts +0 -557
- package/src/modules/workflows/migrations/Migration20260123143500.ts +0 -38
- package/src/modules/workflows/subscribers/event-trigger.ts +0 -109
- package/src/modules/workflows/widgets/injection/order-approval/widget.client.tsx +0 -446
- package/src/modules/workflows/widgets/injection/order-approval/widget.ts +0 -16
- package/src/modules/workflows/widgets/injection-table.ts +0 -21
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../src/modules/notifications/migrations/Migration20260123000001.ts"],
|
|
4
|
+
"sourcesContent": ["import { Migration } from '@mikro-orm/migrations'\n\nexport class Migration20260123000001 extends Migration {\n async up(): Promise<void> {\n this.addSql(`\n CREATE TABLE notifications (\n id UUID PRIMARY KEY DEFAULT gen_random_uuid(),\n \n recipient_user_id UUID NOT NULL,\n \n type TEXT NOT NULL,\n title TEXT NOT NULL,\n body TEXT,\n icon TEXT,\n severity TEXT NOT NULL DEFAULT 'info',\n \n status TEXT NOT NULL DEFAULT 'unread',\n \n action_data JSONB,\n action_result JSONB,\n action_taken TEXT,\n \n source_module TEXT,\n source_entity_type TEXT,\n source_entity_id UUID,\n link_href TEXT,\n \n group_key TEXT,\n \n created_at TIMESTAMPTZ NOT NULL DEFAULT now(),\n read_at TIMESTAMPTZ,\n actioned_at TIMESTAMPTZ,\n dismissed_at TIMESTAMPTZ,\n expires_at TIMESTAMPTZ,\n \n tenant_id UUID NOT NULL,\n organization_id UUID\n );\n `)\n\n this.addSql(`\n CREATE INDEX notifications_recipient_status_idx \n ON notifications(recipient_user_id, status, created_at DESC);\n `)\n\n this.addSql(`\n CREATE INDEX notifications_source_idx \n ON notifications(source_entity_type, source_entity_id) \n WHERE source_entity_id IS NOT NULL;\n `)\n\n this.addSql(`\n CREATE INDEX notifications_tenant_idx \n ON notifications(tenant_id, organization_id);\n `)\n\n this.addSql(`\n CREATE INDEX notifications_expires_idx \n ON notifications(expires_at) \n WHERE expires_at IS NOT NULL AND status NOT IN ('actioned', 'dismissed');\n `)\n\n this.addSql(`\n CREATE INDEX notifications_group_idx \n ON notifications(group_key, recipient_user_id) \n WHERE group_key IS NOT NULL;\n `)\n }\n\n async down(): Promise<void> {\n this.addSql('DROP TABLE IF EXISTS notifications CASCADE;')\n }\n}\n"],
|
|
5
|
+
"mappings": "AAAA,SAAS,iBAAiB;AAEnB,MAAM,gCAAgC,UAAU;AAAA,EACrD,MAAM,KAAoB;AACxB,SAAK,OAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,KAkCX;AAED,SAAK,OAAO;AAAA;AAAA;AAAA,KAGX;AAED,SAAK,OAAO;AAAA;AAAA;AAAA;AAAA,KAIX;AAED,SAAK,OAAO;AAAA;AAAA;AAAA,KAGX;AAED,SAAK,OAAO;AAAA;AAAA;AAAA;AAAA,KAIX;AAED,SAAK,OAAO;AAAA;AAAA;AAAA;AAAA,KAIX;AAAA,EACH;AAAA,EAEA,MAAM,OAAsB;AAC1B,SAAK,OAAO,6CAA6C;AAAA,EAC3D;AACF;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { Migration } from "@mikro-orm/migrations";
|
|
2
|
+
class Migration20260126150000 extends Migration {
|
|
3
|
+
async up() {
|
|
4
|
+
this.addSql(`
|
|
5
|
+
alter table "notifications"
|
|
6
|
+
add column if not exists "title_key" text,
|
|
7
|
+
add column if not exists "body_key" text,
|
|
8
|
+
add column if not exists "title_variables" jsonb,
|
|
9
|
+
add column if not exists "body_variables" jsonb;
|
|
10
|
+
`);
|
|
11
|
+
this.addSql(`
|
|
12
|
+
comment on column "notifications"."title_key" is 'i18n key for notification title';
|
|
13
|
+
`);
|
|
14
|
+
this.addSql(`
|
|
15
|
+
comment on column "notifications"."body_key" is 'i18n key for notification body';
|
|
16
|
+
`);
|
|
17
|
+
this.addSql(`
|
|
18
|
+
comment on column "notifications"."title_variables" is 'Variables for i18n interpolation in title';
|
|
19
|
+
`);
|
|
20
|
+
this.addSql(`
|
|
21
|
+
comment on column "notifications"."body_variables" is 'Variables for i18n interpolation in body';
|
|
22
|
+
`);
|
|
23
|
+
}
|
|
24
|
+
async down() {
|
|
25
|
+
this.addSql(`
|
|
26
|
+
alter table "notifications"
|
|
27
|
+
drop column if exists "title_key",
|
|
28
|
+
drop column if exists "body_key",
|
|
29
|
+
drop column if exists "title_variables",
|
|
30
|
+
drop column if exists "body_variables";
|
|
31
|
+
`);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
export {
|
|
35
|
+
Migration20260126150000
|
|
36
|
+
};
|
|
37
|
+
//# sourceMappingURL=Migration20260126150000.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../src/modules/notifications/migrations/Migration20260126150000.ts"],
|
|
4
|
+
"sourcesContent": ["import { Migration } from '@mikro-orm/migrations'\n\nexport class Migration20260126150000 extends Migration {\n async up(): Promise<void> {\n // Add i18n support fields to notifications table\n this.addSql(`\n alter table \"notifications\"\n add column if not exists \"title_key\" text,\n add column if not exists \"body_key\" text,\n add column if not exists \"title_variables\" jsonb,\n add column if not exists \"body_variables\" jsonb;\n `)\n\n // Add comments for clarity\n this.addSql(`\n comment on column \"notifications\".\"title_key\" is 'i18n key for notification title';\n `)\n this.addSql(`\n comment on column \"notifications\".\"body_key\" is 'i18n key for notification body';\n `)\n this.addSql(`\n comment on column \"notifications\".\"title_variables\" is 'Variables for i18n interpolation in title';\n `)\n this.addSql(`\n comment on column \"notifications\".\"body_variables\" is 'Variables for i18n interpolation in body';\n `)\n }\n\n async down(): Promise<void> {\n // Remove i18n support fields\n this.addSql(`\n alter table \"notifications\"\n drop column if exists \"title_key\",\n drop column if exists \"body_key\",\n drop column if exists \"title_variables\",\n drop column if exists \"body_variables\";\n `)\n }\n}\n"],
|
|
5
|
+
"mappings": "AAAA,SAAS,iBAAiB;AAEnB,MAAM,gCAAgC,UAAU;AAAA,EACrD,MAAM,KAAoB;AAExB,SAAK,OAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,KAMX;AAGD,SAAK,OAAO;AAAA;AAAA,KAEX;AACD,SAAK,OAAO;AAAA;AAAA,KAEX;AACD,SAAK,OAAO;AAAA;AAAA,KAEX;AACD,SAAK,OAAO;AAAA;AAAA,KAEX;AAAA,EACH;AAAA,EAEA,MAAM,OAAsB;AAE1B,SAAK,OAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,KAMX;AAAA,EACH;AACF;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { Migration } from "@mikro-orm/migrations";
|
|
2
|
+
class Migration20260129082610 extends Migration {
|
|
3
|
+
async up() {
|
|
4
|
+
this.addSql(`alter table "notifications" add column if not exists "title_key" text null, add column if not exists "body_key" text null, add column if not exists "title_variables" jsonb null, add column if not exists "body_variables" jsonb null;`);
|
|
5
|
+
}
|
|
6
|
+
async down() {
|
|
7
|
+
this.addSql(`alter table "notifications" drop column if exists "title_key", drop column if exists "body_key", drop column if exists "title_variables", drop column if exists "body_variables";`);
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
export {
|
|
11
|
+
Migration20260129082610
|
|
12
|
+
};
|
|
13
|
+
//# sourceMappingURL=Migration20260129082610.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../src/modules/notifications/migrations/Migration20260129082610.ts"],
|
|
4
|
+
"sourcesContent": ["import { Migration } from '@mikro-orm/migrations';\n\nexport class Migration20260129082610 extends Migration {\n\n override async up(): Promise<void> {\n this.addSql(`alter table \"notifications\" add column if not exists \"title_key\" text null, add column if not exists \"body_key\" text null, add column if not exists \"title_variables\" jsonb null, add column if not exists \"body_variables\" jsonb null;`);\n }\n\n override async down(): Promise<void> {\n this.addSql(`alter table \"notifications\" drop column if exists \"title_key\", drop column if exists \"body_key\", drop column if exists \"title_variables\", drop column if exists \"body_variables\";`);\n }\n\n}\n"],
|
|
5
|
+
"mappings": "AAAA,SAAS,iBAAiB;AAEnB,MAAM,gCAAgC,UAAU;AAAA,EAErD,MAAe,KAAoB;AACjC,SAAK,OAAO,yOAAyO;AAAA,EACvP;AAAA,EAEA,MAAe,OAAsB;AACnC,SAAK,OAAO,mLAAmL;AAAA,EACjM;AAEF;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
import { Notification } from "../data/entities.js";
|
|
2
|
+
import { NOTIFICATION_EVENTS } from "../lib/events.js";
|
|
3
|
+
import { DEFAULT_NOTIFICATION_DELIVERY_CONFIG, resolveNotificationDeliveryConfig, resolveNotificationPanelUrl } from "../lib/deliveryConfig.js";
|
|
4
|
+
import { getNotificationDeliveryStrategies } from "../lib/deliveryStrategies.js";
|
|
5
|
+
import { sendEmail } from "@open-mercato/shared/lib/email/send";
|
|
6
|
+
import NotificationEmail from "../emails/NotificationEmail.js";
|
|
7
|
+
import { loadDictionary } from "@open-mercato/shared/lib/i18n/server";
|
|
8
|
+
import { createFallbackTranslator } from "@open-mercato/shared/lib/i18n/translate";
|
|
9
|
+
import { defaultLocale } from "@open-mercato/shared/lib/i18n/config";
|
|
10
|
+
import { findOneWithDecryption } from "@open-mercato/shared/lib/encryption/find";
|
|
11
|
+
import { User } from "../../auth/data/entities.js";
|
|
12
|
+
const metadata = {
|
|
13
|
+
event: NOTIFICATION_EVENTS.CREATED,
|
|
14
|
+
persistent: true,
|
|
15
|
+
id: "notifications:deliver"
|
|
16
|
+
};
|
|
17
|
+
const DEBUG = process.env.NOTIFICATIONS_DEBUG === "true";
|
|
18
|
+
function debug(...args) {
|
|
19
|
+
if (DEBUG) {
|
|
20
|
+
console.log("[notifications]", ...args);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
const buildPanelLink = (panelUrl, notificationId) => {
|
|
24
|
+
if (panelUrl.startsWith("http://") || panelUrl.startsWith("https://")) {
|
|
25
|
+
const url = new URL(panelUrl);
|
|
26
|
+
url.searchParams.set("notificationId", notificationId);
|
|
27
|
+
return url.toString();
|
|
28
|
+
}
|
|
29
|
+
const separator = panelUrl.includes("?") ? "&" : "?";
|
|
30
|
+
return `${panelUrl}${separator}notificationId=${encodeURIComponent(notificationId)}`;
|
|
31
|
+
};
|
|
32
|
+
const resolveNotificationCopy = async (notification) => {
|
|
33
|
+
const dict = await loadDictionary(defaultLocale);
|
|
34
|
+
const t = createFallbackTranslator(dict);
|
|
35
|
+
const title = notification.titleKey ? t(notification.titleKey, notification.title ?? notification.titleKey, notification.titleVariables ?? void 0) : notification.title;
|
|
36
|
+
const body = notification.bodyKey ? t(notification.bodyKey, notification.body ?? notification.bodyKey ?? "", notification.bodyVariables ?? void 0) : notification.body ?? null;
|
|
37
|
+
return { title, body, t };
|
|
38
|
+
};
|
|
39
|
+
const resolveRecipient = async (em, notification, encryptionService) => {
|
|
40
|
+
const where = {
|
|
41
|
+
id: notification.recipientUserId,
|
|
42
|
+
tenantId: notification.tenantId,
|
|
43
|
+
deletedAt: null
|
|
44
|
+
};
|
|
45
|
+
if (notification.organizationId) {
|
|
46
|
+
where.organizationId = notification.organizationId;
|
|
47
|
+
}
|
|
48
|
+
const record = await findOneWithDecryption(
|
|
49
|
+
em,
|
|
50
|
+
User,
|
|
51
|
+
where,
|
|
52
|
+
void 0,
|
|
53
|
+
{
|
|
54
|
+
tenantId: notification.tenantId,
|
|
55
|
+
organizationId: notification.organizationId ?? null,
|
|
56
|
+
encryptionService: encryptionService ?? null
|
|
57
|
+
}
|
|
58
|
+
);
|
|
59
|
+
if (!record) return null;
|
|
60
|
+
return {
|
|
61
|
+
email: typeof record.email === "string" ? record.email : null,
|
|
62
|
+
name: typeof record.name === "string" ? record.name : null
|
|
63
|
+
};
|
|
64
|
+
};
|
|
65
|
+
async function handle(payload, ctx) {
|
|
66
|
+
debug("deliver notification event", payload);
|
|
67
|
+
const deliveryConfig = await resolveNotificationDeliveryConfig(ctx, { defaultValue: DEFAULT_NOTIFICATION_DELIVERY_CONFIG });
|
|
68
|
+
if (!deliveryConfig.strategies.email.enabled) {
|
|
69
|
+
debug("email delivery disabled");
|
|
70
|
+
}
|
|
71
|
+
const em = ctx.resolve("em");
|
|
72
|
+
const notification = await em.findOne(Notification, {
|
|
73
|
+
id: payload.notificationId,
|
|
74
|
+
tenantId: payload.tenantId,
|
|
75
|
+
organizationId: payload.organizationId ?? null
|
|
76
|
+
});
|
|
77
|
+
if (!notification) {
|
|
78
|
+
debug("notification not found", payload.notificationId);
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
let encryptionService = null;
|
|
82
|
+
try {
|
|
83
|
+
encryptionService = ctx.resolve("tenantEncryptionService");
|
|
84
|
+
} catch {
|
|
85
|
+
encryptionService = null;
|
|
86
|
+
}
|
|
87
|
+
const recipient = await resolveRecipient(em, notification, encryptionService) ?? { email: null, name: null };
|
|
88
|
+
if (!recipient?.email) {
|
|
89
|
+
debug("recipient has no email", notification.recipientUserId);
|
|
90
|
+
}
|
|
91
|
+
const { title, body, t } = await resolveNotificationCopy(notification);
|
|
92
|
+
const panelUrl = resolveNotificationPanelUrl(deliveryConfig);
|
|
93
|
+
if (!panelUrl) {
|
|
94
|
+
debug("missing panelUrl; check appUrl/panelPath settings");
|
|
95
|
+
}
|
|
96
|
+
const panelLink = panelUrl ? buildPanelLink(panelUrl, notification.id) : null;
|
|
97
|
+
const actionLinks = panelLink ? (notification.actionData?.actions ?? []).map((action) => ({
|
|
98
|
+
id: action.id,
|
|
99
|
+
label: action.labelKey ? t(action.labelKey, action.label) : action.label,
|
|
100
|
+
href: panelLink
|
|
101
|
+
})) : [];
|
|
102
|
+
if (deliveryConfig.strategies.email.enabled && recipient?.email && panelLink) {
|
|
103
|
+
const subjectPrefix = deliveryConfig.strategies.email.subjectPrefix?.trim();
|
|
104
|
+
const subject = subjectPrefix ? `${subjectPrefix} ${title}` : title;
|
|
105
|
+
const copy = {
|
|
106
|
+
preview: t("notifications.delivery.email.preview", "New notification"),
|
|
107
|
+
heading: t("notifications.delivery.email.heading", "You have a new notification"),
|
|
108
|
+
bodyIntro: t("notifications.delivery.email.bodyIntro", "Review the notification details and take any required actions."),
|
|
109
|
+
actionNotice: t("notifications.delivery.email.actionNotice", "Actions are available in Open Mercato and are read-only in this email."),
|
|
110
|
+
openCta: t("notifications.delivery.email.openCta", "Open notification center"),
|
|
111
|
+
footer: t("notifications.delivery.email.footer", "Open Mercato notifications")
|
|
112
|
+
};
|
|
113
|
+
try {
|
|
114
|
+
debug("sending email", { to: recipient.email, from: deliveryConfig.strategies.email.from, subject });
|
|
115
|
+
await sendEmail({
|
|
116
|
+
to: recipient.email,
|
|
117
|
+
subject,
|
|
118
|
+
from: deliveryConfig.strategies.email.from,
|
|
119
|
+
replyTo: deliveryConfig.strategies.email.replyTo,
|
|
120
|
+
react: NotificationEmail({
|
|
121
|
+
title,
|
|
122
|
+
body,
|
|
123
|
+
actions: actionLinks,
|
|
124
|
+
panelUrl: panelLink,
|
|
125
|
+
copy
|
|
126
|
+
})
|
|
127
|
+
});
|
|
128
|
+
} catch (error) {
|
|
129
|
+
console.error("[notifications] email delivery failed", error);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
const strategyConfigs = deliveryConfig.strategies.custom ?? {};
|
|
133
|
+
const strategies = getNotificationDeliveryStrategies();
|
|
134
|
+
for (const strategy of strategies) {
|
|
135
|
+
const strategyConfig = strategyConfigs[strategy.id];
|
|
136
|
+
const enabled = strategyConfig?.enabled ?? strategy.defaultEnabled ?? false;
|
|
137
|
+
if (!enabled) {
|
|
138
|
+
debug("custom delivery disabled", strategy.id);
|
|
139
|
+
continue;
|
|
140
|
+
}
|
|
141
|
+
try {
|
|
142
|
+
await strategy.deliver({
|
|
143
|
+
notification,
|
|
144
|
+
recipient,
|
|
145
|
+
title,
|
|
146
|
+
body,
|
|
147
|
+
panelUrl,
|
|
148
|
+
panelLink,
|
|
149
|
+
actionLinks,
|
|
150
|
+
deliveryConfig,
|
|
151
|
+
config: strategyConfig ?? {},
|
|
152
|
+
resolve: ctx.resolve,
|
|
153
|
+
t
|
|
154
|
+
});
|
|
155
|
+
} catch (error) {
|
|
156
|
+
console.error(`[notifications] delivery strategy failed (${strategy.id})`, error);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
export {
|
|
162
|
+
handle as default,
|
|
163
|
+
metadata
|
|
164
|
+
};
|
|
165
|
+
//# sourceMappingURL=deliver-notification.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../src/modules/notifications/subscribers/deliver-notification.ts"],
|
|
4
|
+
"sourcesContent": ["import type { EntityManager } from '@mikro-orm/postgresql'\nimport { Notification } from '../data/entities'\nimport { NOTIFICATION_EVENTS } from '../lib/events'\nimport { DEFAULT_NOTIFICATION_DELIVERY_CONFIG, resolveNotificationDeliveryConfig, resolveNotificationPanelUrl } from '../lib/deliveryConfig'\nimport { getNotificationDeliveryStrategies } from '../lib/deliveryStrategies'\nimport { sendEmail } from '@open-mercato/shared/lib/email/send'\nimport NotificationEmail from '../emails/NotificationEmail'\nimport { loadDictionary } from '@open-mercato/shared/lib/i18n/server'\nimport { createFallbackTranslator } from '@open-mercato/shared/lib/i18n/translate'\nimport { defaultLocale } from '@open-mercato/shared/lib/i18n/config'\nimport { findOneWithDecryption } from '@open-mercato/shared/lib/encryption/find'\nimport { User } from '../../auth/data/entities'\nimport type { TenantDataEncryptionService } from '@open-mercato/shared/lib/encryption/tenantDataEncryptionService'\n\nexport const metadata = {\n event: NOTIFICATION_EVENTS.CREATED,\n persistent: true,\n id: 'notifications:deliver',\n}\n\nconst DEBUG = process.env.NOTIFICATIONS_DEBUG === 'true'\n\nfunction debug(...args: unknown[]): void {\n if (DEBUG) {\n console.log('[notifications]', ...args)\n }\n}\n\ntype NotificationCreatedPayload = {\n notificationId: string\n recipientUserId: string\n tenantId: string\n organizationId?: string | null\n}\n\ntype ResolverContext = {\n resolve: <T = unknown>(name: string) => T\n}\n\nconst buildPanelLink = (panelUrl: string, notificationId: string) => {\n if (panelUrl.startsWith('http://') || panelUrl.startsWith('https://')) {\n const url = new URL(panelUrl)\n url.searchParams.set('notificationId', notificationId)\n return url.toString()\n }\n const separator = panelUrl.includes('?') ? '&' : '?'\n return `${panelUrl}${separator}notificationId=${encodeURIComponent(notificationId)}`\n}\n\nconst resolveNotificationCopy = async (\n notification: Notification\n) => {\n const dict = await loadDictionary(defaultLocale)\n const t = createFallbackTranslator(dict)\n\n const title = notification.titleKey\n ? t(notification.titleKey, notification.title ?? notification.titleKey, notification.titleVariables ?? undefined)\n : notification.title\n\n const body = notification.bodyKey\n ? t(notification.bodyKey, notification.body ?? notification.bodyKey ?? '', notification.bodyVariables ?? undefined)\n : notification.body ?? null\n\n return { title, body, t }\n}\n\nconst resolveRecipient = async (\n em: EntityManager,\n notification: Notification,\n encryptionService?: TenantDataEncryptionService | null,\n) => {\n const where: Partial<User> & { deletedAt?: null } = {\n id: notification.recipientUserId,\n tenantId: notification.tenantId,\n deletedAt: null,\n }\n if (notification.organizationId) {\n where.organizationId = notification.organizationId\n }\n const record = await findOneWithDecryption(\n em,\n User,\n where,\n undefined,\n {\n tenantId: notification.tenantId,\n organizationId: notification.organizationId ?? null,\n encryptionService: encryptionService ?? null,\n },\n )\n if (!record) return null\n return {\n email: typeof record.email === 'string' ? record.email : null,\n name: typeof record.name === 'string' ? record.name : null,\n }\n}\n\n\nexport default async function handle(payload: NotificationCreatedPayload, ctx: ResolverContext) {\n debug('deliver notification event', payload)\n const deliveryConfig = await resolveNotificationDeliveryConfig(ctx, { defaultValue: DEFAULT_NOTIFICATION_DELIVERY_CONFIG })\n if (!deliveryConfig.strategies.email.enabled) {\n debug('email delivery disabled')\n }\n\n const em = ctx.resolve('em') as EntityManager\n const notification = await em.findOne(Notification, {\n id: payload.notificationId,\n tenantId: payload.tenantId,\n organizationId: payload.organizationId ?? null,\n })\n if (!notification) {\n debug('notification not found', payload.notificationId)\n return\n }\n\n let encryptionService: TenantDataEncryptionService | null = null\n try {\n encryptionService = ctx.resolve<TenantDataEncryptionService>('tenantEncryptionService')\n } catch {\n encryptionService = null\n }\n\n const recipient = (await resolveRecipient(em, notification, encryptionService)) ?? { email: null, name: null }\n if (!recipient?.email) {\n debug('recipient has no email', notification.recipientUserId)\n }\n const { title, body, t } = await resolveNotificationCopy(notification)\n const panelUrl = resolveNotificationPanelUrl(deliveryConfig)\n if (!panelUrl) {\n debug('missing panelUrl; check appUrl/panelPath settings')\n }\n\n const panelLink = panelUrl ? buildPanelLink(panelUrl, notification.id) : null\n const actionLinks = panelLink\n ? (notification.actionData?.actions ?? []).map((action) => ({\n id: action.id,\n label: action.labelKey ? t(action.labelKey, action.label) : action.label,\n href: panelLink,\n }))\n : []\n\n if (deliveryConfig.strategies.email.enabled && recipient?.email && panelLink) {\n const subjectPrefix = deliveryConfig.strategies.email.subjectPrefix?.trim()\n const subject = subjectPrefix ? `${subjectPrefix} ${title}` : title\n const copy = {\n preview: t('notifications.delivery.email.preview', 'New notification'),\n heading: t('notifications.delivery.email.heading', 'You have a new notification'),\n bodyIntro: t('notifications.delivery.email.bodyIntro', 'Review the notification details and take any required actions.'),\n actionNotice: t('notifications.delivery.email.actionNotice', 'Actions are available in Open Mercato and are read-only in this email.'),\n openCta: t('notifications.delivery.email.openCta', 'Open notification center'),\n footer: t('notifications.delivery.email.footer', 'Open Mercato notifications'),\n }\n\n try {\n debug('sending email', { to: recipient.email, from: deliveryConfig.strategies.email.from, subject })\n await sendEmail({\n to: recipient.email,\n subject,\n from: deliveryConfig.strategies.email.from,\n replyTo: deliveryConfig.strategies.email.replyTo,\n react: NotificationEmail({\n title,\n body,\n actions: actionLinks,\n panelUrl: panelLink,\n copy,\n }),\n })\n } catch (error) {\n console.error('[notifications] email delivery failed', error)\n }\n }\n\n const strategyConfigs = deliveryConfig.strategies.custom ?? {}\n const strategies = getNotificationDeliveryStrategies()\n for (const strategy of strategies) {\n const strategyConfig = strategyConfigs[strategy.id]\n const enabled = strategyConfig?.enabled ?? strategy.defaultEnabled ?? false\n if (!enabled) {\n debug('custom delivery disabled', strategy.id)\n continue\n }\n try {\n await strategy.deliver({\n notification,\n recipient,\n title,\n body,\n panelUrl,\n panelLink,\n actionLinks,\n deliveryConfig,\n config: strategyConfig ?? {},\n resolve: ctx.resolve,\n t,\n })\n } catch (error) {\n console.error(`[notifications] delivery strategy failed (${strategy.id})`, error)\n }\n }\n\n return\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { buildNotificationEntity, emitNotificationCreated, emitNotificationCreatedBatch } from "../lib/notificationFactory.js";
|
|
2
|
+
import { getRecipientUserIdsForFeature, getRecipientUserIdsForRole } from "../lib/notificationRecipients.js";
|
|
3
|
+
function getKnex(em) {
|
|
4
|
+
return em.getConnection().getKnex();
|
|
5
|
+
}
|
|
6
|
+
const NOTIFICATIONS_QUEUE_NAME = "notifications";
|
|
7
|
+
const metadata = {
|
|
8
|
+
queue: NOTIFICATIONS_QUEUE_NAME,
|
|
9
|
+
id: "notifications:create",
|
|
10
|
+
concurrency: 5
|
|
11
|
+
};
|
|
12
|
+
async function handle(job, ctx) {
|
|
13
|
+
const { payload } = job;
|
|
14
|
+
if (payload.type === "create") {
|
|
15
|
+
const em = ctx.resolve("em").fork();
|
|
16
|
+
const eventBus = ctx.resolve("eventBus");
|
|
17
|
+
const { input, tenantId, organizationId } = payload;
|
|
18
|
+
const { recipientUserId, ...content } = input;
|
|
19
|
+
const notification = buildNotificationEntity(em, content, recipientUserId, { tenantId, organizationId });
|
|
20
|
+
await em.persistAndFlush(notification);
|
|
21
|
+
await emitNotificationCreated(eventBus, notification, { tenantId, organizationId });
|
|
22
|
+
} else if (payload.type === "create-role") {
|
|
23
|
+
const em = ctx.resolve("em").fork();
|
|
24
|
+
const eventBus = ctx.resolve("eventBus");
|
|
25
|
+
const { input, tenantId, organizationId } = payload;
|
|
26
|
+
const knex = getKnex(em);
|
|
27
|
+
const recipientUserIds = await getRecipientUserIdsForRole(knex, tenantId, input.roleId);
|
|
28
|
+
if (recipientUserIds.length === 0) {
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
const { roleId: _roleId, ...content } = input;
|
|
32
|
+
const notifications = [];
|
|
33
|
+
for (const recipientUserId of recipientUserIds) {
|
|
34
|
+
const notification = buildNotificationEntity(em, content, recipientUserId, { tenantId, organizationId });
|
|
35
|
+
notifications.push(notification);
|
|
36
|
+
}
|
|
37
|
+
await em.persistAndFlush(notifications);
|
|
38
|
+
await emitNotificationCreatedBatch(eventBus, notifications, { tenantId, organizationId });
|
|
39
|
+
} else if (payload.type === "create-feature") {
|
|
40
|
+
const em = ctx.resolve("em").fork();
|
|
41
|
+
const eventBus = ctx.resolve("eventBus");
|
|
42
|
+
const { input, tenantId, organizationId } = payload;
|
|
43
|
+
const knex = getKnex(em);
|
|
44
|
+
const recipientUserIds = await getRecipientUserIdsForFeature(knex, tenantId, input.requiredFeature);
|
|
45
|
+
if (recipientUserIds.length === 0) {
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
const notifications = [];
|
|
49
|
+
const { requiredFeature: _requiredFeature, ...content } = input;
|
|
50
|
+
for (const recipientUserId of recipientUserIds) {
|
|
51
|
+
const notification = buildNotificationEntity(em, content, recipientUserId, { tenantId, organizationId });
|
|
52
|
+
notifications.push(notification);
|
|
53
|
+
}
|
|
54
|
+
await em.persistAndFlush(notifications);
|
|
55
|
+
await emitNotificationCreatedBatch(eventBus, notifications, { tenantId, organizationId });
|
|
56
|
+
} else if (payload.type === "cleanup-expired") {
|
|
57
|
+
const em = ctx.resolve("em").fork();
|
|
58
|
+
const knex = getKnex(em);
|
|
59
|
+
await knex("notifications").where("expires_at", "<", knex.fn.now()).whereNotIn("status", ["actioned", "dismissed"]).update({
|
|
60
|
+
status: "dismissed",
|
|
61
|
+
dismissed_at: knex.fn.now()
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
export {
|
|
66
|
+
NOTIFICATIONS_QUEUE_NAME,
|
|
67
|
+
handle as default,
|
|
68
|
+
metadata
|
|
69
|
+
};
|
|
70
|
+
//# sourceMappingURL=create-notification.worker.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../src/modules/notifications/workers/create-notification.worker.ts"],
|
|
4
|
+
"sourcesContent": ["import type { EntityManager } from '@mikro-orm/core'\nimport type { Knex } from 'knex'\nimport { Notification } from '../data/entities'\nimport type { CreateNotificationInput, CreateRoleNotificationInput, CreateFeatureNotificationInput } from '../data/validators'\nimport { buildNotificationEntity, emitNotificationCreated, emitNotificationCreatedBatch } from '../lib/notificationFactory'\nimport { getRecipientUserIdsForFeature, getRecipientUserIdsForRole } from '../lib/notificationRecipients'\n\nfunction getKnex(em: EntityManager): Knex {\n return (em.getConnection() as unknown as { getKnex: () => Knex }).getKnex()\n}\n\nexport const NOTIFICATIONS_QUEUE_NAME = 'notifications'\n\nexport type CreateNotificationJob = {\n type: 'create'\n input: CreateNotificationInput\n tenantId: string\n organizationId?: string | null\n}\n\nexport type CreateRoleNotificationJob = {\n type: 'create-role'\n input: CreateRoleNotificationInput\n tenantId: string\n organizationId?: string | null\n}\n\nexport type CreateFeatureNotificationJob = {\n type: 'create-feature'\n input: CreateFeatureNotificationInput\n tenantId: string\n organizationId?: string | null\n}\n\nexport type CleanupExpiredJob = {\n type: 'cleanup-expired'\n}\n\nexport type NotificationJob = CreateNotificationJob | CreateRoleNotificationJob | CreateFeatureNotificationJob | CleanupExpiredJob\n\nexport const metadata = {\n queue: NOTIFICATIONS_QUEUE_NAME,\n id: 'notifications:create',\n concurrency: 5,\n}\n\ntype HandlerContext = {\n resolve: <T = unknown>(name: string) => T\n}\n\nexport default async function handle(\n job: { payload: NotificationJob },\n ctx: HandlerContext\n): Promise<void> {\n const { payload } = job\n\n if (payload.type === 'create') {\n const em = (ctx.resolve('em') as EntityManager).fork()\n const eventBus = ctx.resolve('eventBus') as { emit: (event: string, payload: unknown) => Promise<void> }\n const { input, tenantId, organizationId } = payload\n const { recipientUserId, ...content } = input\n const notification = buildNotificationEntity(em, content, recipientUserId, { tenantId, organizationId })\n\n await em.persistAndFlush(notification)\n\n await emitNotificationCreated(eventBus, notification, { tenantId, organizationId })\n } else if (payload.type === 'create-role') {\n const em = (ctx.resolve('em') as EntityManager).fork()\n const eventBus = ctx.resolve('eventBus') as { emit: (event: string, payload: unknown) => Promise<void> }\n const { input, tenantId, organizationId } = payload\n\n const knex = getKnex(em)\n const recipientUserIds = await getRecipientUserIdsForRole(knex, tenantId, input.roleId)\n if (recipientUserIds.length === 0) {\n return\n }\n\n const { roleId: _roleId, ...content } = input\n const notifications: Notification[] = []\n for (const recipientUserId of recipientUserIds) {\n const notification = buildNotificationEntity(em, content, recipientUserId, { tenantId, organizationId })\n notifications.push(notification)\n }\n\n await em.persistAndFlush(notifications)\n\n await emitNotificationCreatedBatch(eventBus, notifications, { tenantId, organizationId })\n } else if (payload.type === 'create-feature') {\n const em = (ctx.resolve('em') as EntityManager).fork()\n const eventBus = ctx.resolve('eventBus') as { emit: (event: string, payload: unknown) => Promise<void> }\n const { input, tenantId, organizationId } = payload\n\n const knex = getKnex(em)\n const recipientUserIds = await getRecipientUserIdsForFeature(knex, tenantId, input.requiredFeature)\n\n if (recipientUserIds.length === 0) {\n return\n }\n\n const notifications: Notification[] = []\n const { requiredFeature: _requiredFeature, ...content } = input\n for (const recipientUserId of recipientUserIds) {\n const notification = buildNotificationEntity(em, content, recipientUserId, { tenantId, organizationId })\n notifications.push(notification)\n }\n\n await em.persistAndFlush(notifications)\n\n await emitNotificationCreatedBatch(eventBus, notifications, { tenantId, organizationId })\n } else if (payload.type === 'cleanup-expired') {\n const em = (ctx.resolve('em') as EntityManager).fork()\n const knex = getKnex(em)\n\n await knex('notifications')\n .where('expires_at', '<', knex.fn.now())\n .whereNotIn('status', ['actioned', 'dismissed'])\n .update({\n status: 'dismissed',\n dismissed_at: knex.fn.now(),\n })\n }\n}\n"],
|
|
5
|
+
"mappings": "AAIA,SAAS,yBAAyB,yBAAyB,oCAAoC;AAC/F,SAAS,+BAA+B,kCAAkC;AAE1E,SAAS,QAAQ,IAAyB;AACxC,SAAQ,GAAG,cAAc,EAAyC,QAAQ;AAC5E;AAEO,MAAM,2BAA2B;AA6BjC,MAAM,WAAW;AAAA,EACtB,OAAO;AAAA,EACP,IAAI;AAAA,EACJ,aAAa;AACf;AAMA,eAAO,OACL,KACA,KACe;AACf,QAAM,EAAE,QAAQ,IAAI;AAEpB,MAAI,QAAQ,SAAS,UAAU;AAC7B,UAAM,KAAM,IAAI,QAAQ,IAAI,EAAoB,KAAK;AACrD,UAAM,WAAW,IAAI,QAAQ,UAAU;AACvC,UAAM,EAAE,OAAO,UAAU,eAAe,IAAI;AAC5C,UAAM,EAAE,iBAAiB,GAAG,QAAQ,IAAI;AACxC,UAAM,eAAe,wBAAwB,IAAI,SAAS,iBAAiB,EAAE,UAAU,eAAe,CAAC;AAEvG,UAAM,GAAG,gBAAgB,YAAY;AAErC,UAAM,wBAAwB,UAAU,cAAc,EAAE,UAAU,eAAe,CAAC;AAAA,EACpF,WAAW,QAAQ,SAAS,eAAe;AACzC,UAAM,KAAM,IAAI,QAAQ,IAAI,EAAoB,KAAK;AACrD,UAAM,WAAW,IAAI,QAAQ,UAAU;AACvC,UAAM,EAAE,OAAO,UAAU,eAAe,IAAI;AAE5C,UAAM,OAAO,QAAQ,EAAE;AACvB,UAAM,mBAAmB,MAAM,2BAA2B,MAAM,UAAU,MAAM,MAAM;AACtF,QAAI,iBAAiB,WAAW,GAAG;AACjC;AAAA,IACF;AAEA,UAAM,EAAE,QAAQ,SAAS,GAAG,QAAQ,IAAI;AACxC,UAAM,gBAAgC,CAAC;AACvC,eAAW,mBAAmB,kBAAkB;AAC9C,YAAM,eAAe,wBAAwB,IAAI,SAAS,iBAAiB,EAAE,UAAU,eAAe,CAAC;AACvG,oBAAc,KAAK,YAAY;AAAA,IACjC;AAEA,UAAM,GAAG,gBAAgB,aAAa;AAEtC,UAAM,6BAA6B,UAAU,eAAe,EAAE,UAAU,eAAe,CAAC;AAAA,EAC1F,WAAW,QAAQ,SAAS,kBAAkB;AAC5C,UAAM,KAAM,IAAI,QAAQ,IAAI,EAAoB,KAAK;AACrD,UAAM,WAAW,IAAI,QAAQ,UAAU;AACvC,UAAM,EAAE,OAAO,UAAU,eAAe,IAAI;AAE5C,UAAM,OAAO,QAAQ,EAAE;AACvB,UAAM,mBAAmB,MAAM,8BAA8B,MAAM,UAAU,MAAM,eAAe;AAElG,QAAI,iBAAiB,WAAW,GAAG;AACjC;AAAA,IACF;AAEA,UAAM,gBAAgC,CAAC;AACvC,UAAM,EAAE,iBAAiB,kBAAkB,GAAG,QAAQ,IAAI;AAC1D,eAAW,mBAAmB,kBAAkB;AAC9C,YAAM,eAAe,wBAAwB,IAAI,SAAS,iBAAiB,EAAE,UAAU,eAAe,CAAC;AACvG,oBAAc,KAAK,YAAY;AAAA,IACjC;AAEA,UAAM,GAAG,gBAAgB,aAAa;AAEtC,UAAM,6BAA6B,UAAU,eAAe,EAAE,UAAU,eAAe,CAAC;AAAA,EAC1F,WAAW,QAAQ,SAAS,mBAAmB;AAC7C,UAAM,KAAM,IAAI,QAAQ,IAAI,EAAoB,KAAK;AACrD,UAAM,OAAO,QAAQ,EAAE;AAEvB,UAAM,KAAK,eAAe,EACvB,MAAM,cAAc,KAAK,KAAK,GAAG,IAAI,CAAC,EACtC,WAAW,UAAU,CAAC,YAAY,WAAW,CAAC,EAC9C,OAAO;AAAA,MACN,QAAQ;AAAA,MACR,cAAc,KAAK,GAAG,IAAI;AAAA,IAC5B,CAAC;AAAA,EACL;AACF;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -161,8 +161,8 @@ function PlannerAvailabilityRuleSetsPage() {
|
|
|
161
161
|
RowActions,
|
|
162
162
|
{
|
|
163
163
|
items: [
|
|
164
|
-
{ label: labels.actions.edit, href: `/backend/planner/availability-rulesets/${row.id}` },
|
|
165
|
-
{ label: labels.actions.delete, destructive: true, onSelect: () => {
|
|
164
|
+
{ id: "edit", label: labels.actions.edit, href: `/backend/planner/availability-rulesets/${row.id}` },
|
|
165
|
+
{ id: "delete", label: labels.actions.delete, destructive: true, onSelect: () => {
|
|
166
166
|
void handleDelete(row);
|
|
167
167
|
} }
|
|
168
168
|
]
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../../src/modules/planner/backend/planner/availability-rulesets/page.tsx"],
|
|
4
|
-
"sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport Link from 'next/link'\nimport { useRouter } from 'next/navigation'\nimport type { ColumnDef, SortingState } from '@tanstack/react-table'\nimport type { PluggableList } from 'unified'\nimport ReactMarkdown from 'react-markdown'\nimport remarkGfm from 'remark-gfm'\nimport { Page, PageBody } from '@open-mercato/ui/backend/Page'\nimport { DataTable } from '@open-mercato/ui/backend/DataTable'\nimport { RowActions } from '@open-mercato/ui/backend/RowActions'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { readApiResultOrThrow } from '@open-mercato/ui/backend/utils/apiCall'\nimport { deleteCrud } from '@open-mercato/ui/backend/utils/crud'\nimport { flash } from '@open-mercato/ui/backend/FlashMessages'\nimport { normalizeCrudServerError } from '@open-mercato/ui/backend/utils/serverErrors'\nimport { useOrganizationScopeVersion } from '@open-mercato/shared/lib/frontend/useOrganizationScope'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\n\nconst PAGE_SIZE = 50\nconst MARKDOWN_PLUGINS: PluggableList = [remarkGfm]\nconst MARKDOWN_SUBTEXT_CLASSNAME =\n 'line-clamp-2 text-xs text-muted-foreground [&>p]:m-0 [&_ul]:ml-4 [&_ul]:list-disc [&_ol]:ml-4 [&_ol]:list-decimal [&_code]:rounded [&_code]:bg-muted [&_code]:px-1 [&_code]:py-0.5'\n\ntype RuleSetRow = {\n id: string\n name: string\n description: string | null\n timezone: string\n updatedAt: string | null\n}\n\ntype RuleSetResponse = {\n items?: Array<Record<string, unknown>>\n total?: number\n totalPages?: number\n}\n\nexport default function PlannerAvailabilityRuleSetsPage() {\n const t = useT()\n const router = useRouter()\n const scopeVersion = useOrganizationScopeVersion()\n const [rows, setRows] = React.useState<RuleSetRow[]>([])\n const [page, setPage] = React.useState(1)\n const [total, setTotal] = React.useState(0)\n const [totalPages, setTotalPages] = React.useState(1)\n const [sorting, setSorting] = React.useState<SortingState>([{ id: 'name', desc: false }])\n const [search, setSearch] = React.useState('')\n const [isLoading, setIsLoading] = React.useState(true)\n const [reloadToken, setReloadToken] = React.useState(0)\n\n const labels = React.useMemo(() => ({\n title: t('planner.availabilityRuleSets.page.title', 'Availability schedules'),\n description: t('planner.availabilityRuleSets.page.description', 'Manage shared availability rulesets.'),\n table: {\n name: t('planner.availabilityRuleSets.table.name', 'Name'),\n timezone: t('planner.availabilityRuleSets.table.timezone', 'Timezone'),\n updatedAt: t('planner.availabilityRuleSets.table.updatedAt', 'Updated'),\n empty: t('planner.availabilityRuleSets.table.empty', 'No schedules yet.'),\n search: t('planner.availabilityRuleSets.table.search', 'Search schedules...'),\n },\n actions: {\n add: t('planner.availabilityRuleSets.actions.add', 'New schedule'),\n edit: t('planner.availabilityRuleSets.actions.edit', 'Edit'),\n delete: t('planner.availabilityRuleSets.actions.delete', 'Delete'),\n deleteConfirm: t('planner.availabilityRuleSets.actions.deleteConfirm', 'Delete schedule \"{{name}}\"?'),\n refresh: t('planner.availabilityRuleSets.actions.refresh', 'Refresh'),\n },\n messages: {\n deleted: t('planner.availabilityRuleSets.messages.deleted', 'Schedule deleted.'),\n },\n errors: {\n load: t('planner.availabilityRuleSets.errors.load', 'Failed to load schedules.'),\n delete: t('planner.availabilityRuleSets.errors.delete', 'Failed to delete schedule.'),\n },\n }), [t])\n\n const loadRuleSets = React.useCallback(async () => {\n setIsLoading(true)\n try {\n const params = new URLSearchParams({\n page: String(page),\n pageSize: String(PAGE_SIZE),\n })\n const sort = sorting[0]\n if (sort?.id) {\n params.set('sortField', sort.id)\n params.set('sortDir', sort.desc ? 'desc' : 'asc')\n }\n if (search.trim()) params.set('search', search.trim())\n const payload = await readApiResultOrThrow<RuleSetResponse>(\n `/api/planner/availability-rule-sets?${params.toString()}`,\n undefined,\n { errorMessage: labels.errors.load, fallback: { items: [], total: 0, totalPages: 1 } },\n )\n const items = Array.isArray(payload.items) ? payload.items : []\n setRows(items.map(mapRuleSet))\n setTotal(typeof payload.total === 'number' ? payload.total : items.length)\n setTotalPages(typeof payload.totalPages === 'number' ? payload.totalPages : Math.max(1, Math.ceil(items.length / PAGE_SIZE)))\n } catch (error) {\n console.error('planner.availability-rule-sets.list', error)\n flash(labels.errors.load, 'error')\n } finally {\n setIsLoading(false)\n }\n }, [labels.errors.load, page, search, sorting])\n\n React.useEffect(() => {\n void loadRuleSets()\n }, [loadRuleSets, scopeVersion, reloadToken])\n\n const handleSearchChange = React.useCallback((value: string) => {\n setSearch(value)\n setPage(1)\n }, [])\n\n const handleRefresh = React.useCallback(() => {\n setReloadToken((token) => token + 1)\n }, [])\n\n const handleDelete = React.useCallback(async (entry: RuleSetRow) => {\n const message = labels.actions.deleteConfirm.replace('{{name}}', entry.name)\n if (typeof window !== 'undefined' && !window.confirm(message)) return\n try {\n await deleteCrud('planner/availability-rule-sets', entry.id, { errorMessage: labels.errors.delete })\n flash(labels.messages.deleted, 'success')\n handleRefresh()\n } catch (error) {\n console.error('planner.availability-rule-sets.delete', error)\n const normalized = normalizeCrudServerError(error)\n flash(normalized.message ?? labels.errors.delete, 'error')\n }\n }, [handleRefresh, labels.actions.deleteConfirm, labels.errors.delete, labels.messages.deleted])\n\n const columns = React.useMemo<ColumnDef<RuleSetRow>[]>(() => [\n {\n accessorKey: 'name',\n header: labels.table.name,\n meta: { priority: 1, sticky: true },\n cell: ({ row }) => (\n <div className=\"flex flex-col\">\n <span className=\"font-medium\">{row.original.name}</span>\n {row.original.description ? (\n <ReactMarkdown remarkPlugins={MARKDOWN_PLUGINS} className={MARKDOWN_SUBTEXT_CLASSNAME}>\n {row.original.description}\n </ReactMarkdown>\n ) : null}\n </div>\n ),\n },\n {\n accessorKey: 'timezone',\n header: labels.table.timezone,\n meta: { priority: 2 },\n cell: ({ row }) => <span className=\"text-sm\">{row.original.timezone}</span>,\n },\n {\n accessorKey: 'updatedAt',\n header: labels.table.updatedAt,\n meta: { priority: 3 },\n cell: ({ row }) => row.original.updatedAt\n ? <span className=\"text-xs text-muted-foreground\">{formatDateTime(row.original.updatedAt)}</span>\n : <span className=\"text-xs text-muted-foreground\">-</span>,\n },\n ], [labels.table.name, labels.table.timezone, labels.table.updatedAt])\n\n return (\n <Page>\n <PageBody>\n <DataTable<RuleSetRow>\n title={labels.title}\n data={rows}\n columns={columns}\n isLoading={isLoading}\n searchValue={search}\n onSearchChange={handleSearchChange}\n searchPlaceholder={labels.table.search}\n emptyState={<p className=\"py-8 text-center text-sm text-muted-foreground\">{labels.table.empty}</p>}\n actions={(\n <Button asChild size=\"sm\">\n <Link href=\"/backend/planner/availability-rulesets/create\">\n {labels.actions.add}\n </Link>\n </Button>\n )}\n refreshButton={{\n label: labels.actions.refresh,\n onRefresh: handleRefresh,\n isRefreshing: isLoading,\n }}\n sortable\n sorting={sorting}\n onSortingChange={setSorting}\n pagination={{\n page,\n pageSize: PAGE_SIZE,\n total,\n totalPages,\n onPageChange: setPage,\n }}\n rowActions={(row) => (\n <RowActions\n items={[\n { label: labels.actions.edit, href: `/backend/planner/availability-rulesets/${row.id}` },\n { label: labels.actions.delete, destructive: true, onSelect: () => { void handleDelete(row) } },\n ]}\n />\n )}\n onRowClick={(row) => router.push(`/backend/planner/availability-rulesets/${row.id}`)}\n />\n </PageBody>\n </Page>\n )\n}\n\nfunction mapRuleSet(item: Record<string, unknown>): RuleSetRow {\n const id = typeof item.id === 'string' ? item.id : ''\n const name = typeof item.name === 'string' ? item.name : id\n const description = typeof item.description === 'string' ? item.description : null\n const timezone = typeof item.timezone === 'string' ? item.timezone : 'UTC'\n const updatedAt =\n typeof item.updatedAt === 'string'\n ? item.updatedAt\n : typeof item.updated_at === 'string'\n ? item.updated_at\n : null\n return {\n id,\n name,\n description,\n timezone,\n updatedAt,\n }\n}\n\nfunction formatDateTime(value: string): string {\n const parsed = new Date(value)\n if (Number.isNaN(parsed.getTime())) return value\n return parsed.toLocaleString()\n}\n"],
|
|
5
|
-
"mappings": ";AA6IQ,SACE,KADF;AA3IR,YAAY,WAAW;AACvB,OAAO,UAAU;AACjB,SAAS,iBAAiB;AAG1B,OAAO,mBAAmB;AAC1B,OAAO,eAAe;AACtB,SAAS,MAAM,gBAAgB;AAC/B,SAAS,iBAAiB;AAC1B,SAAS,kBAAkB;AAC3B,SAAS,cAAc;AACvB,SAAS,4BAA4B;AACrC,SAAS,kBAAkB;AAC3B,SAAS,aAAa;AACtB,SAAS,gCAAgC;AACzC,SAAS,mCAAmC;AAC5C,SAAS,YAAY;AAErB,MAAM,YAAY;AAClB,MAAM,mBAAkC,CAAC,SAAS;AAClD,MAAM,6BACJ;AAgBa,SAAR,kCAAmD;AACxD,QAAM,IAAI,KAAK;AACf,QAAM,SAAS,UAAU;AACzB,QAAM,eAAe,4BAA4B;AACjD,QAAM,CAAC,MAAM,OAAO,IAAI,MAAM,SAAuB,CAAC,CAAC;AACvD,QAAM,CAAC,MAAM,OAAO,IAAI,MAAM,SAAS,CAAC;AACxC,QAAM,CAAC,OAAO,QAAQ,IAAI,MAAM,SAAS,CAAC;AAC1C,QAAM,CAAC,YAAY,aAAa,IAAI,MAAM,SAAS,CAAC;AACpD,QAAM,CAAC,SAAS,UAAU,IAAI,MAAM,SAAuB,CAAC,EAAE,IAAI,QAAQ,MAAM,MAAM,CAAC,CAAC;AACxF,QAAM,CAAC,QAAQ,SAAS,IAAI,MAAM,SAAS,EAAE;AAC7C,QAAM,CAAC,WAAW,YAAY,IAAI,MAAM,SAAS,IAAI;AACrD,QAAM,CAAC,aAAa,cAAc,IAAI,MAAM,SAAS,CAAC;AAEtD,QAAM,SAAS,MAAM,QAAQ,OAAO;AAAA,IAClC,OAAO,EAAE,2CAA2C,wBAAwB;AAAA,IAC5E,aAAa,EAAE,iDAAiD,sCAAsC;AAAA,IACtG,OAAO;AAAA,MACL,MAAM,EAAE,2CAA2C,MAAM;AAAA,MACzD,UAAU,EAAE,+CAA+C,UAAU;AAAA,MACrE,WAAW,EAAE,gDAAgD,SAAS;AAAA,MACtE,OAAO,EAAE,4CAA4C,mBAAmB;AAAA,MACxE,QAAQ,EAAE,6CAA6C,qBAAqB;AAAA,IAC9E;AAAA,IACA,SAAS;AAAA,MACP,KAAK,EAAE,4CAA4C,cAAc;AAAA,MACjE,MAAM,EAAE,6CAA6C,MAAM;AAAA,MAC3D,QAAQ,EAAE,+CAA+C,QAAQ;AAAA,MACjE,eAAe,EAAE,sDAAsD,6BAA6B;AAAA,MACpG,SAAS,EAAE,gDAAgD,SAAS;AAAA,IACtE;AAAA,IACA,UAAU;AAAA,MACR,SAAS,EAAE,iDAAiD,mBAAmB;AAAA,IACjF;AAAA,IACA,QAAQ;AAAA,MACN,MAAM,EAAE,4CAA4C,2BAA2B;AAAA,MAC/E,QAAQ,EAAE,8CAA8C,4BAA4B;AAAA,IACtF;AAAA,EACF,IAAI,CAAC,CAAC,CAAC;AAEP,QAAM,eAAe,MAAM,YAAY,YAAY;AACjD,iBAAa,IAAI;AACjB,QAAI;AACF,YAAM,SAAS,IAAI,gBAAgB;AAAA,QACjC,MAAM,OAAO,IAAI;AAAA,QACjB,UAAU,OAAO,SAAS;AAAA,MAC5B,CAAC;AACD,YAAM,OAAO,QAAQ,CAAC;AACtB,UAAI,MAAM,IAAI;AACZ,eAAO,IAAI,aAAa,KAAK,EAAE;AAC/B,eAAO,IAAI,WAAW,KAAK,OAAO,SAAS,KAAK;AAAA,MAClD;AACA,UAAI,OAAO,KAAK,EAAG,QAAO,IAAI,UAAU,OAAO,KAAK,CAAC;AACrD,YAAM,UAAU,MAAM;AAAA,QACpB,uCAAuC,OAAO,SAAS,CAAC;AAAA,QACxD;AAAA,QACA,EAAE,cAAc,OAAO,OAAO,MAAM,UAAU,EAAE,OAAO,CAAC,GAAG,OAAO,GAAG,YAAY,EAAE,EAAE;AAAA,MACvF;AACA,YAAM,QAAQ,MAAM,QAAQ,QAAQ,KAAK,IAAI,QAAQ,QAAQ,CAAC;AAC9D,cAAQ,MAAM,IAAI,UAAU,CAAC;AAC7B,eAAS,OAAO,QAAQ,UAAU,WAAW,QAAQ,QAAQ,MAAM,MAAM;AACzE,oBAAc,OAAO,QAAQ,eAAe,WAAW,QAAQ,aAAa,KAAK,IAAI,GAAG,KAAK,KAAK,MAAM,SAAS,SAAS,CAAC,CAAC;AAAA,IAC9H,SAAS,OAAO;AACd,cAAQ,MAAM,uCAAuC,KAAK;AAC1D,YAAM,OAAO,OAAO,MAAM,OAAO;AAAA,IACnC,UAAE;AACA,mBAAa,KAAK;AAAA,IACpB;AAAA,EACF,GAAG,CAAC,OAAO,OAAO,MAAM,MAAM,QAAQ,OAAO,CAAC;AAE9C,QAAM,UAAU,MAAM;AACpB,SAAK,aAAa;AAAA,EACpB,GAAG,CAAC,cAAc,cAAc,WAAW,CAAC;AAE5C,QAAM,qBAAqB,MAAM,YAAY,CAAC,UAAkB;AAC9D,cAAU,KAAK;AACf,YAAQ,CAAC;AAAA,EACX,GAAG,CAAC,CAAC;AAEL,QAAM,gBAAgB,MAAM,YAAY,MAAM;AAC5C,mBAAe,CAAC,UAAU,QAAQ,CAAC;AAAA,EACrC,GAAG,CAAC,CAAC;AAEL,QAAM,eAAe,MAAM,YAAY,OAAO,UAAsB;AAClE,UAAM,UAAU,OAAO,QAAQ,cAAc,QAAQ,YAAY,MAAM,IAAI;AAC3E,QAAI,OAAO,WAAW,eAAe,CAAC,OAAO,QAAQ,OAAO,EAAG;AAC/D,QAAI;AACF,YAAM,WAAW,kCAAkC,MAAM,IAAI,EAAE,cAAc,OAAO,OAAO,OAAO,CAAC;AACnG,YAAM,OAAO,SAAS,SAAS,SAAS;AACxC,oBAAc;AAAA,IAChB,SAAS,OAAO;AACd,cAAQ,MAAM,yCAAyC,KAAK;AAC5D,YAAM,aAAa,yBAAyB,KAAK;AACjD,YAAM,WAAW,WAAW,OAAO,OAAO,QAAQ,OAAO;AAAA,IAC3D;AAAA,EACF,GAAG,CAAC,eAAe,OAAO,QAAQ,eAAe,OAAO,OAAO,QAAQ,OAAO,SAAS,OAAO,CAAC;AAE/F,QAAM,UAAU,MAAM,QAAiC,MAAM;AAAA,IAC3D;AAAA,MACE,aAAa;AAAA,MACb,QAAQ,OAAO,MAAM;AAAA,MACrB,MAAM,EAAE,UAAU,GAAG,QAAQ,KAAK;AAAA,MAClC,MAAM,CAAC,EAAE,IAAI,MACX,qBAAC,SAAI,WAAU,iBACb;AAAA,4BAAC,UAAK,WAAU,eAAe,cAAI,SAAS,MAAK;AAAA,QAChD,IAAI,SAAS,cACZ,oBAAC,iBAAc,eAAe,kBAAkB,WAAW,4BACxD,cAAI,SAAS,aAChB,IACE;AAAA,SACN;AAAA,IAEJ;AAAA,IACA;AAAA,MACE,aAAa;AAAA,MACb,QAAQ,OAAO,MAAM;AAAA,MACrB,MAAM,EAAE,UAAU,EAAE;AAAA,MACpB,MAAM,CAAC,EAAE,IAAI,MAAM,oBAAC,UAAK,WAAU,WAAW,cAAI,SAAS,UAAS;AAAA,IACtE;AAAA,IACA;AAAA,MACE,aAAa;AAAA,MACb,QAAQ,OAAO,MAAM;AAAA,MACrB,MAAM,EAAE,UAAU,EAAE;AAAA,MACpB,MAAM,CAAC,EAAE,IAAI,MAAM,IAAI,SAAS,YAC5B,oBAAC,UAAK,WAAU,iCAAiC,yBAAe,IAAI,SAAS,SAAS,GAAE,IACxF,oBAAC,UAAK,WAAU,iCAAgC,eAAC;AAAA,IACvD;AAAA,EACF,GAAG,CAAC,OAAO,MAAM,MAAM,OAAO,MAAM,UAAU,OAAO,MAAM,SAAS,CAAC;AAErE,SACE,oBAAC,QACC,8BAAC,YACC;AAAA,IAAC;AAAA;AAAA,MACC,OAAO,OAAO;AAAA,MACd,MAAM;AAAA,MACN;AAAA,MACA;AAAA,MACA,aAAa;AAAA,MACb,gBAAgB;AAAA,MAChB,mBAAmB,OAAO,MAAM;AAAA,MAChC,YAAY,oBAAC,OAAE,WAAU,kDAAkD,iBAAO,MAAM,OAAM;AAAA,MAC9F,SACE,oBAAC,UAAO,SAAO,MAAC,MAAK,MACnB,8BAAC,QAAK,MAAK,iDACR,iBAAO,QAAQ,KAClB,GACF;AAAA,MAEF,eAAe;AAAA,QACb,OAAO,OAAO,QAAQ;AAAA,QACtB,WAAW;AAAA,QACX,cAAc;AAAA,MAChB;AAAA,MACA,UAAQ;AAAA,MACR;AAAA,MACA,iBAAiB;AAAA,MACjB,YAAY;AAAA,QACV;AAAA,QACA,UAAU;AAAA,QACV;AAAA,QACA;AAAA,QACA,cAAc;AAAA,MAChB;AAAA,MACA,YAAY,CAAC,QACX;AAAA,QAAC;AAAA;AAAA,UACC,OAAO;AAAA,YACL,EAAE,OAAO,OAAO,QAAQ,MAAM,MAAM,0CAA0C,IAAI,EAAE,GAAG;AAAA,
|
|
4
|
+
"sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport Link from 'next/link'\nimport { useRouter } from 'next/navigation'\nimport type { ColumnDef, SortingState } from '@tanstack/react-table'\nimport type { PluggableList } from 'unified'\nimport ReactMarkdown from 'react-markdown'\nimport remarkGfm from 'remark-gfm'\nimport { Page, PageBody } from '@open-mercato/ui/backend/Page'\nimport { DataTable } from '@open-mercato/ui/backend/DataTable'\nimport { RowActions } from '@open-mercato/ui/backend/RowActions'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { readApiResultOrThrow } from '@open-mercato/ui/backend/utils/apiCall'\nimport { deleteCrud } from '@open-mercato/ui/backend/utils/crud'\nimport { flash } from '@open-mercato/ui/backend/FlashMessages'\nimport { normalizeCrudServerError } from '@open-mercato/ui/backend/utils/serverErrors'\nimport { useOrganizationScopeVersion } from '@open-mercato/shared/lib/frontend/useOrganizationScope'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\n\nconst PAGE_SIZE = 50\nconst MARKDOWN_PLUGINS: PluggableList = [remarkGfm]\nconst MARKDOWN_SUBTEXT_CLASSNAME =\n 'line-clamp-2 text-xs text-muted-foreground [&>p]:m-0 [&_ul]:ml-4 [&_ul]:list-disc [&_ol]:ml-4 [&_ol]:list-decimal [&_code]:rounded [&_code]:bg-muted [&_code]:px-1 [&_code]:py-0.5'\n\ntype RuleSetRow = {\n id: string\n name: string\n description: string | null\n timezone: string\n updatedAt: string | null\n}\n\ntype RuleSetResponse = {\n items?: Array<Record<string, unknown>>\n total?: number\n totalPages?: number\n}\n\nexport default function PlannerAvailabilityRuleSetsPage() {\n const t = useT()\n const router = useRouter()\n const scopeVersion = useOrganizationScopeVersion()\n const [rows, setRows] = React.useState<RuleSetRow[]>([])\n const [page, setPage] = React.useState(1)\n const [total, setTotal] = React.useState(0)\n const [totalPages, setTotalPages] = React.useState(1)\n const [sorting, setSorting] = React.useState<SortingState>([{ id: 'name', desc: false }])\n const [search, setSearch] = React.useState('')\n const [isLoading, setIsLoading] = React.useState(true)\n const [reloadToken, setReloadToken] = React.useState(0)\n\n const labels = React.useMemo(() => ({\n title: t('planner.availabilityRuleSets.page.title', 'Availability schedules'),\n description: t('planner.availabilityRuleSets.page.description', 'Manage shared availability rulesets.'),\n table: {\n name: t('planner.availabilityRuleSets.table.name', 'Name'),\n timezone: t('planner.availabilityRuleSets.table.timezone', 'Timezone'),\n updatedAt: t('planner.availabilityRuleSets.table.updatedAt', 'Updated'),\n empty: t('planner.availabilityRuleSets.table.empty', 'No schedules yet.'),\n search: t('planner.availabilityRuleSets.table.search', 'Search schedules...'),\n },\n actions: {\n add: t('planner.availabilityRuleSets.actions.add', 'New schedule'),\n edit: t('planner.availabilityRuleSets.actions.edit', 'Edit'),\n delete: t('planner.availabilityRuleSets.actions.delete', 'Delete'),\n deleteConfirm: t('planner.availabilityRuleSets.actions.deleteConfirm', 'Delete schedule \"{{name}}\"?'),\n refresh: t('planner.availabilityRuleSets.actions.refresh', 'Refresh'),\n },\n messages: {\n deleted: t('planner.availabilityRuleSets.messages.deleted', 'Schedule deleted.'),\n },\n errors: {\n load: t('planner.availabilityRuleSets.errors.load', 'Failed to load schedules.'),\n delete: t('planner.availabilityRuleSets.errors.delete', 'Failed to delete schedule.'),\n },\n }), [t])\n\n const loadRuleSets = React.useCallback(async () => {\n setIsLoading(true)\n try {\n const params = new URLSearchParams({\n page: String(page),\n pageSize: String(PAGE_SIZE),\n })\n const sort = sorting[0]\n if (sort?.id) {\n params.set('sortField', sort.id)\n params.set('sortDir', sort.desc ? 'desc' : 'asc')\n }\n if (search.trim()) params.set('search', search.trim())\n const payload = await readApiResultOrThrow<RuleSetResponse>(\n `/api/planner/availability-rule-sets?${params.toString()}`,\n undefined,\n { errorMessage: labels.errors.load, fallback: { items: [], total: 0, totalPages: 1 } },\n )\n const items = Array.isArray(payload.items) ? payload.items : []\n setRows(items.map(mapRuleSet))\n setTotal(typeof payload.total === 'number' ? payload.total : items.length)\n setTotalPages(typeof payload.totalPages === 'number' ? payload.totalPages : Math.max(1, Math.ceil(items.length / PAGE_SIZE)))\n } catch (error) {\n console.error('planner.availability-rule-sets.list', error)\n flash(labels.errors.load, 'error')\n } finally {\n setIsLoading(false)\n }\n }, [labels.errors.load, page, search, sorting])\n\n React.useEffect(() => {\n void loadRuleSets()\n }, [loadRuleSets, scopeVersion, reloadToken])\n\n const handleSearchChange = React.useCallback((value: string) => {\n setSearch(value)\n setPage(1)\n }, [])\n\n const handleRefresh = React.useCallback(() => {\n setReloadToken((token) => token + 1)\n }, [])\n\n const handleDelete = React.useCallback(async (entry: RuleSetRow) => {\n const message = labels.actions.deleteConfirm.replace('{{name}}', entry.name)\n if (typeof window !== 'undefined' && !window.confirm(message)) return\n try {\n await deleteCrud('planner/availability-rule-sets', entry.id, { errorMessage: labels.errors.delete })\n flash(labels.messages.deleted, 'success')\n handleRefresh()\n } catch (error) {\n console.error('planner.availability-rule-sets.delete', error)\n const normalized = normalizeCrudServerError(error)\n flash(normalized.message ?? labels.errors.delete, 'error')\n }\n }, [handleRefresh, labels.actions.deleteConfirm, labels.errors.delete, labels.messages.deleted])\n\n const columns = React.useMemo<ColumnDef<RuleSetRow>[]>(() => [\n {\n accessorKey: 'name',\n header: labels.table.name,\n meta: { priority: 1, sticky: true },\n cell: ({ row }) => (\n <div className=\"flex flex-col\">\n <span className=\"font-medium\">{row.original.name}</span>\n {row.original.description ? (\n <ReactMarkdown remarkPlugins={MARKDOWN_PLUGINS} className={MARKDOWN_SUBTEXT_CLASSNAME}>\n {row.original.description}\n </ReactMarkdown>\n ) : null}\n </div>\n ),\n },\n {\n accessorKey: 'timezone',\n header: labels.table.timezone,\n meta: { priority: 2 },\n cell: ({ row }) => <span className=\"text-sm\">{row.original.timezone}</span>,\n },\n {\n accessorKey: 'updatedAt',\n header: labels.table.updatedAt,\n meta: { priority: 3 },\n cell: ({ row }) => row.original.updatedAt\n ? <span className=\"text-xs text-muted-foreground\">{formatDateTime(row.original.updatedAt)}</span>\n : <span className=\"text-xs text-muted-foreground\">-</span>,\n },\n ], [labels.table.name, labels.table.timezone, labels.table.updatedAt])\n\n return (\n <Page>\n <PageBody>\n <DataTable<RuleSetRow>\n title={labels.title}\n data={rows}\n columns={columns}\n isLoading={isLoading}\n searchValue={search}\n onSearchChange={handleSearchChange}\n searchPlaceholder={labels.table.search}\n emptyState={<p className=\"py-8 text-center text-sm text-muted-foreground\">{labels.table.empty}</p>}\n actions={(\n <Button asChild size=\"sm\">\n <Link href=\"/backend/planner/availability-rulesets/create\">\n {labels.actions.add}\n </Link>\n </Button>\n )}\n refreshButton={{\n label: labels.actions.refresh,\n onRefresh: handleRefresh,\n isRefreshing: isLoading,\n }}\n sortable\n sorting={sorting}\n onSortingChange={setSorting}\n pagination={{\n page,\n pageSize: PAGE_SIZE,\n total,\n totalPages,\n onPageChange: setPage,\n }}\n rowActions={(row) => (\n <RowActions\n items={[\n { id: 'edit', label: labels.actions.edit, href: `/backend/planner/availability-rulesets/${row.id}` },\n { id: 'delete', label: labels.actions.delete, destructive: true, onSelect: () => { void handleDelete(row) } },\n ]}\n />\n )}\n onRowClick={(row) => router.push(`/backend/planner/availability-rulesets/${row.id}`)}\n />\n </PageBody>\n </Page>\n )\n}\n\nfunction mapRuleSet(item: Record<string, unknown>): RuleSetRow {\n const id = typeof item.id === 'string' ? item.id : ''\n const name = typeof item.name === 'string' ? item.name : id\n const description = typeof item.description === 'string' ? item.description : null\n const timezone = typeof item.timezone === 'string' ? item.timezone : 'UTC'\n const updatedAt =\n typeof item.updatedAt === 'string'\n ? item.updatedAt\n : typeof item.updated_at === 'string'\n ? item.updated_at\n : null\n return {\n id,\n name,\n description,\n timezone,\n updatedAt,\n }\n}\n\nfunction formatDateTime(value: string): string {\n const parsed = new Date(value)\n if (Number.isNaN(parsed.getTime())) return value\n return parsed.toLocaleString()\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -10,6 +10,43 @@ import { upsertIndexBatch } from "./lib/batch.js";
|
|
|
10
10
|
import { reindexEntity, DEFAULT_REINDEX_PARTITIONS } from "./lib/reindexer.js";
|
|
11
11
|
import { purgeIndexScope } from "./lib/purge.js";
|
|
12
12
|
import { flattenSystemEntityIds } from "@open-mercato/shared/lib/entities/system-entities";
|
|
13
|
+
function isIndexerVerbose() {
|
|
14
|
+
const parsed = parseBooleanToken(process.env.OM_INDEXER_VERBOSE ?? "");
|
|
15
|
+
return parsed === true;
|
|
16
|
+
}
|
|
17
|
+
function createGroupedProgress(label, partitionTargets) {
|
|
18
|
+
const totals = /* @__PURE__ */ new Map();
|
|
19
|
+
const processed = /* @__PURE__ */ new Map();
|
|
20
|
+
let bar = null;
|
|
21
|
+
const getTotals = () => {
|
|
22
|
+
let total = 0;
|
|
23
|
+
let done = 0;
|
|
24
|
+
for (const value of totals.values()) total += value;
|
|
25
|
+
for (const value of processed.values()) done += value;
|
|
26
|
+
return { total, done };
|
|
27
|
+
};
|
|
28
|
+
const tryInitBar = () => {
|
|
29
|
+
if (bar) return;
|
|
30
|
+
if (totals.size < partitionTargets.length) return;
|
|
31
|
+
const { total } = getTotals();
|
|
32
|
+
if (total <= 0) return;
|
|
33
|
+
bar = createProgressBar(label, total);
|
|
34
|
+
};
|
|
35
|
+
return {
|
|
36
|
+
onProgress(partition, info) {
|
|
37
|
+
processed.set(partition, info.processed);
|
|
38
|
+
if (!totals.has(partition)) totals.set(partition, info.total);
|
|
39
|
+
tryInitBar();
|
|
40
|
+
if (!bar) return;
|
|
41
|
+
const { done } = getTotals();
|
|
42
|
+
bar.update(done);
|
|
43
|
+
},
|
|
44
|
+
complete() {
|
|
45
|
+
if (bar) bar.complete();
|
|
46
|
+
},
|
|
47
|
+
getTotals
|
|
48
|
+
};
|
|
49
|
+
}
|
|
13
50
|
function parseArgs(rest) {
|
|
14
51
|
const args = {};
|
|
15
52
|
for (let i = 0; i < rest.length; i += 1) {
|
|
@@ -444,8 +481,11 @@ const reindex = {
|
|
|
444
481
|
await purgeIndexScope(baseEm, { entityType: entity, organizationId: orgId, tenantId });
|
|
445
482
|
}
|
|
446
483
|
console.log(`Reindexing ${entity}${force ? " (forced)" : ""} in ${partitionTargets.length} partition(s)...`);
|
|
447
|
-
const
|
|
484
|
+
const verbose = isIndexerVerbose();
|
|
485
|
+
const progressState = verbose ? /* @__PURE__ */ new Map() : null;
|
|
486
|
+
const groupedProgress = !verbose && partitionTargets.length > 1 ? createGroupedProgress(`Reindexing ${entity}`, partitionTargets) : null;
|
|
448
487
|
const renderProgress = (part, entityId, info) => {
|
|
488
|
+
if (!progressState) return;
|
|
449
489
|
const state = progressState.get(part) ?? { last: 0 };
|
|
450
490
|
const now = Date.now();
|
|
451
491
|
if (now - state.last < 1e3 && info.processed < info.total) return;
|
|
@@ -461,7 +501,7 @@ const reindex = {
|
|
|
461
501
|
const label = partitionTargets.length > 1 ? ` [partition ${part + 1}/${partitionCount}]` : "";
|
|
462
502
|
if (partitionTargets.length === 1) {
|
|
463
503
|
console.log(` -> processing${label}`);
|
|
464
|
-
} else if (idx === 0) {
|
|
504
|
+
} else if (verbose && idx === 0) {
|
|
465
505
|
console.log(` -> processing partitions in parallel (count=${partitionTargets.length})`);
|
|
466
506
|
}
|
|
467
507
|
const partitionContainer = await createRequestContainer();
|
|
@@ -489,9 +529,14 @@ const reindex = {
|
|
|
489
529
|
onProgress(info) {
|
|
490
530
|
if (useBar) {
|
|
491
531
|
if (info.total > 0 && !progressBar) {
|
|
492
|
-
progressBar = createProgressBar(
|
|
532
|
+
progressBar = createProgressBar(
|
|
533
|
+
`Reindexing ${entity}${label}`,
|
|
534
|
+
info.total
|
|
535
|
+
);
|
|
493
536
|
}
|
|
494
537
|
progressBar?.update(info.processed);
|
|
538
|
+
} else if (groupedProgress) {
|
|
539
|
+
groupedProgress.onProgress(part, info);
|
|
495
540
|
} else {
|
|
496
541
|
renderProgress(part, entity, info);
|
|
497
542
|
}
|
|
@@ -500,7 +545,9 @@ const reindex = {
|
|
|
500
545
|
if (progressBar) {
|
|
501
546
|
progressBar.complete();
|
|
502
547
|
}
|
|
503
|
-
if (!useBar) {
|
|
548
|
+
if (!useBar && groupedProgress) {
|
|
549
|
+
groupedProgress.onProgress(part, { processed: partitionStats.processed, total: partitionStats.total });
|
|
550
|
+
} else if (!useBar) {
|
|
504
551
|
renderProgress(part, entity, { processed: partitionStats.processed, total: partitionStats.total });
|
|
505
552
|
} else {
|
|
506
553
|
console.log(
|
|
@@ -515,6 +562,7 @@ const reindex = {
|
|
|
515
562
|
}
|
|
516
563
|
})
|
|
517
564
|
);
|
|
565
|
+
groupedProgress?.complete();
|
|
518
566
|
const totalProcessed = stats.reduce((acc, value) => acc + value, 0);
|
|
519
567
|
console.log(`Finished ${entity}: processed ${totalProcessed} row(s) across ${partitionTargets.length} partition(s)`);
|
|
520
568
|
await recordIndexerLog(
|
|
@@ -569,8 +617,11 @@ const reindex = {
|
|
|
569
617
|
console.log(
|
|
570
618
|
`[${idx + 1}/${entityIds.length}] Reindexing ${id}${force ? " (forced)" : ""} in ${partitionTargets.length} partition(s)...`
|
|
571
619
|
);
|
|
572
|
-
const
|
|
620
|
+
const verbose = isIndexerVerbose();
|
|
621
|
+
const progressState = verbose ? /* @__PURE__ */ new Map() : null;
|
|
622
|
+
const groupedProgress = !verbose && partitionTargets.length > 1 ? createGroupedProgress(`Reindexing ${id}`, partitionTargets) : null;
|
|
573
623
|
const renderProgress = (part, entityId, info) => {
|
|
624
|
+
if (!progressState) return;
|
|
574
625
|
const state = progressState.get(part) ?? { last: 0 };
|
|
575
626
|
const now = Date.now();
|
|
576
627
|
if (now - state.last < 1e3 && info.processed < info.total) return;
|
|
@@ -586,7 +637,7 @@ const reindex = {
|
|
|
586
637
|
const label = partitionTargets.length > 1 ? ` [partition ${part + 1}/${partitionCount}]` : "";
|
|
587
638
|
if (partitionTargets.length === 1) {
|
|
588
639
|
console.log(` -> processing${label}`);
|
|
589
|
-
} else if (partitionIdx === 0) {
|
|
640
|
+
} else if (verbose && partitionIdx === 0) {
|
|
590
641
|
console.log(` -> processing partitions in parallel (count=${partitionTargets.length})`);
|
|
591
642
|
}
|
|
592
643
|
const partitionContainer = await createRequestContainer();
|
|
@@ -617,6 +668,8 @@ const reindex = {
|
|
|
617
668
|
progressBar = createProgressBar(`Reindexing ${id}${label}`, info.total);
|
|
618
669
|
}
|
|
619
670
|
progressBar?.update(info.processed);
|
|
671
|
+
} else if (groupedProgress) {
|
|
672
|
+
groupedProgress.onProgress(part, info);
|
|
620
673
|
} else {
|
|
621
674
|
renderProgress(part, id, info);
|
|
622
675
|
}
|
|
@@ -625,7 +678,9 @@ const reindex = {
|
|
|
625
678
|
if (progressBar) {
|
|
626
679
|
progressBar.complete();
|
|
627
680
|
}
|
|
628
|
-
if (!useBar) {
|
|
681
|
+
if (!useBar && groupedProgress) {
|
|
682
|
+
groupedProgress.onProgress(part, { processed: result.processed, total: result.total });
|
|
683
|
+
} else if (!useBar) {
|
|
629
684
|
renderProgress(part, id, { processed: result.processed, total: result.total });
|
|
630
685
|
} else {
|
|
631
686
|
console.log(
|
|
@@ -640,6 +695,7 @@ const reindex = {
|
|
|
640
695
|
}
|
|
641
696
|
})
|
|
642
697
|
);
|
|
698
|
+
groupedProgress?.complete();
|
|
643
699
|
const totalProcessed = partitionResults.reduce((acc, value) => acc + value, 0);
|
|
644
700
|
console.log(` -> ${id} complete: processed ${totalProcessed} row(s) across ${partitionTargets.length} partition(s)`);
|
|
645
701
|
await recordIndexerLog(
|