@open-mercato/core 0.4.2-canary-da2b080494 → 0.4.2-canary-19703ca707
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 -1
- package/dist/generated/entities.ids.generated.js.map +2 -2
- package/dist/generated/entity-fields-registry.js +2 -0
- 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 +85 -1
- 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/lib/rule-engine.js +33 -3
- 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/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/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 +68 -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/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/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/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/commands/documents.js +53 -0
- 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/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/backend/definitions/page.js +5 -0
- package/dist/modules/workflows/backend/definitions/page.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/page.js +3 -0
- package/dist/modules/workflows/backend/tasks/page.js.map +2 -2
- package/dist/modules/workflows/cli.js +12 -12
- package/dist/modules/workflows/cli.js.map +2 -2
- package/dist/modules/workflows/lib/transition-handler.js +14 -6
- package/dist/modules/workflows/lib/transition-handler.js.map +2 -2
- 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 -1
- package/generated/entity-fields-registry.ts +2 -0
- 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 +106 -2
- 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/i18n/en.json +3 -1
- package/src/modules/business_rules/lib/__tests__/rule-engine.test.ts +51 -0
- package/src/modules/business_rules/lib/rule-engine.ts +57 -3
- 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/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/dictionaries/components/DictionaryTable.tsx +2 -0
- package/src/modules/directory/api/get/tenants/lookup.ts +73 -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 +300 -0
- package/src/modules/notifications/migrations/Migration20260123000001.ts +73 -0
- package/src/modules/notifications/migrations/Migration20260126150000.ts +39 -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/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/backend/sales/channels/offers/page.tsx +2 -0
- package/src/modules/sales/backend/sales/channels/page.tsx +2 -0
- package/src/modules/sales/commands/documents.ts +65 -0
- 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/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/backend/definitions/page.tsx +5 -0
- package/src/modules/workflows/backend/instances/page.tsx +4 -1
- package/src/modules/workflows/backend/tasks/page.tsx +4 -1
- package/src/modules/workflows/cli.ts +12 -12
- package/src/modules/workflows/i18n/en.json +3 -1
- package/src/modules/workflows/lib/transition-handler.ts +18 -6
- package/src/modules/workflows/notifications.ts +25 -0
- package/src/modules/workflows/subscribers/task-assigned-notification.ts +53 -0
|
@@ -4,6 +4,7 @@ import type { EntityManager } from '@mikro-orm/postgresql'
|
|
|
4
4
|
import { DashboardRoleWidgets } from '@open-mercato/core/modules/dashboards/data/entities'
|
|
5
5
|
import { Role } from '@open-mercato/core/modules/auth/data/entities'
|
|
6
6
|
import { loadAllWidgets } from '@open-mercato/core/modules/dashboards/lib/widgets'
|
|
7
|
+
import { appendWidgetsToRoles, resolveAnalyticsWidgetIds } from '@open-mercato/core/modules/dashboards/lib/role-widgets'
|
|
7
8
|
import { seedAnalyticsData } from './seed/analytics'
|
|
8
9
|
|
|
9
10
|
type Args = Record<string, string>
|
|
@@ -41,15 +42,25 @@ export async function seedDashboardDefaultsForTenant(
|
|
|
41
42
|
const widgetMap = new Map(widgets.map((widget) => [widget.metadata.id, widget]))
|
|
42
43
|
const resolvedWidgetIds = widgetIds && widgetIds.length
|
|
43
44
|
? widgetIds.filter((id) => widgetMap.has(id))
|
|
44
|
-
:
|
|
45
|
+
: null
|
|
46
|
+
const defaultWidgetIds = widgets
|
|
47
|
+
.filter((widget) => widget.metadata.defaultEnabled)
|
|
48
|
+
.map((widget) => widget.metadata.id)
|
|
49
|
+
const allWidgetIds = widgets.map((widget) => widget.metadata.id)
|
|
45
50
|
|
|
46
|
-
if (
|
|
51
|
+
if (resolvedWidgetIds && resolvedWidgetIds.length === 0) {
|
|
47
52
|
log('No widgets resolved for dashboard seeding.')
|
|
48
53
|
return false
|
|
49
54
|
}
|
|
50
55
|
|
|
51
56
|
await em.transactional(async (tem) => {
|
|
52
57
|
for (const roleName of roleNames) {
|
|
58
|
+
const isAdminRole = roleName === 'admin' || roleName === 'superadmin'
|
|
59
|
+
const roleWidgetIds = resolvedWidgetIds ?? (isAdminRole ? allWidgetIds : defaultWidgetIds)
|
|
60
|
+
if (!roleWidgetIds.length) {
|
|
61
|
+
log(`No widgets resolved for role "${roleName}".`)
|
|
62
|
+
continue
|
|
63
|
+
}
|
|
53
64
|
const role = await tem.findOne(Role, { name: roleName })
|
|
54
65
|
if (!role) {
|
|
55
66
|
log(`Skipping role "${roleName}" (not found)`)
|
|
@@ -62,7 +73,7 @@ export async function seedDashboardDefaultsForTenant(
|
|
|
62
73
|
deletedAt: null,
|
|
63
74
|
})
|
|
64
75
|
if (existing) {
|
|
65
|
-
existing.widgetIdsJson =
|
|
76
|
+
existing.widgetIdsJson = roleWidgetIds
|
|
66
77
|
tem.persist(existing)
|
|
67
78
|
log(`Updated dashboard widgets for role "${roleName}"`)
|
|
68
79
|
} else {
|
|
@@ -70,7 +81,7 @@ export async function seedDashboardDefaultsForTenant(
|
|
|
70
81
|
roleId: String(role.id),
|
|
71
82
|
tenantId,
|
|
72
83
|
organizationId,
|
|
73
|
-
widgetIdsJson:
|
|
84
|
+
widgetIdsJson: roleWidgetIds,
|
|
74
85
|
createdAt: new Date(),
|
|
75
86
|
updatedAt: null,
|
|
76
87
|
deletedAt: null,
|
|
@@ -120,6 +131,45 @@ const seedDefaults: ModuleCli = {
|
|
|
120
131
|
},
|
|
121
132
|
}
|
|
122
133
|
|
|
134
|
+
const enableAnalyticsWidgets: ModuleCli = {
|
|
135
|
+
command: 'enable-analytics-widgets',
|
|
136
|
+
async run(rest) {
|
|
137
|
+
const args = parseArgs(rest)
|
|
138
|
+
const tenantId = args.tenant || args.tenantId || null
|
|
139
|
+
const organizationId = args.organization || args.organizationId || args.org || null
|
|
140
|
+
const roleCsv = args.roles || 'admin,employee'
|
|
141
|
+
if (!tenantId) {
|
|
142
|
+
console.error('Usage: mercato dashboards enable-analytics-widgets --tenant <tenantId> [--org <orgId>] [--roles admin,employee]')
|
|
143
|
+
return
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
const roleNames = roleCsv
|
|
147
|
+
.split(',')
|
|
148
|
+
.map((name) => name.trim())
|
|
149
|
+
.filter(Boolean)
|
|
150
|
+
|
|
151
|
+
if (!roleNames.length) {
|
|
152
|
+
console.log('No roles provided, nothing to update.')
|
|
153
|
+
return
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
const { resolve } = await createRequestContainer()
|
|
157
|
+
const em = resolve('em') as EntityManager
|
|
158
|
+
const widgetIds = await resolveAnalyticsWidgetIds()
|
|
159
|
+
|
|
160
|
+
const updated = await appendWidgetsToRoles(em, {
|
|
161
|
+
tenantId,
|
|
162
|
+
organizationId,
|
|
163
|
+
roleNames,
|
|
164
|
+
widgetIds,
|
|
165
|
+
})
|
|
166
|
+
|
|
167
|
+
if (!updated) {
|
|
168
|
+
console.log('No dashboard role widgets updated.')
|
|
169
|
+
}
|
|
170
|
+
},
|
|
171
|
+
}
|
|
172
|
+
|
|
123
173
|
const seedAnalytics: ModuleCli = {
|
|
124
174
|
command: 'seed-analytics',
|
|
125
175
|
async run(rest) {
|
|
@@ -282,4 +332,4 @@ const debugAnalytics: ModuleCli = {
|
|
|
282
332
|
},
|
|
283
333
|
}
|
|
284
334
|
|
|
285
|
-
export default [seedDefaults, seedAnalytics, debugAnalytics]
|
|
335
|
+
export default [seedDefaults, enableAnalyticsWidgets, seedAnalytics, debugAnalytics]
|
|
@@ -44,9 +44,13 @@ type UserProps = BaseProps & {
|
|
|
44
44
|
|
|
45
45
|
type WidgetVisibilityEditorProps = RoleProps | UserProps
|
|
46
46
|
|
|
47
|
+
export type WidgetVisibilityEditorHandle = {
|
|
48
|
+
save: () => Promise<void>
|
|
49
|
+
}
|
|
50
|
+
|
|
47
51
|
const EMPTY: string[] = []
|
|
48
52
|
|
|
49
|
-
export function WidgetVisibilityEditor(props
|
|
53
|
+
export const WidgetVisibilityEditor = React.forwardRef<WidgetVisibilityEditorHandle, WidgetVisibilityEditorProps>(function WidgetVisibilityEditor(props, ref) {
|
|
50
54
|
const t = useT()
|
|
51
55
|
const { kind, targetId, tenantId, organizationId } = props
|
|
52
56
|
const [catalog, setCatalog] = React.useState<WidgetCatalogItem[]>([])
|
|
@@ -60,6 +64,15 @@ export function WidgetVisibilityEditor(props: WidgetVisibilityEditorProps) {
|
|
|
60
64
|
const [originalMode, setOriginalMode] = React.useState<'inherit' | 'override'>('inherit')
|
|
61
65
|
const [effective, setEffective] = React.useState<string[]>(EMPTY)
|
|
62
66
|
|
|
67
|
+
const dirty = React.useMemo(() => {
|
|
68
|
+
if (kind === 'user') {
|
|
69
|
+
if (mode !== originalMode) return true
|
|
70
|
+
if (mode === 'override') return selected.join('|') !== original.join('|')
|
|
71
|
+
return false
|
|
72
|
+
}
|
|
73
|
+
return selected.join('|') !== original.join('|')
|
|
74
|
+
}, [kind, mode, original, originalMode, selected])
|
|
75
|
+
|
|
63
76
|
const loadCatalog = React.useCallback(async () => {
|
|
64
77
|
const data = await readApiResultOrThrow<{ items?: unknown[] }>(
|
|
65
78
|
'/api/dashboards/widgets/catalog',
|
|
@@ -149,6 +162,9 @@ export function WidgetVisibilityEditor(props: WidgetVisibilityEditorProps) {
|
|
|
149
162
|
}, [original, originalMode])
|
|
150
163
|
|
|
151
164
|
const save = React.useCallback(async () => {
|
|
165
|
+
if (loading) return
|
|
166
|
+
if (error && catalog.length === 0) return
|
|
167
|
+
if (!dirty) return
|
|
152
168
|
setSaving(true)
|
|
153
169
|
setError(null)
|
|
154
170
|
try {
|
|
@@ -202,16 +218,9 @@ export function WidgetVisibilityEditor(props: WidgetVisibilityEditorProps) {
|
|
|
202
218
|
} finally {
|
|
203
219
|
setSaving(false)
|
|
204
220
|
}
|
|
205
|
-
}, [kind, mode, organizationId, selected, t, targetId, tenantId])
|
|
221
|
+
}, [catalog.length, dirty, error, kind, loading, mode, organizationId, selected, t, targetId, tenantId])
|
|
206
222
|
|
|
207
|
-
|
|
208
|
-
if (kind === 'user') {
|
|
209
|
-
if (mode !== originalMode) return true
|
|
210
|
-
if (mode === 'override') return selected.join('|') !== original.join('|')
|
|
211
|
-
return false
|
|
212
|
-
}
|
|
213
|
-
return selected.join('|') !== original.join('|')
|
|
214
|
-
}, [kind, mode, original, originalMode, selected])
|
|
223
|
+
React.useImperativeHandle(ref, () => ({ save }), [save])
|
|
215
224
|
|
|
216
225
|
if (loading) {
|
|
217
226
|
return (
|
|
@@ -297,4 +306,6 @@ export function WidgetVisibilityEditor(props: WidgetVisibilityEditorProps) {
|
|
|
297
306
|
</div>
|
|
298
307
|
</div>
|
|
299
308
|
)
|
|
300
|
-
}
|
|
309
|
+
})
|
|
310
|
+
|
|
311
|
+
WidgetVisibilityEditor.displayName = 'WidgetVisibilityEditor'
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import type { EntityManager } from '@mikro-orm/postgresql'
|
|
2
|
+
import { Role } from '@open-mercato/core/modules/auth/data/entities'
|
|
3
|
+
import { DashboardRoleWidgets } from '../data/entities'
|
|
4
|
+
import { loadAllWidgets } from './widgets'
|
|
5
|
+
|
|
6
|
+
type RoleWidgetScope = {
|
|
7
|
+
tenantId: string
|
|
8
|
+
organizationId?: string | null
|
|
9
|
+
roleNames: string[]
|
|
10
|
+
widgetIds: string[]
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
async function findRoleByName(
|
|
14
|
+
em: EntityManager,
|
|
15
|
+
roleName: string,
|
|
16
|
+
tenantId: string,
|
|
17
|
+
): Promise<Role | null> {
|
|
18
|
+
const tenantRole = await em.findOne(Role, { name: roleName, tenantId })
|
|
19
|
+
if (tenantRole) return tenantRole
|
|
20
|
+
return em.findOne(Role, { name: roleName, tenantId: null })
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export async function resolveAnalyticsWidgetIds(): Promise<string[]> {
|
|
24
|
+
const widgets = await loadAllWidgets()
|
|
25
|
+
return widgets
|
|
26
|
+
.filter((widget) => widget.metadata.category === 'analytics' || widget.metadata.id.startsWith('dashboards.analytics.'))
|
|
27
|
+
.map((widget) => widget.metadata.id)
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export async function appendWidgetsToRoles(
|
|
31
|
+
em: EntityManager,
|
|
32
|
+
{ tenantId, organizationId = null, roleNames, widgetIds }: RoleWidgetScope,
|
|
33
|
+
): Promise<boolean> {
|
|
34
|
+
const trimmedTenantId = tenantId.trim()
|
|
35
|
+
const widgets = await loadAllWidgets()
|
|
36
|
+
const validWidgetIds = new Set(widgets.map((widget) => widget.metadata.id))
|
|
37
|
+
const resolvedWidgetIds = widgetIds.filter((id) => validWidgetIds.has(id))
|
|
38
|
+
if (!resolvedWidgetIds.length) return false
|
|
39
|
+
|
|
40
|
+
let updated = false
|
|
41
|
+
await em.transactional(async (tem) => {
|
|
42
|
+
for (const roleName of roleNames) {
|
|
43
|
+
const role = await findRoleByName(tem, roleName, trimmedTenantId)
|
|
44
|
+
if (!role) continue
|
|
45
|
+
|
|
46
|
+
const record = await tem.findOne(DashboardRoleWidgets, {
|
|
47
|
+
roleId: String(role.id),
|
|
48
|
+
tenantId: trimmedTenantId,
|
|
49
|
+
organizationId,
|
|
50
|
+
deletedAt: null,
|
|
51
|
+
})
|
|
52
|
+
const roleRecord = record ?? (organizationId
|
|
53
|
+
? await tem.findOne(DashboardRoleWidgets, {
|
|
54
|
+
roleId: String(role.id),
|
|
55
|
+
tenantId: trimmedTenantId,
|
|
56
|
+
organizationId: null,
|
|
57
|
+
deletedAt: null,
|
|
58
|
+
})
|
|
59
|
+
: null)
|
|
60
|
+
if (!roleRecord) continue
|
|
61
|
+
|
|
62
|
+
const current = Array.isArray(roleRecord.widgetIdsJson) ? roleRecord.widgetIdsJson : []
|
|
63
|
+
const next = [...current]
|
|
64
|
+
const existing = new Set(current)
|
|
65
|
+
for (const widgetId of resolvedWidgetIds) {
|
|
66
|
+
if (existing.has(widgetId)) continue
|
|
67
|
+
existing.add(widgetId)
|
|
68
|
+
next.push(widgetId)
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
if (next.length === current.length) continue
|
|
72
|
+
roleRecord.widgetIdsJson = next
|
|
73
|
+
roleRecord.updatedAt = new Date()
|
|
74
|
+
tem.persist(roleRecord)
|
|
75
|
+
updated = true
|
|
76
|
+
}
|
|
77
|
+
})
|
|
78
|
+
|
|
79
|
+
return updated
|
|
80
|
+
}
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
import type { EntityManager } from '@mikro-orm/postgresql'
|
|
2
2
|
import type { CacheStrategy } from '@open-mercato/cache'
|
|
3
3
|
import { createHash } from 'node:crypto'
|
|
4
|
+
import { decryptWithAesGcm } from '@open-mercato/shared/lib/encryption/aes'
|
|
5
|
+
import { resolveTenantEncryptionService } from '@open-mercato/shared/lib/encryption/customFieldValues'
|
|
6
|
+
import { resolveEntityIdFromMetadata } from '@open-mercato/shared/lib/encryption/entityIds'
|
|
7
|
+
import { findWithDecryption } from '@open-mercato/shared/lib/encryption/find'
|
|
4
8
|
import {
|
|
5
9
|
type DateRangePreset,
|
|
6
10
|
resolveDateRange,
|
|
@@ -17,6 +21,8 @@ import {
|
|
|
17
21
|
import type { AnalyticsRegistry } from './analyticsRegistry'
|
|
18
22
|
|
|
19
23
|
const WIDGET_DATA_CACHE_TTL = 120_000
|
|
24
|
+
const WIDGET_DATA_SEGMENT_TTL = 86_400_000
|
|
25
|
+
const WIDGET_DATA_SEGMENT_KEY = 'widget-data:__segment__'
|
|
20
26
|
|
|
21
27
|
const SAFE_IDENTIFIER_PATTERN = /^[a-zA-Z_][a-zA-Z0-9_]*$/
|
|
22
28
|
|
|
@@ -168,6 +174,11 @@ export class WidgetDataService {
|
|
|
168
174
|
const tags = this.getCacheTags(request.entityType)
|
|
169
175
|
try {
|
|
170
176
|
await this.cache.set(cacheKey, response, { ttl: WIDGET_DATA_CACHE_TTL, tags })
|
|
177
|
+
await this.cache.set(
|
|
178
|
+
WIDGET_DATA_SEGMENT_KEY,
|
|
179
|
+
{ updatedAt: response.metadata.fetchedAt },
|
|
180
|
+
{ ttl: WIDGET_DATA_SEGMENT_TTL, tags: ['widget-data'] },
|
|
181
|
+
)
|
|
171
182
|
} catch {
|
|
172
183
|
}
|
|
173
184
|
}
|
|
@@ -282,6 +293,75 @@ export class WidgetDataService {
|
|
|
282
293
|
assertSafeIdentifier(config.idColumn, 'id column')
|
|
283
294
|
assertSafeIdentifier(config.labelColumn, 'label column')
|
|
284
295
|
|
|
296
|
+
const meta = this.resolveEntityMetadata(config.table)
|
|
297
|
+
const idProp = meta ? this.resolveEntityPropertyName(meta, config.idColumn) : null
|
|
298
|
+
const labelProp = meta ? this.resolveEntityPropertyName(meta, config.labelColumn) : null
|
|
299
|
+
const tenantProp = meta
|
|
300
|
+
? (this.resolveEntityPropertyName(meta, 'tenant_id') ?? this.resolveEntityPropertyName(meta, 'tenantId'))
|
|
301
|
+
: null
|
|
302
|
+
const organizationProp = meta
|
|
303
|
+
? (this.resolveEntityPropertyName(meta, 'organization_id') ?? this.resolveEntityPropertyName(meta, 'organizationId'))
|
|
304
|
+
: null
|
|
305
|
+
const entityName = meta ? ((meta as any).class ?? meta.className ?? meta.name) : null
|
|
306
|
+
|
|
307
|
+
if (meta && idProp && labelProp && tenantProp && entityName) {
|
|
308
|
+
const where: Record<string, unknown> = {
|
|
309
|
+
[idProp]: { $in: uniqueIds },
|
|
310
|
+
[tenantProp]: this.scope.tenantId,
|
|
311
|
+
}
|
|
312
|
+
if (organizationProp && this.scope.organizationIds && this.scope.organizationIds.length > 0) {
|
|
313
|
+
where[organizationProp] = { $in: this.scope.organizationIds }
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
try {
|
|
317
|
+
const records = await findWithDecryption(
|
|
318
|
+
this.em,
|
|
319
|
+
entityName,
|
|
320
|
+
where,
|
|
321
|
+
{ fields: [idProp, labelProp, tenantProp, organizationProp].filter(Boolean) },
|
|
322
|
+
{ tenantId: this.scope.tenantId, organizationId: this.resolveOrganizationId() },
|
|
323
|
+
)
|
|
324
|
+
|
|
325
|
+
const encryptionService = resolveTenantEncryptionService(this.em as any)
|
|
326
|
+
const dek = encryptionService?.isEnabled() ? await encryptionService.getDek(this.scope.tenantId) : null
|
|
327
|
+
let hasEncryptedLabels = false
|
|
328
|
+
let hasDecryptedLabels = false
|
|
329
|
+
|
|
330
|
+
const labelMap = new Map<string, string>()
|
|
331
|
+
for (const record of records as Array<Record<string, unknown>>) {
|
|
332
|
+
const id = record[idProp]
|
|
333
|
+
let labelValue = record[labelProp]
|
|
334
|
+
if (typeof labelValue === 'string' && this.isEncryptedPayload(labelValue)) {
|
|
335
|
+
hasEncryptedLabels = true
|
|
336
|
+
if (dek?.key) {
|
|
337
|
+
const decrypted = this.decryptWithDek(labelValue, dek.key)
|
|
338
|
+
if (decrypted !== null) {
|
|
339
|
+
labelValue = decrypted
|
|
340
|
+
hasDecryptedLabels = true
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
} else if (labelValue != null && labelValue !== '') {
|
|
344
|
+
hasDecryptedLabels = true
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
if (typeof id === 'string' && labelValue != null && labelValue !== '') {
|
|
348
|
+
labelMap.set(id, String(labelValue))
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
if (labelMap.size > 0 && (!hasEncryptedLabels || hasDecryptedLabels)) {
|
|
353
|
+
return data.map((item) => ({
|
|
354
|
+
...item,
|
|
355
|
+
groupLabel: typeof item.groupKey === 'string' && labelMap.has(item.groupKey)
|
|
356
|
+
? labelMap.get(item.groupKey)!
|
|
357
|
+
: undefined,
|
|
358
|
+
}))
|
|
359
|
+
}
|
|
360
|
+
} catch {
|
|
361
|
+
// fall through to SQL resolution
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
|
|
285
365
|
const clauses = [`"${config.idColumn}" = ANY(?::uuid[])`, 'tenant_id = ?']
|
|
286
366
|
const params: unknown[] = [`{${uniqueIds.join(',')}}`, this.scope.tenantId]
|
|
287
367
|
|
|
@@ -290,17 +370,43 @@ export class WidgetDataService {
|
|
|
290
370
|
params.push(`{${this.scope.organizationIds.join(',')}}`)
|
|
291
371
|
}
|
|
292
372
|
|
|
293
|
-
const sql = `SELECT "${config.idColumn}" as id, "${config.labelColumn}" as label FROM "${config.table}" WHERE ${clauses.join(
|
|
373
|
+
const sql = `SELECT "${config.idColumn}" as id, "${config.labelColumn}" as label, tenant_id, organization_id FROM "${config.table}" WHERE ${clauses.join(
|
|
294
374
|
' AND ',
|
|
295
375
|
)}`
|
|
296
376
|
|
|
297
377
|
try {
|
|
298
378
|
const labelRows = await this.em.getConnection().execute(sql, params)
|
|
379
|
+
const entityId = this.resolveEntityId(meta)
|
|
380
|
+
const encryptionService = resolveTenantEncryptionService(this.em as any)
|
|
381
|
+
const organizationId = this.resolveOrganizationId()
|
|
382
|
+
const dek = encryptionService?.isEnabled() ? await encryptionService.getDek(this.scope.tenantId) : null
|
|
299
383
|
|
|
300
384
|
const labelMap = new Map<string, string>()
|
|
301
|
-
for (const row of labelRows as Array<{ id: string; label: string | null }>) {
|
|
302
|
-
|
|
303
|
-
|
|
385
|
+
for (const row of labelRows as Array<{ id: string; label: string | null; tenant_id?: string | null; organization_id?: string | null }>) {
|
|
386
|
+
let labelValue = row.label
|
|
387
|
+
if (entityId && encryptionService?.isEnabled() && labelValue != null) {
|
|
388
|
+
const rowOrgId = row.organization_id ?? organizationId ?? null
|
|
389
|
+
const decrypted = await encryptionService.decryptEntityPayload(
|
|
390
|
+
entityId,
|
|
391
|
+
{ [config.labelColumn]: labelValue },
|
|
392
|
+
this.scope.tenantId,
|
|
393
|
+
rowOrgId,
|
|
394
|
+
)
|
|
395
|
+
const resolved = decrypted[config.labelColumn]
|
|
396
|
+
if (typeof resolved === 'string' || typeof resolved === 'number') {
|
|
397
|
+
labelValue = String(resolved)
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
if (labelValue && dek?.key && this.isEncryptedPayload(labelValue)) {
|
|
402
|
+
const decrypted = this.decryptWithDek(labelValue, dek.key)
|
|
403
|
+
if (decrypted !== null) {
|
|
404
|
+
labelValue = decrypted
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
if (row.id && labelValue != null && labelValue !== '') {
|
|
409
|
+
labelMap.set(row.id, labelValue)
|
|
304
410
|
}
|
|
305
411
|
}
|
|
306
412
|
|
|
@@ -317,6 +423,60 @@ export class WidgetDataService {
|
|
|
317
423
|
}))
|
|
318
424
|
}
|
|
319
425
|
}
|
|
426
|
+
|
|
427
|
+
private resolveOrganizationId(): string | null {
|
|
428
|
+
if (!this.scope.organizationIds || this.scope.organizationIds.length !== 1) return null
|
|
429
|
+
return this.scope.organizationIds[0] ?? null
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
private resolveEntityMetadata(tableName: string): Record<string, any> | null {
|
|
433
|
+
const registry = (this.em as any)?.getMetadata?.()
|
|
434
|
+
if (!registry) return null
|
|
435
|
+
const entries =
|
|
436
|
+
(typeof registry.getAll === 'function' && registry.getAll()) ||
|
|
437
|
+
(Array.isArray(registry.metadata) ? registry.metadata : Object.values(registry.metadata ?? {}))
|
|
438
|
+
const metas = Array.isArray(entries) ? entries : Object.values(entries ?? {})
|
|
439
|
+
const match = metas.find((meta: any) => {
|
|
440
|
+
const table = meta?.tableName ?? meta?.collection
|
|
441
|
+
if (typeof table !== 'string') return false
|
|
442
|
+
if (table === tableName) return true
|
|
443
|
+
return table.split('.').pop() === tableName
|
|
444
|
+
})
|
|
445
|
+
return match ?? null
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
private resolveEntityPropertyName(meta: Record<string, any>, columnName: string): string | null {
|
|
449
|
+
const properties = meta?.properties ? Object.values(meta.properties) : []
|
|
450
|
+
for (const prop of properties as Array<Record<string, any>>) {
|
|
451
|
+
const fieldName = prop?.fieldName
|
|
452
|
+
const fieldNames = prop?.fieldNames
|
|
453
|
+
if (typeof fieldName === 'string' && fieldName === columnName) return prop?.name ?? null
|
|
454
|
+
if (Array.isArray(fieldNames) && fieldNames.includes(columnName)) return prop?.name ?? null
|
|
455
|
+
if (prop?.name === columnName) return prop?.name ?? null
|
|
456
|
+
}
|
|
457
|
+
return null
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
private resolveEntityId(meta: Record<string, any> | null): string | null {
|
|
461
|
+
if (!meta) return null
|
|
462
|
+
try {
|
|
463
|
+
return resolveEntityIdFromMetadata(meta as any)
|
|
464
|
+
} catch {
|
|
465
|
+
return null
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
private isEncryptedPayload(value: string): boolean {
|
|
470
|
+
const parts = value.split(':')
|
|
471
|
+
return parts.length === 4 && parts[3] === 'v1'
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
private decryptWithDek(value: string, dek: string): string | null {
|
|
475
|
+
const first = decryptWithAesGcm(value, dek)
|
|
476
|
+
if (first === null) return null
|
|
477
|
+
if (!this.isEncryptedPayload(first)) return first
|
|
478
|
+
return decryptWithAesGcm(first, dek) ?? first
|
|
479
|
+
}
|
|
320
480
|
}
|
|
321
481
|
|
|
322
482
|
export function createWidgetDataService(
|
|
@@ -171,12 +171,14 @@ export function DictionaryTable({
|
|
|
171
171
|
const items: RowActionItem[] = []
|
|
172
172
|
if (onEdit) {
|
|
173
173
|
items.push({
|
|
174
|
+
id: 'edit',
|
|
174
175
|
label: translations.editLabel,
|
|
175
176
|
onSelect: () => onEdit(entry),
|
|
176
177
|
})
|
|
177
178
|
}
|
|
178
179
|
if (onDelete) {
|
|
179
180
|
items.push({
|
|
181
|
+
id: 'delete',
|
|
180
182
|
label: translations.deleteLabel,
|
|
181
183
|
onSelect: () => onDelete(entry),
|
|
182
184
|
destructive: true,
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { NextResponse } from 'next/server'
|
|
2
|
+
import { z } from 'zod'
|
|
3
|
+
import type { EntityManager } from '@mikro-orm/postgresql'
|
|
4
|
+
import { createRequestContainer } from '@open-mercato/shared/lib/di/container'
|
|
5
|
+
import { Tenant } from '@open-mercato/core/modules/directory/data/entities'
|
|
6
|
+
import type { OpenApiMethodDoc, OpenApiRouteDoc } from '@open-mercato/shared/lib/openapi'
|
|
7
|
+
|
|
8
|
+
export const metadata = {
|
|
9
|
+
GET: {
|
|
10
|
+
requireAuth: false,
|
|
11
|
+
},
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const tenantLookupQuerySchema = z.object({
|
|
15
|
+
tenantId: z.string().uuid(),
|
|
16
|
+
})
|
|
17
|
+
|
|
18
|
+
export async function GET(req: Request) {
|
|
19
|
+
const url = new URL(req.url)
|
|
20
|
+
const tenantId = url.searchParams.get('tenantId') || url.searchParams.get('tenant') || ''
|
|
21
|
+
const parsed = tenantLookupQuerySchema.safeParse({ tenantId })
|
|
22
|
+
if (!parsed.success) {
|
|
23
|
+
return NextResponse.json({ ok: false, error: 'Invalid tenant id.' }, { status: 400 })
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const container = await createRequestContainer()
|
|
27
|
+
const em = (container.resolve('em') as EntityManager)
|
|
28
|
+
const tenant = await em.findOne(Tenant, { id: parsed.data.tenantId, deletedAt: null })
|
|
29
|
+
if (!tenant) {
|
|
30
|
+
return NextResponse.json({ ok: false, error: 'Tenant not found.' }, { status: 404 })
|
|
31
|
+
}
|
|
32
|
+
return NextResponse.json({
|
|
33
|
+
ok: true,
|
|
34
|
+
tenant: { id: String(tenant.id), name: tenant.name },
|
|
35
|
+
})
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const lookupTag = 'Directory'
|
|
39
|
+
|
|
40
|
+
const tenantLookupSuccessSchema = z.object({
|
|
41
|
+
ok: z.literal(true),
|
|
42
|
+
tenant: z.object({
|
|
43
|
+
id: z.string().uuid(),
|
|
44
|
+
name: z.string(),
|
|
45
|
+
}),
|
|
46
|
+
})
|
|
47
|
+
|
|
48
|
+
const tenantLookupErrorSchema = z.object({
|
|
49
|
+
ok: z.literal(false),
|
|
50
|
+
error: z.string(),
|
|
51
|
+
})
|
|
52
|
+
|
|
53
|
+
const tenantLookupDoc: OpenApiMethodDoc = {
|
|
54
|
+
summary: 'Public tenant lookup',
|
|
55
|
+
description: 'Resolves tenant metadata for login/activation flows.',
|
|
56
|
+
tags: [lookupTag],
|
|
57
|
+
query: tenantLookupQuerySchema,
|
|
58
|
+
responses: [
|
|
59
|
+
{ status: 200, description: 'Tenant resolved.', schema: tenantLookupSuccessSchema },
|
|
60
|
+
],
|
|
61
|
+
errors: [
|
|
62
|
+
{ status: 400, description: 'Invalid tenant id', schema: tenantLookupErrorSchema },
|
|
63
|
+
{ status: 404, description: 'Tenant not found', schema: tenantLookupErrorSchema },
|
|
64
|
+
],
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export const openApi: OpenApiRouteDoc = {
|
|
68
|
+
tag: lookupTag,
|
|
69
|
+
summary: 'Public tenant lookup',
|
|
70
|
+
methods: {
|
|
71
|
+
GET: tenantLookupDoc,
|
|
72
|
+
},
|
|
73
|
+
}
|
|
@@ -235,8 +235,8 @@ export default function DirectoryOrganizationsPage() {
|
|
|
235
235
|
canManage ? (
|
|
236
236
|
<RowActions
|
|
237
237
|
items={[
|
|
238
|
-
{ label: t('directory.organizations.list.actions.edit', 'Edit'), href: `/backend/directory/organizations/${row.id}/edit` },
|
|
239
|
-
{ label: t('directory.organizations.list.actions.delete', 'Delete'), destructive: true, onSelect: () => handleDelete(row) },
|
|
238
|
+
{ id: 'edit', label: t('directory.organizations.list.actions.edit', 'Edit'), href: `/backend/directory/organizations/${row.id}/edit` },
|
|
239
|
+
{ id: 'delete', label: t('directory.organizations.list.actions.delete', 'Delete'), destructive: true, onSelect: () => handleDelete(row) },
|
|
240
240
|
]}
|
|
241
241
|
/>
|
|
242
242
|
) : null
|
|
@@ -160,8 +160,8 @@ export default function DirectoryTenantsPage() {
|
|
|
160
160
|
canManage ? (
|
|
161
161
|
<RowActions
|
|
162
162
|
items={[
|
|
163
|
-
{ label: t('common.edit', 'Edit'), href: `/backend/directory/tenants/${row.id}/edit` },
|
|
164
|
-
{ label: t('common.delete', 'Delete'), destructive: true, onSelect: () => handleDelete(row) },
|
|
163
|
+
{ id: 'edit', label: t('common.edit', 'Edit'), href: `/backend/directory/tenants/${row.id}/edit` },
|
|
164
|
+
{ id: 'delete', label: t('common.delete', 'Delete'), destructive: true, onSelect: () => handleDelete(row) },
|
|
165
165
|
]}
|
|
166
166
|
/>
|
|
167
167
|
) : null
|
|
@@ -338,8 +338,8 @@ export RECORD_ID="<record uuid>"`}</code></pre>
|
|
|
338
338
|
rowActions={(row) => (
|
|
339
339
|
<RowActions
|
|
340
340
|
items={[
|
|
341
|
-
{ label: 'Edit', href: `/backend/entities/user/${encodeURIComponent(entityId)}/records/${encodeURIComponent(String((row as any).id))}` },
|
|
342
|
-
{ label: 'Delete', destructive: true, onSelect: async () => {
|
|
341
|
+
{ id: 'edit', label: 'Edit', href: `/backend/entities/user/${encodeURIComponent(entityId)}/records/${encodeURIComponent(String((row as any).id))}` },
|
|
342
|
+
{ id: 'delete', label: 'Delete', destructive: true, onSelect: async () => {
|
|
343
343
|
try {
|
|
344
344
|
if (typeof window !== 'undefined') {
|
|
345
345
|
const ok = window.confirm('Delete this record?')
|
|
@@ -88,7 +88,7 @@ export default function SystemEntitiesTable() {
|
|
|
88
88
|
rowActions={(row) => (
|
|
89
89
|
<RowActions
|
|
90
90
|
items={[
|
|
91
|
-
{ label: 'Edit', href: `/backend/entities/system/${encodeURIComponent(row.entityId)}` },
|
|
91
|
+
{ id: 'edit', label: 'Edit', href: `/backend/entities/system/${encodeURIComponent(row.entityId)}` },
|
|
92
92
|
]}
|
|
93
93
|
/>
|
|
94
94
|
)}
|
|
@@ -110,8 +110,8 @@ export default function UserEntitiesTable() {
|
|
|
110
110
|
rowActions={(row) => (
|
|
111
111
|
<RowActions
|
|
112
112
|
items={[
|
|
113
|
-
{ label: t('common.edit', 'Edit'), href: `/backend/entities/user/${encodeURIComponent(row.entityId)}` },
|
|
114
|
-
{ label: t('entities.user.table.actions.showRecords', 'Show records'), href: `/backend/entities/user/${encodeURIComponent(row.entityId)}/records` },
|
|
113
|
+
{ id: 'edit', label: t('common.edit', 'Edit'), href: `/backend/entities/user/${encodeURIComponent(row.entityId)}` },
|
|
114
|
+
{ id: 'show-records', label: t('entities.user.table.actions.showRecords', 'Show records'), href: `/backend/entities/user/${encodeURIComponent(row.entityId)}/records` },
|
|
115
115
|
]}
|
|
116
116
|
/>
|
|
117
117
|
)}
|
|
@@ -205,12 +205,11 @@ export function FeatureTogglesTable() {
|
|
|
205
205
|
}}
|
|
206
206
|
rowActions={(row) => (
|
|
207
207
|
<RowActions items={[
|
|
208
|
-
{ label: t('common.edit', 'Edit'), href: `/backend/feature-toggles/global/${row.id}/edit` },
|
|
209
|
-
{ label: t('common.view', 'Overrides'), href: `/backend/feature-toggles/global/${row.id}` },
|
|
210
|
-
{ label: t('common.delete', 'Delete'), destructive: true, onSelect: () => { void handleDelete(row) } },
|
|
208
|
+
{ id: 'edit', label: t('common.edit', 'Edit'), href: `/backend/feature-toggles/global/${row.id}/edit` },
|
|
209
|
+
{ id: 'view', label: t('common.view', 'Overrides'), href: `/backend/feature-toggles/global/${row.id}` },
|
|
210
|
+
{ id: 'delete', label: t('common.delete', 'Delete'), destructive: true, onSelect: () => { void handleDelete(row) } },
|
|
211
211
|
]} />
|
|
212
212
|
)}
|
|
213
213
|
/>
|
|
214
214
|
)
|
|
215
215
|
}
|
|
216
|
-
|
|
@@ -161,7 +161,7 @@ export default function OverridesTable() {
|
|
|
161
161
|
}}
|
|
162
162
|
rowActions={(row) => (
|
|
163
163
|
<RowActions items={[
|
|
164
|
-
{ label: t('common.edit', 'Edit'), href: `/backend/feature-toggles/global/${row.toggleId}` },
|
|
164
|
+
{ id: 'edit', label: t('common.edit', 'Edit'), href: `/backend/feature-toggles/global/${row.toggleId}` },
|
|
165
165
|
]} />
|
|
166
166
|
)}
|
|
167
167
|
error={error ? error.message : undefined}
|