@open-mercato/core 0.4.2-canary-968c919ed2 → 0.4.2-canary-f821f89ef6
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/workflow_event_trigger/index.js +33 -0
- package/dist/generated/entities/workflow_event_trigger/index.js.map +7 -0
- package/dist/generated/entities.ids.generated.js +2 -5
- 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 +2 -3
- 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 +0 -4
- package/dist/modules/attachments/components/AttachmentLibrary.js.map +2 -2
- package/dist/modules/attachments/components/AttachmentPartitionSettings.js +0 -2
- package/dist/modules/attachments/components/AttachmentPartitionSettings.js.map +2 -2
- package/dist/modules/auth/api/admin/nav.js +3 -4
- package/dist/modules/auth/api/admin/nav.js.map +2 -2
- package/dist/modules/auth/api/login.js +6 -25
- package/dist/modules/auth/api/login.js.map +2 -2
- package/dist/modules/auth/api/reset/confirm.js +2 -25
- package/dist/modules/auth/api/reset/confirm.js.map +2 -2
- package/dist/modules/auth/api/reset.js +0 -23
- package/dist/modules/auth/api/reset.js.map +2 -2
- package/dist/modules/auth/api/sidebar/preferences/route.js +9 -14
- package/dist/modules/auth/api/sidebar/preferences/route.js.map +2 -2
- package/dist/modules/auth/api/users/route.js +2 -4
- package/dist/modules/auth/api/users/route.js.map +2 -2
- package/dist/modules/auth/backend/roles/[id]/edit/page.js +1 -4
- 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 +3 -18
- package/dist/modules/auth/backend/users/[id]/edit/page.js.map +2 -2
- package/dist/modules/auth/backend/users/create/page.js +2 -15
- 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 +11 -25
- package/dist/modules/auth/cli.js.map +2 -2
- package/dist/modules/auth/commands/users.js +2 -59
- package/dist/modules/auth/commands/users.js.map +2 -2
- package/dist/modules/auth/data/validators.js +3 -6
- package/dist/modules/auth/data/validators.js.map +2 -2
- package/dist/modules/auth/events.js +30 -0
- package/dist/modules/auth/events.js.map +7 -0
- package/dist/modules/auth/frontend/login.js +3 -105
- package/dist/modules/auth/frontend/login.js.map +2 -2
- package/dist/modules/auth/frontend/reset/[token]/page.js +10 -20
- package/dist/modules/auth/frontend/reset/[token]/page.js.map +2 -2
- package/dist/modules/auth/lib/setup-app.js +8 -42
- package/dist/modules/auth/lib/setup-app.js.map +2 -2
- package/dist/modules/auth/services/authService.js +3 -24
- package/dist/modules/auth/services/authService.js.map +2 -2
- package/dist/modules/business_rules/api/execute/[ruleId]/route.js +145 -0
- package/dist/modules/business_rules/api/execute/[ruleId]/route.js.map +7 -0
- package/dist/modules/business_rules/api/execute/route.js +1 -7
- package/dist/modules/business_rules/api/execute/route.js.map +2 -2
- package/dist/modules/business_rules/backend/rules/page.js +0 -4
- package/dist/modules/business_rules/backend/rules/page.js.map +2 -2
- package/dist/modules/business_rules/backend/sets/page.js +0 -3
- package/dist/modules/business_rules/backend/sets/page.js.map +2 -2
- package/dist/modules/business_rules/cli.js +1 -2
- package/dist/modules/business_rules/cli.js.map +2 -2
- package/dist/modules/business_rules/data/validators.js +34 -0
- package/dist/modules/business_rules/data/validators.js.map +2 -2
- package/dist/modules/business_rules/index.js +21 -1
- package/dist/modules/business_rules/index.js.map +2 -2
- package/dist/modules/business_rules/lib/rule-engine.js +185 -34
- package/dist/modules/business_rules/lib/rule-engine.js.map +2 -2
- package/dist/modules/catalog/components/PriceKindSettings.js +0 -2
- 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 +0 -2
- package/dist/modules/catalog/components/products/ProductsDataTable.js.map +2 -2
- package/dist/modules/catalog/events.js +34 -0
- package/dist/modules/catalog/events.js.map +7 -0
- package/dist/modules/configs/cli.js +0 -6
- 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 +1 -48
- package/dist/modules/configs/lib/system-status.js.map +2 -2
- package/dist/modules/configs/lib/upgrade-actions.js +0 -18
- package/dist/modules/configs/lib/upgrade-actions.js.map +2 -2
- package/dist/modules/currencies/backend/currencies/page.js +0 -3
- package/dist/modules/currencies/backend/currencies/page.js.map +2 -2
- package/dist/modules/currencies/backend/exchange-rates/page.js +0 -2
- package/dist/modules/currencies/backend/exchange-rates/page.js.map +2 -2
- package/dist/modules/customers/backend/customers/companies/page.js +0 -3
- package/dist/modules/customers/backend/customers/companies/page.js.map +2 -2
- package/dist/modules/customers/backend/customers/deals/page.js +0 -3
- package/dist/modules/customers/backend/customers/deals/page.js.map +2 -2
- package/dist/modules/customers/backend/customers/people/page.js +0 -3
- package/dist/modules/customers/backend/customers/people/page.js.map +2 -2
- package/dist/modules/customers/commands/deals.js +0 -31
- package/dist/modules/customers/commands/deals.js.map +2 -2
- package/dist/modules/customers/components/CustomerTodosTable.js +0 -1
- package/dist/modules/customers/components/CustomerTodosTable.js.map +2 -2
- package/dist/modules/customers/events.js +49 -0
- package/dist/modules/customers/events.js.map +7 -0
- package/dist/modules/customers/widgets/dashboard/customer-todos/widget.js +1 -2
- package/dist/modules/customers/widgets/dashboard/customer-todos/widget.js.map +2 -2
- package/dist/modules/customers/widgets/dashboard/new-customers/widget.js +1 -2
- package/dist/modules/customers/widgets/dashboard/new-customers/widget.js.map +2 -2
- package/dist/modules/customers/widgets/dashboard/new-deals/widget.js +1 -2
- package/dist/modules/customers/widgets/dashboard/new-deals/widget.js.map +2 -2
- package/dist/modules/customers/widgets/dashboard/next-interactions/widget.js +1 -2
- package/dist/modules/customers/widgets/dashboard/next-interactions/widget.js.map +2 -2
- package/dist/modules/dashboards/cli.js +5 -44
- package/dist/modules/dashboards/cli.js.map +2 -2
- package/dist/modules/dashboards/components/WidgetVisibilityEditor.js +11 -16
- package/dist/modules/dashboards/components/WidgetVisibilityEditor.js.map +3 -3
- package/dist/modules/dashboards/services/widgetDataService.js +3 -139
- package/dist/modules/dashboards/services/widgetDataService.js.map +2 -2
- package/dist/modules/dashboards/widgets/dashboard/aov-kpi/widget.js +1 -2
- package/dist/modules/dashboards/widgets/dashboard/aov-kpi/widget.js.map +2 -2
- package/dist/modules/dashboards/widgets/dashboard/new-customers-kpi/widget.js +1 -2
- 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 +1 -2
- package/dist/modules/dashboards/widgets/dashboard/orders-by-status/widget.js.map +2 -2
- package/dist/modules/dashboards/widgets/dashboard/orders-kpi/widget.js +1 -2
- package/dist/modules/dashboards/widgets/dashboard/orders-kpi/widget.js.map +2 -2
- package/dist/modules/dashboards/widgets/dashboard/pipeline-summary/widget.js +1 -2
- package/dist/modules/dashboards/widgets/dashboard/pipeline-summary/widget.js.map +2 -2
- package/dist/modules/dashboards/widgets/dashboard/revenue-kpi/widget.js +1 -2
- package/dist/modules/dashboards/widgets/dashboard/revenue-kpi/widget.js.map +2 -2
- package/dist/modules/dashboards/widgets/dashboard/revenue-trend/widget.js +1 -2
- package/dist/modules/dashboards/widgets/dashboard/revenue-trend/widget.js.map +2 -2
- package/dist/modules/dashboards/widgets/dashboard/sales-by-region/widget.js +1 -2
- package/dist/modules/dashboards/widgets/dashboard/sales-by-region/widget.js.map +2 -2
- package/dist/modules/dashboards/widgets/dashboard/top-customers/widget.js +1 -2
- package/dist/modules/dashboards/widgets/dashboard/top-customers/widget.js.map +2 -2
- package/dist/modules/dashboards/widgets/dashboard/top-products/widget.js +1 -2
- package/dist/modules/dashboards/widgets/dashboard/top-products/widget.js.map +2 -2
- package/dist/modules/dictionaries/components/DictionaryTable.js +0 -2
- package/dist/modules/dictionaries/components/DictionaryTable.js.map +2 -2
- 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/directory/events.js +23 -0
- package/dist/modules/directory/events.js.map +7 -0
- 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/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 +7 -63
- package/dist/modules/query_index/cli.js.map +2 -2
- package/dist/modules/query_index/components/QueryIndexesTable.js +1 -7
- 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 +1 -0
- package/dist/modules/sales/acl.js.map +2 -2
- package/dist/modules/sales/backend/sales/channels/offers/page.js +0 -2
- package/dist/modules/sales/backend/sales/channels/offers/page.js.map +2 -2
- package/dist/modules/sales/backend/sales/channels/page.js +0 -2
- package/dist/modules/sales/backend/sales/channels/page.js.map +2 -2
- package/dist/modules/sales/backend/sales/documents/[id]/page.js +12 -0
- package/dist/modules/sales/backend/sales/documents/[id]/page.js.map +2 -2
- package/dist/modules/sales/commands/documents.js +62 -53
- package/dist/modules/sales/commands/documents.js.map +2 -2
- package/dist/modules/sales/commands/payments.js +0 -26
- 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 +0 -2
- package/dist/modules/sales/components/channels/SalesChannelOffersPanel.js.map +2 -2
- package/dist/modules/sales/components/documents/AdjustmentsSection.js +0 -2
- package/dist/modules/sales/components/documents/AdjustmentsSection.js.map +2 -2
- package/dist/modules/sales/components/documents/PaymentsSection.js +1 -2
- package/dist/modules/sales/components/documents/PaymentsSection.js.map +2 -2
- package/dist/modules/sales/components/documents/SalesDocumentsTable.js +0 -2
- package/dist/modules/sales/components/documents/SalesDocumentsTable.js.map +2 -2
- package/dist/modules/sales/events.js +63 -0
- package/dist/modules/sales/events.js.map +7 -0
- package/dist/modules/sales/lib/dictionaries.js +3 -0
- package/dist/modules/sales/lib/dictionaries.js.map +2 -2
- package/dist/modules/sales/lib/frontend/documentDataEvents.js +25 -0
- package/dist/modules/sales/lib/frontend/documentDataEvents.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 +0 -79
- package/dist/modules/staff/commands/leave-requests.js.map +2 -2
- package/dist/modules/workflows/acl.js +2 -0
- package/dist/modules/workflows/acl.js.map +2 -2
- package/dist/modules/workflows/api/instances/route.js +18 -6
- package/dist/modules/workflows/api/instances/route.js.map +2 -2
- package/dist/modules/workflows/api/tasks/route.js +6 -1
- package/dist/modules/workflows/api/tasks/route.js.map +2 -2
- package/dist/modules/workflows/backend/definitions/[id]/page.js +9 -1
- 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 +24 -15
- 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 +0 -5
- package/dist/modules/workflows/backend/definitions/page.js.map +2 -2
- package/dist/modules/workflows/backend/definitions/visual-editor/page.js +150 -132
- 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 +0 -3
- 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 +5 -9
- package/dist/modules/workflows/backend/tasks/page.js.map +2 -2
- package/dist/modules/workflows/cli.js +93 -15
- package/dist/modules/workflows/cli.js.map +3 -3
- package/dist/modules/workflows/components/DefinitionTriggersEditor.js +481 -0
- package/dist/modules/workflows/components/DefinitionTriggersEditor.js.map +7 -0
- package/dist/modules/workflows/components/EventTriggersEditor.js +553 -0
- package/dist/modules/workflows/components/EventTriggersEditor.js.map +7 -0
- package/dist/modules/workflows/data/entities.js +64 -1
- package/dist/modules/workflows/data/entities.js.map +2 -2
- package/dist/modules/workflows/data/validators.js +115 -0
- package/dist/modules/workflows/data/validators.js.map +2 -2
- package/dist/modules/workflows/events.js +38 -0
- package/dist/modules/workflows/events.js.map +7 -0
- package/dist/modules/workflows/examples/checkout-demo-definition.json +1 -5
- package/dist/modules/workflows/examples/order-approval-definition.json +257 -0
- package/dist/modules/workflows/examples/order-approval-guard-rules.json +32 -0
- package/dist/modules/workflows/lib/activity-executor.js +75 -13
- package/dist/modules/workflows/lib/activity-executor.js.map +2 -2
- package/dist/modules/workflows/lib/event-trigger-service.js +308 -0
- package/dist/modules/workflows/lib/event-trigger-service.js.map +7 -0
- package/dist/modules/workflows/lib/graph-utils.js +71 -2
- package/dist/modules/workflows/lib/graph-utils.js.map +2 -2
- package/dist/modules/workflows/lib/seeds.js +22 -5
- package/dist/modules/workflows/lib/seeds.js.map +2 -2
- package/dist/modules/workflows/lib/start-validator.js +33 -23
- package/dist/modules/workflows/lib/start-validator.js.map +2 -2
- package/dist/modules/workflows/lib/transition-handler.js +161 -57
- package/dist/modules/workflows/lib/transition-handler.js.map +3 -3
- package/dist/modules/workflows/migrations/Migration20260123143500.js +36 -0
- package/dist/modules/workflows/migrations/Migration20260123143500.js.map +7 -0
- package/dist/modules/workflows/subscribers/event-trigger.js +78 -0
- package/dist/modules/workflows/subscribers/event-trigger.js.map +7 -0
- package/dist/modules/workflows/widgets/injection/order-approval/widget.client.js +323 -0
- package/dist/modules/workflows/widgets/injection/order-approval/widget.client.js.map +7 -0
- package/dist/modules/workflows/widgets/injection/order-approval/widget.js +17 -0
- package/dist/modules/workflows/widgets/injection/order-approval/widget.js.map +7 -0
- package/dist/modules/workflows/widgets/injection-table.js +19 -0
- package/dist/modules/workflows/widgets/injection-table.js.map +7 -0
- package/generated/entities/workflow_event_trigger/index.ts +15 -0
- package/generated/entities.ids.generated.ts +2 -5
- package/generated/entity-fields-registry.ts +2 -2
- package/package.json +2 -2
- package/src/modules/api_docs/frontend/docs/api/page.tsx +2 -3
- package/src/modules/api_keys/backend/api-keys/page.tsx +1 -1
- package/src/modules/attachments/components/AttachmentLibrary.tsx +0 -4
- package/src/modules/attachments/components/AttachmentPartitionSettings.tsx +0 -2
- 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 +0 -2
- package/src/modules/auth/api/admin/nav.ts +6 -10
- package/src/modules/auth/api/login.ts +7 -26
- package/src/modules/auth/api/reset/confirm.ts +2 -25
- package/src/modules/auth/api/reset.ts +0 -23
- package/src/modules/auth/api/sidebar/preferences/route.ts +12 -21
- package/src/modules/auth/api/users/route.ts +2 -5
- package/src/modules/auth/backend/roles/[id]/edit/page.tsx +1 -4
- package/src/modules/auth/backend/roles/page.tsx +3 -3
- package/src/modules/auth/backend/users/[id]/edit/page.tsx +3 -22
- package/src/modules/auth/backend/users/create/page.tsx +2 -19
- package/src/modules/auth/backend/users/page.tsx +3 -3
- package/src/modules/auth/cli.ts +11 -38
- package/src/modules/auth/commands/users.ts +2 -73
- package/src/modules/auth/data/validators.ts +2 -6
- package/src/modules/auth/events.ts +39 -0
- package/src/modules/auth/frontend/login.tsx +5 -131
- package/src/modules/auth/frontend/reset/[token]/page.tsx +11 -24
- package/src/modules/auth/i18n/de.json +1 -48
- package/src/modules/auth/i18n/en.json +1 -48
- package/src/modules/auth/i18n/es.json +1 -48
- package/src/modules/auth/i18n/pl.json +1 -48
- package/src/modules/auth/lib/setup-app.ts +9 -58
- package/src/modules/auth/services/authService.ts +4 -27
- package/src/modules/business_rules/api/execute/[ruleId]/route.ts +163 -0
- package/src/modules/business_rules/api/execute/route.ts +1 -8
- package/src/modules/business_rules/backend/rules/page.tsx +0 -4
- package/src/modules/business_rules/backend/sets/page.tsx +0 -3
- package/src/modules/business_rules/cli.ts +1 -2
- package/src/modules/business_rules/data/validators.ts +40 -0
- package/src/modules/business_rules/i18n/en.json +1 -3
- package/src/modules/business_rules/index.ts +25 -0
- package/src/modules/business_rules/lib/__tests__/rule-engine.test.ts +0 -51
- package/src/modules/business_rules/lib/rule-engine.ts +277 -51
- package/src/modules/catalog/components/PriceKindSettings.tsx +0 -2
- package/src/modules/catalog/components/categories/CategoriesDataTable.tsx +2 -2
- package/src/modules/catalog/components/products/ProductsDataTable.tsx +0 -2
- package/src/modules/catalog/events.ts +45 -0
- package/src/modules/catalog/i18n/en.json +1 -3
- package/src/modules/configs/cli.ts +0 -6
- package/src/modules/configs/components/CachePanel.tsx +4 -4
- package/src/modules/configs/i18n/en.json +2 -12
- package/src/modules/configs/i18n/pl.json +2 -12
- package/src/modules/configs/lib/system-status.ts +1 -48
- package/src/modules/configs/lib/system-status.types.ts +0 -1
- package/src/modules/configs/lib/upgrade-actions.ts +0 -18
- package/src/modules/currencies/backend/currencies/page.tsx +0 -3
- package/src/modules/currencies/backend/exchange-rates/page.tsx +0 -2
- package/src/modules/customers/backend/customers/companies/page.tsx +0 -3
- package/src/modules/customers/backend/customers/deals/page.tsx +0 -3
- package/src/modules/customers/backend/customers/people/page.tsx +0 -3
- package/src/modules/customers/commands/deals.ts +0 -39
- package/src/modules/customers/components/CustomerTodosTable.tsx +0 -1
- package/src/modules/customers/events.ts +63 -0
- package/src/modules/customers/i18n/en.json +1 -5
- 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 +5 -55
- package/src/modules/dashboards/components/WidgetVisibilityEditor.tsx +11 -22
- package/src/modules/dashboards/services/widgetDataService.ts +4 -164
- 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 +0 -2
- 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/directory/events.ts +31 -0
- 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 +4 -3
- package/src/modules/feature_toggles/components/OverridesTable.tsx +1 -1
- package/src/modules/planner/backend/planner/availability-rulesets/page.tsx +2 -2
- package/src/modules/query_index/cli.ts +13 -82
- package/src/modules/query_index/components/QueryIndexesTable.tsx +2 -8
- 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 +1 -0
- package/src/modules/sales/backend/sales/channels/offers/page.tsx +0 -2
- package/src/modules/sales/backend/sales/channels/page.tsx +0 -2
- package/src/modules/sales/backend/sales/documents/[id]/page.tsx +16 -0
- package/src/modules/sales/commands/documents.ts +70 -62
- package/src/modules/sales/commands/payments.ts +0 -33
- 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 +0 -2
- package/src/modules/sales/components/documents/AdjustmentsSection.tsx +0 -2
- package/src/modules/sales/components/documents/PaymentsSection.tsx +1 -2
- package/src/modules/sales/components/documents/SalesDocumentsTable.tsx +0 -2
- package/src/modules/sales/events.ts +82 -0
- package/src/modules/sales/i18n/de.json +0 -20
- package/src/modules/sales/i18n/en.json +1 -25
- package/src/modules/sales/i18n/es.json +0 -20
- package/src/modules/sales/i18n/pl.json +0 -20
- package/src/modules/sales/lib/dictionaries.ts +3 -0
- package/src/modules/sales/lib/frontend/documentDataEvents.ts +28 -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 +0 -94
- package/src/modules/staff/i18n/de.json +0 -4
- package/src/modules/staff/i18n/en.json +1 -9
- package/src/modules/staff/i18n/es.json +0 -4
- package/src/modules/staff/i18n/pl.json +0 -4
- package/src/modules/workflows/acl.ts +2 -0
- package/src/modules/workflows/api/__tests__/instances.route.test.ts +5 -2
- package/src/modules/workflows/api/instances/route.ts +21 -7
- package/src/modules/workflows/api/tasks/route.ts +7 -1
- package/src/modules/workflows/backend/definitions/[id]/page.meta.ts +1 -1
- package/src/modules/workflows/backend/definitions/[id]/page.tsx +9 -0
- package/src/modules/workflows/backend/definitions/create/page.meta.ts +1 -1
- package/src/modules/workflows/backend/definitions/create/page.tsx +9 -0
- package/src/modules/workflows/backend/definitions/page.tsx +0 -5
- package/src/modules/workflows/backend/definitions/visual-editor/page.meta.ts +1 -1
- package/src/modules/workflows/backend/definitions/visual-editor/page.tsx +21 -3
- 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 +1 -4
- 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 +6 -10
- package/src/modules/workflows/cli.ts +123 -12
- package/src/modules/workflows/components/DefinitionTriggersEditor.tsx +581 -0
- package/src/modules/workflows/components/EventTriggersEditor.tsx +664 -0
- package/src/modules/workflows/data/entities.ts +124 -0
- package/src/modules/workflows/data/validators.ts +138 -0
- package/src/modules/workflows/events.ts +49 -0
- package/src/modules/workflows/examples/checkout-demo-definition.json +1 -5
- package/src/modules/workflows/examples/order-approval-definition.json +257 -0
- package/src/modules/workflows/examples/order-approval-guard-rules.json +32 -0
- package/src/modules/workflows/i18n/en.json +72 -3
- package/src/modules/workflows/lib/__tests__/activity-executor.test.ts +43 -36
- package/src/modules/workflows/lib/__tests__/transition-handler.test.ts +170 -90
- package/src/modules/workflows/lib/activity-executor.ts +129 -16
- package/src/modules/workflows/lib/event-trigger-service.ts +557 -0
- package/src/modules/workflows/lib/graph-utils.ts +117 -2
- package/src/modules/workflows/lib/seeds.ts +34 -8
- package/src/modules/workflows/lib/start-validator.ts +38 -28
- package/src/modules/workflows/lib/transition-handler.ts +212 -71
- package/src/modules/workflows/migrations/Migration20260123143500.ts +38 -0
- package/src/modules/workflows/subscribers/event-trigger.ts +109 -0
- package/src/modules/workflows/widgets/injection/order-approval/widget.client.tsx +446 -0
- package/src/modules/workflows/widgets/injection/order-approval/widget.ts +16 -0
- package/src/modules/workflows/widgets/injection-table.ts +21 -0
- package/dist/generated/entities/notification/index.js +0 -57
- package/dist/generated/entities/notification/index.js.map +0 -7
- package/dist/modules/auth/api/profile/route.js +0 -157
- package/dist/modules/auth/api/profile/route.js.map +0 -7
- package/dist/modules/auth/backend/auth/profile/page.js +0 -141
- package/dist/modules/auth/backend/auth/profile/page.js.map +0 -7
- package/dist/modules/auth/backend/auth/profile/page.meta.js +0 -13
- package/dist/modules/auth/backend/auth/profile/page.meta.js.map +0 -7
- package/dist/modules/auth/notifications.js +0 -112
- package/dist/modules/auth/notifications.js.map +0 -7
- package/dist/modules/business_rules/notifications.js +0 -28
- package/dist/modules/business_rules/notifications.js.map +0 -7
- package/dist/modules/business_rules/subscribers/rule-execution-failed-notification.js +0 -37
- package/dist/modules/business_rules/subscribers/rule-execution-failed-notification.js.map +0 -7
- package/dist/modules/catalog/notifications.js +0 -28
- package/dist/modules/catalog/notifications.js.map +0 -7
- package/dist/modules/catalog/subscribers/low-stock-notification.js +0 -38
- package/dist/modules/catalog/subscribers/low-stock-notification.js.map +0 -7
- package/dist/modules/customers/notifications.js +0 -48
- package/dist/modules/customers/notifications.js.map +0 -7
- package/dist/modules/dashboards/lib/role-widgets.js +0 -58
- package/dist/modules/dashboards/lib/role-widgets.js.map +0 -7
- package/dist/modules/directory/api/get/tenants/lookup.js +0 -70
- package/dist/modules/directory/api/get/tenants/lookup.js.map +0 -7
- package/dist/modules/notifications/acl.js +0 -11
- package/dist/modules/notifications/acl.js.map +0 -7
- package/dist/modules/notifications/api/[id]/action/route.js +0 -74
- package/dist/modules/notifications/api/[id]/action/route.js.map +0 -7
- package/dist/modules/notifications/api/[id]/dismiss/route.js +0 -15
- package/dist/modules/notifications/api/[id]/dismiss/route.js.map +0 -7
- package/dist/modules/notifications/api/[id]/read/route.js +0 -15
- package/dist/modules/notifications/api/[id]/read/route.js.map +0 -7
- package/dist/modules/notifications/api/[id]/restore/route.js +0 -53
- package/dist/modules/notifications/api/[id]/restore/route.js.map +0 -7
- package/dist/modules/notifications/api/batch/route.js +0 -17
- package/dist/modules/notifications/api/batch/route.js.map +0 -7
- package/dist/modules/notifications/api/feature/route.js +0 -17
- package/dist/modules/notifications/api/feature/route.js.map +0 -7
- package/dist/modules/notifications/api/mark-all-read/route.js +0 -35
- package/dist/modules/notifications/api/mark-all-read/route.js.map +0 -7
- package/dist/modules/notifications/api/openapi.js +0 -76
- package/dist/modules/notifications/api/openapi.js.map +0 -7
- package/dist/modules/notifications/api/role/route.js +0 -17
- package/dist/modules/notifications/api/role/route.js.map +0 -7
- package/dist/modules/notifications/api/route.js +0 -85
- package/dist/modules/notifications/api/route.js.map +0 -7
- package/dist/modules/notifications/api/settings/route.js +0 -155
- package/dist/modules/notifications/api/settings/route.js.map +0 -7
- package/dist/modules/notifications/api/unread-count/route.js +0 -38
- package/dist/modules/notifications/api/unread-count/route.js.map +0 -7
- package/dist/modules/notifications/backend/config/notifications/page.js +0 -10
- package/dist/modules/notifications/backend/config/notifications/page.js.map +0 -7
- package/dist/modules/notifications/backend/config/notifications/page.meta.js +0 -24
- package/dist/modules/notifications/backend/config/notifications/page.meta.js.map +0 -7
- package/dist/modules/notifications/cli.js +0 -16
- package/dist/modules/notifications/cli.js.map +0 -7
- package/dist/modules/notifications/data/entities.js +0 -112
- package/dist/modules/notifications/data/entities.js.map +0 -7
- package/dist/modules/notifications/data/validators.js +0 -98
- package/dist/modules/notifications/data/validators.js.map +0 -7
- package/dist/modules/notifications/di.js +0 -13
- package/dist/modules/notifications/di.js.map +0 -7
- package/dist/modules/notifications/emails/NotificationEmail.js +0 -58
- package/dist/modules/notifications/emails/NotificationEmail.js.map +0 -7
- package/dist/modules/notifications/frontend/NotificationInboxPageClient.js +0 -44
- package/dist/modules/notifications/frontend/NotificationInboxPageClient.js.map +0 -7
- package/dist/modules/notifications/frontend/NotificationSettingsPageClient.js +0 -220
- package/dist/modules/notifications/frontend/NotificationSettingsPageClient.js.map +0 -7
- package/dist/modules/notifications/index.js +0 -14
- package/dist/modules/notifications/index.js.map +0 -7
- package/dist/modules/notifications/lib/deliveryConfig.js +0 -107
- package/dist/modules/notifications/lib/deliveryConfig.js.map +0 -7
- package/dist/modules/notifications/lib/deliveryStrategies.js +0 -14
- package/dist/modules/notifications/lib/deliveryStrategies.js.map +0 -7
- package/dist/modules/notifications/lib/events.js +0 -12
- package/dist/modules/notifications/lib/events.js.map +0 -7
- package/dist/modules/notifications/lib/notificationBuilder.js +0 -66
- package/dist/modules/notifications/lib/notificationBuilder.js.map +0 -7
- package/dist/modules/notifications/lib/notificationFactory.js +0 -54
- package/dist/modules/notifications/lib/notificationFactory.js.map +0 -7
- package/dist/modules/notifications/lib/notificationMapper.js +0 -34
- package/dist/modules/notifications/lib/notificationMapper.js.map +0 -7
- package/dist/modules/notifications/lib/notificationRecipients.js +0 -35
- package/dist/modules/notifications/lib/notificationRecipients.js.map +0 -7
- package/dist/modules/notifications/lib/notificationService.js +0 -279
- package/dist/modules/notifications/lib/notificationService.js.map +0 -7
- package/dist/modules/notifications/lib/routeHelpers.js +0 -101
- package/dist/modules/notifications/lib/routeHelpers.js.map +0 -7
- package/dist/modules/notifications/lib/safeHref.js +0 -24
- package/dist/modules/notifications/lib/safeHref.js.map +0 -7
- package/dist/modules/notifications/migrations/Migration20260123000001.js +0 -70
- package/dist/modules/notifications/migrations/Migration20260123000001.js.map +0 -7
- package/dist/modules/notifications/migrations/Migration20260126150000.js +0 -37
- package/dist/modules/notifications/migrations/Migration20260126150000.js.map +0 -7
- package/dist/modules/notifications/migrations/Migration20260129082610.js +0 -13
- package/dist/modules/notifications/migrations/Migration20260129082610.js.map +0 -7
- package/dist/modules/notifications/subscribers/deliver-notification.js +0 -165
- package/dist/modules/notifications/subscribers/deliver-notification.js.map +0 -7
- package/dist/modules/notifications/workers/create-notification.worker.js +0 -70
- package/dist/modules/notifications/workers/create-notification.worker.js.map +0 -7
- package/dist/modules/sales/notifications.client.js +0 -51
- package/dist/modules/sales/notifications.client.js.map +0 -7
- package/dist/modules/sales/notifications.js +0 -88
- package/dist/modules/sales/notifications.js.map +0 -7
- package/dist/modules/sales/subscribers/quote-expiring-notification.js +0 -38
- package/dist/modules/sales/subscribers/quote-expiring-notification.js.map +0 -7
- package/dist/modules/sales/widgets/notifications/SalesOrderCreatedRenderer.js +0 -137
- package/dist/modules/sales/widgets/notifications/SalesOrderCreatedRenderer.js.map +0 -7
- package/dist/modules/sales/widgets/notifications/SalesQuoteCreatedRenderer.js +0 -137
- package/dist/modules/sales/widgets/notifications/SalesQuoteCreatedRenderer.js.map +0 -7
- package/dist/modules/sales/widgets/notifications/index.js +0 -7
- package/dist/modules/sales/widgets/notifications/index.js.map +0 -7
- package/dist/modules/sales/widgets/notifications/useSalesDocumentTotals.js +0 -60
- package/dist/modules/sales/widgets/notifications/useSalesDocumentTotals.js.map +0 -7
- package/dist/modules/staff/notifications.js +0 -75
- package/dist/modules/staff/notifications.js.map +0 -7
- package/dist/modules/workflows/notifications.js +0 -28
- package/dist/modules/workflows/notifications.js.map +0 -7
- package/dist/modules/workflows/subscribers/task-assigned-notification.js +0 -38
- package/dist/modules/workflows/subscribers/task-assigned-notification.js.map +0 -7
- package/generated/entities/notification/index.ts +0 -27
- package/src/modules/auth/api/profile/route.ts +0 -163
- package/src/modules/auth/backend/auth/profile/page.meta.ts +0 -9
- package/src/modules/auth/backend/auth/profile/page.tsx +0 -174
- package/src/modules/auth/notifications.ts +0 -109
- package/src/modules/business_rules/notifications.ts +0 -25
- package/src/modules/business_rules/subscribers/rule-execution-failed-notification.ts +0 -50
- package/src/modules/catalog/notifications.ts +0 -25
- package/src/modules/catalog/subscribers/low-stock-notification.ts +0 -52
- package/src/modules/customers/notifications.ts +0 -44
- package/src/modules/dashboards/lib/role-widgets.ts +0 -80
- package/src/modules/directory/api/get/tenants/lookup.ts +0 -75
- package/src/modules/notifications/__tests__/deliver-notification.test.ts +0 -195
- package/src/modules/notifications/__tests__/deliveryStrategies.test.ts +0 -19
- package/src/modules/notifications/__tests__/notificationService.test.ts +0 -208
- package/src/modules/notifications/acl.ts +0 -7
- package/src/modules/notifications/api/[id]/action/route.ts +0 -75
- package/src/modules/notifications/api/[id]/dismiss/route.ts +0 -12
- package/src/modules/notifications/api/[id]/read/route.ts +0 -12
- package/src/modules/notifications/api/[id]/restore/route.ts +0 -53
- package/src/modules/notifications/api/batch/route.ts +0 -14
- package/src/modules/notifications/api/feature/route.ts +0 -14
- package/src/modules/notifications/api/mark-all-read/route.ts +0 -34
- package/src/modules/notifications/api/openapi.ts +0 -76
- package/src/modules/notifications/api/role/route.ts +0 -14
- package/src/modules/notifications/api/route.ts +0 -92
- package/src/modules/notifications/api/settings/route.ts +0 -157
- package/src/modules/notifications/api/unread-count/route.ts +0 -38
- package/src/modules/notifications/backend/config/notifications/page.meta.ts +0 -22
- package/src/modules/notifications/backend/config/notifications/page.tsx +0 -12
- package/src/modules/notifications/cli.ts +0 -18
- package/src/modules/notifications/data/entities.ts +0 -99
- package/src/modules/notifications/data/validators.ts +0 -115
- package/src/modules/notifications/di.ts +0 -11
- package/src/modules/notifications/emails/NotificationEmail.tsx +0 -98
- package/src/modules/notifications/frontend/NotificationInboxPageClient.tsx +0 -42
- package/src/modules/notifications/frontend/NotificationSettingsPageClient.tsx +0 -233
- package/src/modules/notifications/i18n/de.json +0 -50
- package/src/modules/notifications/i18n/en.json +0 -50
- package/src/modules/notifications/i18n/es.json +0 -50
- package/src/modules/notifications/i18n/pl.json +0 -50
- package/src/modules/notifications/index.ts +0 -12
- package/src/modules/notifications/lib/deliveryConfig.ts +0 -153
- package/src/modules/notifications/lib/deliveryStrategies.ts +0 -50
- package/src/modules/notifications/lib/events.ts +0 -48
- package/src/modules/notifications/lib/notificationBuilder.ts +0 -121
- package/src/modules/notifications/lib/notificationFactory.ts +0 -76
- package/src/modules/notifications/lib/notificationMapper.ts +0 -33
- package/src/modules/notifications/lib/notificationRecipients.ts +0 -83
- package/src/modules/notifications/lib/notificationService.ts +0 -414
- package/src/modules/notifications/lib/routeHelpers.ts +0 -151
- package/src/modules/notifications/lib/safeHref.ts +0 -29
- package/src/modules/notifications/migrations/.snapshot-open-mercato.json +0 -336
- package/src/modules/notifications/migrations/Migration20260123000001.ts +0 -73
- package/src/modules/notifications/migrations/Migration20260126150000.ts +0 -39
- package/src/modules/notifications/migrations/Migration20260129082610.ts +0 -13
- package/src/modules/notifications/subscribers/deliver-notification.ts +0 -204
- package/src/modules/notifications/workers/create-notification.worker.ts +0 -122
- package/src/modules/sales/notifications.client.ts +0 -65
- package/src/modules/sales/notifications.ts +0 -82
- package/src/modules/sales/subscribers/quote-expiring-notification.ts +0 -53
- package/src/modules/sales/widgets/notifications/SalesOrderCreatedRenderer.tsx +0 -156
- package/src/modules/sales/widgets/notifications/SalesQuoteCreatedRenderer.tsx +0 -156
- package/src/modules/sales/widgets/notifications/index.ts +0 -2
- package/src/modules/sales/widgets/notifications/useSalesDocumentTotals.ts +0 -81
- package/src/modules/staff/notifications.ts +0 -71
- package/src/modules/workflows/notifications.ts +0 -25
- package/src/modules/workflows/subscribers/task-assigned-notification.ts +0 -53
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../../src/modules/staff/backend/staff/teams/page.tsx"],
|
|
4
|
-
"sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport Link from 'next/link'\nimport dynamic from 'next/dynamic'\nimport type { PluggableList } from 'unified'\nimport { useRouter } from 'next/navigation'\nimport type { ColumnDef, SortingState } from '@tanstack/react-table'\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 { BooleanIcon } from '@open-mercato/ui/backend/ValueIcons'\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 { useOrganizationScopeVersion } from '@open-mercato/shared/lib/frontend/useOrganizationScope'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { Users } from 'lucide-react'\n\nconst PAGE_SIZE = 50\nconst isTestEnv = typeof process !== 'undefined' && process.env.NODE_ENV === 'test'\nconst MARKDOWN_CLASSNAME =\n 'text-sm text-foreground break-words [&>*]:mb-2 [&>*:last-child]:mb-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 [&_pre]:rounded-md [&_pre]:bg-muted [&_pre]:p-3 [&_pre]:text-xs'\n\ntype MarkdownPreviewProps = { children: string; className?: string; remarkPlugins?: PluggableList }\n\nconst MarkdownPreview: React.ComponentType<MarkdownPreviewProps> = isTestEnv\n ? ({ children, className }) => <div className={className}>{children}</div>\n : (dynamic(() => import('react-markdown').then((mod) => mod.default as React.ComponentType<MarkdownPreviewProps>), {\n ssr: false,\n loading: () => null,\n }) as unknown as React.ComponentType<MarkdownPreviewProps>)\n\nlet markdownPluginsPromise: Promise<PluggableList> | null = null\n\nasync function loadMarkdownPlugins(): Promise<PluggableList> {\n if (isTestEnv) return []\n if (!markdownPluginsPromise) {\n markdownPluginsPromise = import('remark-gfm')\n .then((mod) => [mod.default ?? mod] as PluggableList)\n .catch(() => [])\n }\n return markdownPluginsPromise\n}\n\ntype TeamRow = {\n id: string\n name: string\n description: string | null\n isActive: boolean\n updatedAt: string | null\n memberCount: number\n}\n\ntype TeamsResponse = {\n items?: Array<Record<string, unknown>>\n total?: number\n totalPages?: number\n}\n\nexport default function StaffTeamsPage() {\n const t = useT()\n const router = useRouter()\n const scopeVersion = useOrganizationScopeVersion()\n const [rows, setRows] = React.useState<TeamRow[]>([])\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 const [markdownPlugins, setMarkdownPlugins] = React.useState<PluggableList>([])\n\n React.useEffect(() => {\n void loadMarkdownPlugins().then((plugins) => setMarkdownPlugins(plugins))\n }, [])\n\n const labels = React.useMemo(() => ({\n title: t('staff.teams.page.title', 'Teams'),\n description: t('staff.teams.page.description', 'Group team members and roles.'),\n table: {\n name: t('staff.teams.table.name', 'Name'),\n description: t('staff.teams.table.description', 'Description'),\n active: t('staff.teams.table.active', 'Active'),\n members: t('staff.teams.table.members', 'Team members'),\n updatedAt: t('staff.teams.table.updatedAt', 'Updated'),\n empty: t('staff.teams.table.empty', 'No teams yet.'),\n search: t('staff.teams.table.search', 'Search teams...'),\n },\n actions: {\n add: t('staff.teams.actions.add', 'Add team'),\n edit: t('staff.teams.actions.edit', 'Edit'),\n delete: t('staff.teams.actions.delete', 'Delete'),\n deleteConfirm: t('staff.teams.actions.deleteConfirm', 'Delete team \"{{name}}\"?'),\n showMembers: t('staff.teams.actions.showMembers', 'Show team members ({{count}})'),\n refresh: t('staff.teams.actions.refresh', 'Refresh'),\n },\n messages: {\n deleted: t('staff.teams.messages.deleted', 'Team deleted.'),\n },\n errors: {\n load: t('staff.teams.errors.load', 'Failed to load teams.'),\n delete: t('staff.teams.errors.delete', 'Failed to delete team.'),\n deleteAssigned: t('staff.teams.errors.deleteAssigned', 'Team has assigned members and cannot be deleted.'),\n },\n }), [t])\n\n const columns = React.useMemo<ColumnDef<TeamRow>[]>(() => [\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 <MarkdownPreview\n remarkPlugins={markdownPlugins}\n className={`${MARKDOWN_CLASSNAME} text-xs text-muted-foreground line-clamp-2`}\n >\n {row.original.description}\n </MarkdownPreview>\n ) : null}\n </div>\n ),\n },\n {\n accessorKey: 'description',\n header: labels.table.description,\n meta: { priority: 4 },\n cell: ({ row }) => row.original.description\n ? (\n <MarkdownPreview remarkPlugins={markdownPlugins} className={MARKDOWN_CLASSNAME}>\n {row.original.description}\n </MarkdownPreview>\n )\n : <span className=\"text-xs text-muted-foreground\">-</span>,\n },\n {\n accessorKey: 'isActive',\n header: labels.table.active,\n meta: { priority: 2 },\n cell: ({ row }) => <BooleanIcon value={row.original.isActive} />,\n },\n {\n accessorKey: 'memberCount',\n header: () => <span className=\"inline-block min-w-[250px]\">{labels.table.members}</span>,\n meta: { priority: 3 },\n enableSorting: false,\n cell: ({ row }) => (\n <Link\n className=\"inline-flex min-w-[220px] items-center gap-2 text-sm text-muted-foreground hover:text-foreground\"\n href={`/backend/staff/team-members?teamId=${encodeURIComponent(row.original.id)}`}\n onClick={(event) => event.stopPropagation()}\n >\n <Users className=\"h-4 w-4\" aria-hidden />\n {labels.actions.showMembers.replace('{{count}}', String(row.original.memberCount))}\n </Link>\n ),\n },\n {\n accessorKey: 'updatedAt',\n header: labels.table.updatedAt,\n meta: { priority: 5 },\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 ], [\n labels.actions.showMembers,\n labels.table.active,\n labels.table.description,\n labels.table.members,\n labels.table.name,\n labels.table.updatedAt,\n markdownPlugins,\n ])\n\n const loadTeams = 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<TeamsResponse>(\n `/api/staff/teams?${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(mapApiTeam))\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('staff.teams.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 loadTeams()\n }, [loadTeams, 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: TeamRow) => {\n if (entry.memberCount > 0) {\n flash(labels.errors.deleteAssigned, 'error')\n return\n }\n const message = labels.actions.deleteConfirm.replace('{{name}}', entry.name)\n if (typeof window !== 'undefined' && !window.confirm(message)) return\n try {\n await deleteCrud('staff/teams', entry.id, { errorMessage: labels.errors.delete })\n flash(labels.messages.deleted, 'success')\n handleRefresh()\n } catch (error) {\n console.error('staff.teams.delete', error)\n flash(labels.errors.delete, 'error')\n }\n }, [handleRefresh, labels.actions.deleteConfirm, labels.errors.delete, labels.errors.deleteAssigned, labels.messages.deleted])\n\n return (\n <Page>\n <PageBody>\n <DataTable<TeamRow>\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/staff/teams/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/staff/teams/${row.id}/edit` },\n ...(row.memberCount > 0\n ? []\n : [{ id: 'delete', label: labels.actions.delete, destructive: true, onSelect: () => { void handleDelete(row) } }]),\n ]}\n />\n )}\n onRowClick={(row) => router.push(`/backend/staff/teams/${row.id}/edit`)}\n />\n </PageBody>\n </Page>\n )\n}\n\nfunction mapApiTeam(item: Record<string, unknown>): TeamRow {\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.trim().length ? item.description.trim() : null\n const updatedAt = typeof item.updatedAt === 'string'\n ? item.updatedAt\n : typeof item.updated_at === 'string'\n ? item.updated_at\n : null\n const isActive = typeof item.isActive === 'boolean'\n ? item.isActive\n : typeof item.is_active === 'boolean'\n ? item.is_active\n : true\n const memberCount = typeof item.memberCount === 'number'\n ? item.memberCount\n : typeof item.member_count === 'number'\n ? item.member_count\n : 0\n return { id, name, description, isActive, updatedAt, memberCount }\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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
|
|
4
|
+
"sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport Link from 'next/link'\nimport dynamic from 'next/dynamic'\nimport type { PluggableList } from 'unified'\nimport { useRouter } from 'next/navigation'\nimport type { ColumnDef, SortingState } from '@tanstack/react-table'\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 { BooleanIcon } from '@open-mercato/ui/backend/ValueIcons'\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 { useOrganizationScopeVersion } from '@open-mercato/shared/lib/frontend/useOrganizationScope'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { Users } from 'lucide-react'\n\nconst PAGE_SIZE = 50\nconst isTestEnv = typeof process !== 'undefined' && process.env.NODE_ENV === 'test'\nconst MARKDOWN_CLASSNAME =\n 'text-sm text-foreground break-words [&>*]:mb-2 [&>*:last-child]:mb-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 [&_pre]:rounded-md [&_pre]:bg-muted [&_pre]:p-3 [&_pre]:text-xs'\n\ntype MarkdownPreviewProps = { children: string; className?: string; remarkPlugins?: PluggableList }\n\nconst MarkdownPreview: React.ComponentType<MarkdownPreviewProps> = isTestEnv\n ? ({ children, className }) => <div className={className}>{children}</div>\n : (dynamic(() => import('react-markdown').then((mod) => mod.default as React.ComponentType<MarkdownPreviewProps>), {\n ssr: false,\n loading: () => null,\n }) as unknown as React.ComponentType<MarkdownPreviewProps>)\n\nlet markdownPluginsPromise: Promise<PluggableList> | null = null\n\nasync function loadMarkdownPlugins(): Promise<PluggableList> {\n if (isTestEnv) return []\n if (!markdownPluginsPromise) {\n markdownPluginsPromise = import('remark-gfm')\n .then((mod) => [mod.default ?? mod] as PluggableList)\n .catch(() => [])\n }\n return markdownPluginsPromise\n}\n\ntype TeamRow = {\n id: string\n name: string\n description: string | null\n isActive: boolean\n updatedAt: string | null\n memberCount: number\n}\n\ntype TeamsResponse = {\n items?: Array<Record<string, unknown>>\n total?: number\n totalPages?: number\n}\n\nexport default function StaffTeamsPage() {\n const t = useT()\n const router = useRouter()\n const scopeVersion = useOrganizationScopeVersion()\n const [rows, setRows] = React.useState<TeamRow[]>([])\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 const [markdownPlugins, setMarkdownPlugins] = React.useState<PluggableList>([])\n\n React.useEffect(() => {\n void loadMarkdownPlugins().then((plugins) => setMarkdownPlugins(plugins))\n }, [])\n\n const labels = React.useMemo(() => ({\n title: t('staff.teams.page.title', 'Teams'),\n description: t('staff.teams.page.description', 'Group team members and roles.'),\n table: {\n name: t('staff.teams.table.name', 'Name'),\n description: t('staff.teams.table.description', 'Description'),\n active: t('staff.teams.table.active', 'Active'),\n members: t('staff.teams.table.members', 'Team members'),\n updatedAt: t('staff.teams.table.updatedAt', 'Updated'),\n empty: t('staff.teams.table.empty', 'No teams yet.'),\n search: t('staff.teams.table.search', 'Search teams...'),\n },\n actions: {\n add: t('staff.teams.actions.add', 'Add team'),\n edit: t('staff.teams.actions.edit', 'Edit'),\n delete: t('staff.teams.actions.delete', 'Delete'),\n deleteConfirm: t('staff.teams.actions.deleteConfirm', 'Delete team \"{{name}}\"?'),\n showMembers: t('staff.teams.actions.showMembers', 'Show team members ({{count}})'),\n refresh: t('staff.teams.actions.refresh', 'Refresh'),\n },\n messages: {\n deleted: t('staff.teams.messages.deleted', 'Team deleted.'),\n },\n errors: {\n load: t('staff.teams.errors.load', 'Failed to load teams.'),\n delete: t('staff.teams.errors.delete', 'Failed to delete team.'),\n deleteAssigned: t('staff.teams.errors.deleteAssigned', 'Team has assigned members and cannot be deleted.'),\n },\n }), [t])\n\n const columns = React.useMemo<ColumnDef<TeamRow>[]>(() => [\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 <MarkdownPreview\n remarkPlugins={markdownPlugins}\n className={`${MARKDOWN_CLASSNAME} text-xs text-muted-foreground line-clamp-2`}\n >\n {row.original.description}\n </MarkdownPreview>\n ) : null}\n </div>\n ),\n },\n {\n accessorKey: 'description',\n header: labels.table.description,\n meta: { priority: 4 },\n cell: ({ row }) => row.original.description\n ? (\n <MarkdownPreview remarkPlugins={markdownPlugins} className={MARKDOWN_CLASSNAME}>\n {row.original.description}\n </MarkdownPreview>\n )\n : <span className=\"text-xs text-muted-foreground\">-</span>,\n },\n {\n accessorKey: 'isActive',\n header: labels.table.active,\n meta: { priority: 2 },\n cell: ({ row }) => <BooleanIcon value={row.original.isActive} />,\n },\n {\n accessorKey: 'memberCount',\n header: () => <span className=\"inline-block min-w-[250px]\">{labels.table.members}</span>,\n meta: { priority: 3 },\n enableSorting: false,\n cell: ({ row }) => (\n <Link\n className=\"inline-flex min-w-[220px] items-center gap-2 text-sm text-muted-foreground hover:text-foreground\"\n href={`/backend/staff/team-members?teamId=${encodeURIComponent(row.original.id)}`}\n onClick={(event) => event.stopPropagation()}\n >\n <Users className=\"h-4 w-4\" aria-hidden />\n {labels.actions.showMembers.replace('{{count}}', String(row.original.memberCount))}\n </Link>\n ),\n },\n {\n accessorKey: 'updatedAt',\n header: labels.table.updatedAt,\n meta: { priority: 5 },\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 ], [\n labels.actions.showMembers,\n labels.table.active,\n labels.table.description,\n labels.table.members,\n labels.table.name,\n labels.table.updatedAt,\n markdownPlugins,\n ])\n\n const loadTeams = 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<TeamsResponse>(\n `/api/staff/teams?${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(mapApiTeam))\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('staff.teams.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 loadTeams()\n }, [loadTeams, 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: TeamRow) => {\n if (entry.memberCount > 0) {\n flash(labels.errors.deleteAssigned, 'error')\n return\n }\n const message = labels.actions.deleteConfirm.replace('{{name}}', entry.name)\n if (typeof window !== 'undefined' && !window.confirm(message)) return\n try {\n await deleteCrud('staff/teams', entry.id, { errorMessage: labels.errors.delete })\n flash(labels.messages.deleted, 'success')\n handleRefresh()\n } catch (error) {\n console.error('staff.teams.delete', error)\n flash(labels.errors.delete, 'error')\n }\n }, [handleRefresh, labels.actions.deleteConfirm, labels.errors.delete, labels.errors.deleteAssigned, labels.messages.deleted])\n\n return (\n <Page>\n <PageBody>\n <DataTable<TeamRow>\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/staff/teams/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/staff/teams/${row.id}/edit` },\n ...(row.memberCount > 0\n ? []\n : [{ label: labels.actions.delete, destructive: true, onSelect: () => { void handleDelete(row) } }]),\n ]}\n />\n )}\n onRowClick={(row) => router.push(`/backend/staff/teams/${row.id}/edit`)}\n />\n </PageBody>\n </Page>\n )\n}\n\nfunction mapApiTeam(item: Record<string, unknown>): TeamRow {\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.trim().length ? item.description.trim() : null\n const updatedAt = typeof item.updatedAt === 'string'\n ? item.updatedAt\n : typeof item.updated_at === 'string'\n ? item.updated_at\n : null\n const isActive = typeof item.isActive === 'boolean'\n ? item.isActive\n : typeof item.is_active === 'boolean'\n ? item.is_active\n : true\n const memberCount = typeof item.memberCount === 'number'\n ? item.memberCount\n : typeof item.member_count === 'number'\n ? item.member_count\n : 0\n return { id, name, description, isActive, updatedAt, memberCount }\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
|
}
|
|
@@ -14,9 +14,6 @@ import {
|
|
|
14
14
|
} from "../data/validators.js";
|
|
15
15
|
import { ensureOrganizationScope, ensureTenantScope, extractUndoPayload, requireTeamMember } from "./shared.js";
|
|
16
16
|
import { E } from "../../../generated/entities.ids.generated.js";
|
|
17
|
-
import { resolveNotificationService } from "../../notifications/lib/notificationService.js";
|
|
18
|
-
import { buildFeatureNotificationFromType, buildNotificationFromType } from "../../notifications/lib/notificationBuilder.js";
|
|
19
|
-
import { notificationTypes } from "../notifications.js";
|
|
20
17
|
const leaveRequestCrudIndexer = {
|
|
21
18
|
entityType: E.staff.staff_leave_request
|
|
22
19
|
};
|
|
@@ -195,31 +192,6 @@ const createLeaveRequestCommand = {
|
|
|
195
192
|
},
|
|
196
193
|
indexer: leaveRequestCrudIndexer
|
|
197
194
|
});
|
|
198
|
-
try {
|
|
199
|
-
const notificationService = resolveNotificationService(ctx.container);
|
|
200
|
-
const typeDef = notificationTypes.find((type) => type.type === "staff.leave_request.pending");
|
|
201
|
-
if (typeDef) {
|
|
202
|
-
const memberName = member.displayName || "Team member";
|
|
203
|
-
const startDateStr = request.startDate.toLocaleDateString();
|
|
204
|
-
const endDateStr = request.endDate.toLocaleDateString();
|
|
205
|
-
const notificationInput = buildFeatureNotificationFromType(typeDef, {
|
|
206
|
-
requiredFeature: "staff.leave_requests.manage",
|
|
207
|
-
bodyVariables: {
|
|
208
|
-
memberName,
|
|
209
|
-
startDate: startDateStr,
|
|
210
|
-
endDate: endDateStr
|
|
211
|
-
},
|
|
212
|
-
sourceEntityType: "staff:leave_request",
|
|
213
|
-
sourceEntityId: request.id,
|
|
214
|
-
linkHref: `/backend/staff/leave-requests/${request.id}`
|
|
215
|
-
});
|
|
216
|
-
await notificationService.createForFeature(notificationInput, {
|
|
217
|
-
tenantId: request.tenantId,
|
|
218
|
-
organizationId: request.organizationId
|
|
219
|
-
});
|
|
220
|
-
}
|
|
221
|
-
} catch {
|
|
222
|
-
}
|
|
223
195
|
return { requestId: request.id };
|
|
224
196
|
},
|
|
225
197
|
captureAfter: async (_input, result, ctx) => {
|
|
@@ -518,31 +490,6 @@ const acceptLeaveRequestCommand = {
|
|
|
518
490
|
organizationId: request.organizationId,
|
|
519
491
|
ruleIds: createdRuleIds
|
|
520
492
|
});
|
|
521
|
-
if (request.submittedByUserId) {
|
|
522
|
-
try {
|
|
523
|
-
const notificationService = resolveNotificationService(ctx.container);
|
|
524
|
-
const typeDef = notificationTypes.find((type) => type.type === "staff.leave_request.approved");
|
|
525
|
-
if (typeDef) {
|
|
526
|
-
const startDateStr = request.startDate.toLocaleDateString();
|
|
527
|
-
const endDateStr = request.endDate.toLocaleDateString();
|
|
528
|
-
const notificationInput = buildNotificationFromType(typeDef, {
|
|
529
|
-
recipientUserId: request.submittedByUserId,
|
|
530
|
-
bodyVariables: {
|
|
531
|
-
startDate: startDateStr,
|
|
532
|
-
endDate: endDateStr
|
|
533
|
-
},
|
|
534
|
-
sourceEntityType: "staff:leave_request",
|
|
535
|
-
sourceEntityId: request.id,
|
|
536
|
-
linkHref: `/backend/staff/leave-requests/${request.id}`
|
|
537
|
-
});
|
|
538
|
-
await notificationService.create(notificationInput, {
|
|
539
|
-
tenantId: request.tenantId,
|
|
540
|
-
organizationId: request.organizationId
|
|
541
|
-
});
|
|
542
|
-
}
|
|
543
|
-
} catch {
|
|
544
|
-
}
|
|
545
|
-
}
|
|
546
493
|
return { requestId: request.id, ruleIds: createdRuleIds };
|
|
547
494
|
},
|
|
548
495
|
buildLog: async ({ result, ctx, snapshots }) => {
|
|
@@ -657,32 +604,6 @@ const rejectLeaveRequestCommand = {
|
|
|
657
604
|
},
|
|
658
605
|
indexer: leaveRequestCrudIndexer
|
|
659
606
|
});
|
|
660
|
-
if (request.submittedByUserId) {
|
|
661
|
-
try {
|
|
662
|
-
const notificationService = resolveNotificationService(ctx.container);
|
|
663
|
-
const typeDef = notificationTypes.find((type) => type.type === "staff.leave_request.rejected");
|
|
664
|
-
if (typeDef) {
|
|
665
|
-
const startDateStr = request.startDate.toLocaleDateString();
|
|
666
|
-
const endDateStr = request.endDate.toLocaleDateString();
|
|
667
|
-
const notificationInput = buildNotificationFromType(typeDef, {
|
|
668
|
-
recipientUserId: request.submittedByUserId,
|
|
669
|
-
bodyVariables: {
|
|
670
|
-
startDate: startDateStr,
|
|
671
|
-
endDate: endDateStr,
|
|
672
|
-
reason: request.decisionComment ?? ""
|
|
673
|
-
},
|
|
674
|
-
sourceEntityType: "staff:leave_request",
|
|
675
|
-
sourceEntityId: request.id,
|
|
676
|
-
linkHref: `/backend/staff/leave-requests/${request.id}`
|
|
677
|
-
});
|
|
678
|
-
await notificationService.create(notificationInput, {
|
|
679
|
-
tenantId: request.tenantId,
|
|
680
|
-
organizationId: request.organizationId
|
|
681
|
-
});
|
|
682
|
-
}
|
|
683
|
-
} catch {
|
|
684
|
-
}
|
|
685
|
-
}
|
|
686
607
|
return { requestId: request.id };
|
|
687
608
|
},
|
|
688
609
|
async prepare(rawInput, ctx) {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/modules/staff/commands/leave-requests.ts"],
|
|
4
|
-
"sourcesContent": ["import { randomUUID } from 'crypto'\nimport type { CommandHandler, CommandRuntimeContext } from '@open-mercato/shared/lib/commands'\nimport { registerCommand } from '@open-mercato/shared/lib/commands'\nimport type { EntityManager } from '@mikro-orm/postgresql'\nimport { CrudHttpError } from '@open-mercato/shared/lib/crud/errors'\nimport { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\nimport { emitCrudSideEffects, emitCrudUndoSideEffects, buildChanges } from '@open-mercato/shared/lib/commands/helpers'\nimport type { CrudIndexerConfig } from '@open-mercato/shared/lib/crud/types'\nimport type { DataEngine } from '@open-mercato/shared/lib/data/engine'\nimport { invalidateCrudCache } from '@open-mercato/shared/lib/crud/cache'\nimport { findOneWithDecryption } from '@open-mercato/shared/lib/encryption/find'\nimport { PlannerAvailabilityRule } from '@open-mercato/core/modules/planner/data/entities'\nimport { StaffLeaveRequest, type StaffLeaveRequestStatus } from '../data/entities'\nimport {\n staffLeaveRequestCreateSchema,\n staffLeaveRequestDecisionSchema,\n staffLeaveRequestUpdateSchema,\n type StaffLeaveRequestCreateInput,\n type StaffLeaveRequestDecisionInput,\n type StaffLeaveRequestUpdateInput,\n} from '../data/validators'\nimport { ensureOrganizationScope, ensureTenantScope, extractUndoPayload, requireTeamMember } from './shared'\nimport { E } from '#generated/entities.ids.generated'\nimport { resolveNotificationService } from '../../notifications/lib/notificationService'\nimport { buildFeatureNotificationFromType, buildNotificationFromType } from '../../notifications/lib/notificationBuilder'\nimport { notificationTypes } from '../notifications'\n\nconst leaveRequestCrudIndexer: CrudIndexerConfig<StaffLeaveRequest> = {\n entityType: E.staff.staff_leave_request,\n}\n\nconst availabilityRuleCrudIndexer: CrudIndexerConfig<PlannerAvailabilityRule> = {\n entityType: E.planner.planner_availability_rule,\n cacheAliases: ['planner.availability'],\n}\n\ntype LeaveRequestSnapshot = {\n id: string\n tenantId: string\n organizationId: string\n memberId: string\n startDate: string\n endDate: string\n timezone: string\n status: StaffLeaveRequestStatus\n unavailabilityReasonEntryId: string | null\n unavailabilityReasonValue: string | null\n note: string | null\n decisionComment: string | null\n submittedByUserId: string | null\n decidedByUserId: string | null\n decidedAt: string | null\n deletedAt: string | null\n createdAt: string | null\n updatedAt: string | null\n}\n\ntype LeaveRequestUndoPayload = {\n before?: LeaveRequestSnapshot | null\n after?: LeaveRequestSnapshot | null\n availabilityRuleIds?: string[]\n}\n\nfunction parseUuidCandidate(value: string | null | undefined): string | null {\n if (!value) return null\n const uuidRegex = /^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-5][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}$/\n return uuidRegex.test(value) ? value : null\n}\n\nfunction resolveAuthUserId(ctx: { auth?: { sub?: string | null; isApiKey?: boolean } | null }): string | null {\n if (!ctx.auth || ctx.auth.isApiKey) return null\n return parseUuidCandidate(ctx.auth.sub ?? null)\n}\n\nfunction formatDateKey(value: Date): string {\n const year = value.getUTCFullYear()\n const month = String(value.getUTCMonth() + 1).padStart(2, '0')\n const day = String(value.getUTCDate()).padStart(2, '0')\n return `${year}-${month}-${day}`\n}\n\nfunction listDateKeysInRange(start: Date, end: Date): string[] {\n const dates: string[] = []\n const current = new Date(Date.UTC(start.getUTCFullYear(), start.getUTCMonth(), start.getUTCDate()))\n const last = new Date(Date.UTC(end.getUTCFullYear(), end.getUTCMonth(), end.getUTCDate()))\n while (current <= last) {\n dates.push(formatDateKey(current))\n current.setUTCDate(current.getUTCDate() + 1)\n }\n return dates\n}\n\nfunction formatDuration(minutes: number): string {\n const clamped = Math.max(1, minutes)\n const hours = Math.floor(clamped / 60)\n const mins = clamped % 60\n if (hours > 0 && mins > 0) return `PT${hours}H${mins}M`\n if (hours > 0) return `PT${hours}H`\n return `PT${mins}M`\n}\n\nfunction buildAvailabilityRrule(start: Date, end: Date): string {\n const dtStart = start.toISOString().replace(/[-:]/g, '').split('.')[0] + 'Z'\n const durationMinutes = Math.max(1, Math.round((end.getTime() - start.getTime()) / 60000))\n const duration = formatDuration(durationMinutes)\n return `DTSTART:${dtStart}\\nDURATION:${duration}\\nRRULE:FREQ=DAILY;COUNT=1`\n}\n\nfunction buildFullDayRrule(date: string): string | null {\n const [year, month, day] = date.split('-').map((part) => Number(part))\n if (!Number.isFinite(year) || !Number.isFinite(month) || !Number.isFinite(day)) return null\n const start = new Date(Date.UTC(year, month - 1, day, 0, 0, 0))\n const end = new Date(start.getTime() + 24 * 60 * 60 * 1000)\n return buildAvailabilityRrule(start, end)\n}\n\nasync function loadLeaveRequestSnapshot(em: EntityManager, id: string): Promise<LeaveRequestSnapshot | null> {\n const request = await findOneWithDecryption(em, StaffLeaveRequest, { id }, undefined, { tenantId: null, organizationId: null })\n if (!request) return null\n const memberId = typeof request.member === 'string' ? request.member : request.member.id\n return {\n id: request.id,\n tenantId: request.tenantId,\n organizationId: request.organizationId,\n memberId,\n startDate: request.startDate.toISOString(),\n endDate: request.endDate.toISOString(),\n timezone: request.timezone,\n status: request.status,\n unavailabilityReasonEntryId: request.unavailabilityReasonEntryId ?? null,\n unavailabilityReasonValue: request.unavailabilityReasonValue ?? null,\n note: request.note ?? null,\n decisionComment: request.decisionComment ?? null,\n submittedByUserId: request.submittedByUserId ?? null,\n decidedByUserId: request.decidedByUserId ?? null,\n decidedAt: request.decidedAt ? request.decidedAt.toISOString() : null,\n deletedAt: request.deletedAt ? request.deletedAt.toISOString() : null,\n createdAt: request.createdAt ? request.createdAt.toISOString() : null,\n updatedAt: request.updatedAt ? request.updatedAt.toISOString() : null,\n }\n}\n\nasync function requireLeaveRequest(em: EntityManager, id: string): Promise<StaffLeaveRequest> {\n const request = await findOneWithDecryption(em, StaffLeaveRequest, { id, deletedAt: null }, undefined, { tenantId: null, organizationId: null })\n if (!request) throw new CrudHttpError(404, { error: 'Leave request not found.' })\n return request\n}\n\nfunction ensurePendingStatus(request: StaffLeaveRequest): void {\n if (request.status !== 'pending') {\n throw new CrudHttpError(400, { error: 'Leave request is already finalized.' })\n }\n}\n\nasync function createUnavailabilityRules(params: {\n em: EntityManager\n tenantId: string\n organizationId: string\n memberId: string\n timezone: string\n dates: string[]\n note: string | null\n reasonEntryId: string | null\n reasonValue: string | null\n}): Promise<string[]> {\n const now = new Date()\n const createdIds: string[] = []\n params.dates.forEach((date) => {\n const rrule = buildFullDayRrule(date)\n if (!rrule) return\n const ruleId = randomUUID()\n const rule = params.em.create(PlannerAvailabilityRule, {\n id: ruleId,\n tenantId: params.tenantId,\n organizationId: params.organizationId,\n subjectType: 'member',\n subjectId: params.memberId,\n timezone: params.timezone,\n rrule,\n exdates: [],\n kind: 'unavailability',\n note: params.note,\n unavailabilityReasonEntryId: params.reasonEntryId,\n unavailabilityReasonValue: params.reasonValue,\n createdAt: now,\n updatedAt: now,\n deletedAt: null,\n })\n params.em.persist(rule)\n createdIds.push(ruleId)\n })\n return createdIds\n}\n\nasync function invalidateAvailabilityCache(params: {\n container: CommandRuntimeContext['container']\n tenantId: string | null\n organizationId: string | null\n ruleIds: string[]\n}) {\n if (!params.ruleIds.length) return\n const resource = 'planner.availability'\n const fallbackTenant = params.tenantId ?? null\n for (const ruleId of params.ruleIds) {\n await invalidateCrudCache(\n params.container,\n resource,\n { id: ruleId, organizationId: params.organizationId, tenantId: params.tenantId },\n fallbackTenant,\n 'updated',\n )\n }\n}\n\nconst createLeaveRequestCommand: CommandHandler<StaffLeaveRequestCreateInput, { requestId: string }> = {\n id: 'staff.leave-requests.create',\n async execute(rawInput, ctx) {\n const parsed = staffLeaveRequestCreateSchema.parse(rawInput)\n ensureTenantScope(ctx, parsed.tenantId)\n ensureOrganizationScope(ctx, parsed.organizationId)\n\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const member = await requireTeamMember(em, parsed.memberId, 'Team member not found')\n ensureTenantScope(ctx, member.tenantId)\n ensureOrganizationScope(ctx, member.organizationId)\n\n const submittedByUserId = parsed.submittedByUserId ?? resolveAuthUserId(ctx)\n const now = new Date()\n const request = em.create(StaffLeaveRequest, {\n tenantId: parsed.tenantId,\n organizationId: parsed.organizationId,\n member,\n startDate: parsed.startDate,\n endDate: parsed.endDate,\n timezone: parsed.timezone,\n status: 'pending',\n unavailabilityReasonEntryId: parsed.unavailabilityReasonEntryId ?? null,\n unavailabilityReasonValue: parsed.unavailabilityReasonValue ?? null,\n note: parsed.note ?? null,\n decisionComment: null,\n submittedByUserId,\n decidedByUserId: null,\n decidedAt: null,\n createdAt: now,\n updatedAt: now,\n deletedAt: null,\n })\n em.persist(request)\n await em.flush()\n\n const de = (ctx.container.resolve('dataEngine') as DataEngine)\n await emitCrudSideEffects({\n dataEngine: de,\n action: 'created',\n entity: request,\n identifiers: {\n id: request.id,\n organizationId: request.organizationId,\n tenantId: request.tenantId,\n },\n indexer: leaveRequestCrudIndexer,\n })\n\n // Create notification for users who can approve/reject leave requests\n try {\n const notificationService = resolveNotificationService(ctx.container)\n const typeDef = notificationTypes.find((type) => type.type === 'staff.leave_request.pending')\n if (typeDef) {\n const memberName = member.displayName || 'Team member'\n const startDateStr = request.startDate.toLocaleDateString()\n const endDateStr = request.endDate.toLocaleDateString()\n\n const notificationInput = buildFeatureNotificationFromType(typeDef, {\n requiredFeature: 'staff.leave_requests.manage',\n bodyVariables: {\n memberName,\n startDate: startDateStr,\n endDate: endDateStr,\n },\n sourceEntityType: 'staff:leave_request',\n sourceEntityId: request.id,\n linkHref: `/backend/staff/leave-requests/${request.id}`,\n })\n\n await notificationService.createForFeature(notificationInput, {\n tenantId: request.tenantId,\n organizationId: request.organizationId,\n })\n }\n } catch {\n // Notification creation is non-critical, don't fail the command\n }\n\n return { requestId: request.id }\n },\n captureAfter: async (_input, result, ctx) => {\n const em = (ctx.container.resolve('em') as EntityManager)\n return await loadLeaveRequestSnapshot(em, result.requestId)\n },\n buildLog: async ({ result, ctx }) => {\n const { translate } = await resolveTranslations()\n const em = (ctx.container.resolve('em') as EntityManager)\n const snapshot = await loadLeaveRequestSnapshot(em, result.requestId)\n return {\n actionLabel: translate('staff.audit.leaveRequests.create', 'Create leave request'),\n resourceKind: 'staff.leave_request',\n resourceId: result.requestId,\n tenantId: snapshot?.tenantId ?? null,\n organizationId: snapshot?.organizationId ?? null,\n snapshotAfter: snapshot ?? null,\n payload: {\n undo: {\n after: snapshot ?? null,\n } satisfies LeaveRequestUndoPayload,\n },\n }\n },\n undo: async ({ logEntry, ctx }) => {\n const payload = extractUndoPayload<LeaveRequestUndoPayload>(logEntry)\n const after = payload?.after\n if (!after) return\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const request = await em.findOne(StaffLeaveRequest, { id: after.id })\n if (request) {\n request.deletedAt = new Date()\n request.updatedAt = new Date()\n await em.flush()\n\n const de = (ctx.container.resolve('dataEngine') as DataEngine)\n await emitCrudUndoSideEffects({\n dataEngine: de,\n action: 'deleted',\n entity: request,\n identifiers: {\n id: request.id,\n organizationId: request.organizationId,\n tenantId: request.tenantId,\n },\n indexer: leaveRequestCrudIndexer,\n })\n }\n },\n}\n\nconst updateLeaveRequestCommand: CommandHandler<StaffLeaveRequestUpdateInput, { requestId: string }> = {\n id: 'staff.leave-requests.update',\n async prepare(rawInput, ctx) {\n const parsed = staffLeaveRequestUpdateSchema.parse(rawInput)\n const em = (ctx.container.resolve('em') as EntityManager)\n const snapshot = await loadLeaveRequestSnapshot(em, parsed.id)\n return snapshot ? { before: snapshot } : {}\n },\n async execute(rawInput, ctx) {\n const parsed = staffLeaveRequestUpdateSchema.parse(rawInput)\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const request = await requireLeaveRequest(em, parsed.id)\n ensureTenantScope(ctx, request.tenantId)\n ensureOrganizationScope(ctx, request.organizationId)\n ensurePendingStatus(request)\n\n if (parsed.memberId !== undefined) {\n const member = await requireTeamMember(em, parsed.memberId, 'Team member not found')\n ensureTenantScope(ctx, member.tenantId)\n ensureOrganizationScope(ctx, member.organizationId)\n request.member = member\n }\n if (parsed.startDate !== undefined) request.startDate = parsed.startDate\n if (parsed.endDate !== undefined) request.endDate = parsed.endDate\n if (parsed.timezone !== undefined) request.timezone = parsed.timezone\n if (parsed.unavailabilityReasonEntryId !== undefined) request.unavailabilityReasonEntryId = parsed.unavailabilityReasonEntryId ?? null\n if (parsed.unavailabilityReasonValue !== undefined) request.unavailabilityReasonValue = parsed.unavailabilityReasonValue ?? null\n if (parsed.note !== undefined) request.note = parsed.note ?? null\n request.updatedAt = new Date()\n await em.flush()\n\n const de = (ctx.container.resolve('dataEngine') as DataEngine)\n await emitCrudSideEffects({\n dataEngine: de,\n action: 'updated',\n entity: request,\n identifiers: {\n id: request.id,\n organizationId: request.organizationId,\n tenantId: request.tenantId,\n },\n indexer: leaveRequestCrudIndexer,\n })\n\n return { requestId: request.id }\n },\n buildLog: async ({ snapshots, ctx }) => {\n const { translate } = await resolveTranslations()\n const before = snapshots.before as LeaveRequestSnapshot | undefined\n if (!before) return null\n const em = (ctx.container.resolve('em') as EntityManager)\n const after = await loadLeaveRequestSnapshot(em, before.id)\n const changes = after\n ? buildChanges(before as unknown as Record<string, unknown>, after as unknown as Record<string, unknown>, [\n 'memberId',\n 'startDate',\n 'endDate',\n 'timezone',\n 'unavailabilityReasonEntryId',\n 'unavailabilityReasonValue',\n 'note',\n ])\n : {}\n return {\n actionLabel: translate('staff.audit.leaveRequests.update', 'Update leave request'),\n resourceKind: 'staff.leave_request',\n resourceId: before.id,\n tenantId: before.tenantId,\n organizationId: before.organizationId,\n snapshotBefore: before,\n snapshotAfter: after ?? null,\n changes,\n payload: {\n undo: {\n before,\n after: after ?? null,\n } satisfies LeaveRequestUndoPayload,\n },\n }\n },\n undo: async ({ logEntry, ctx }) => {\n const payload = extractUndoPayload<LeaveRequestUndoPayload>(logEntry)\n const before = payload?.before\n const after = payload?.after\n if (!before || !after) return\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const request = await em.findOne(StaffLeaveRequest, { id: after.id })\n if (!request) return\n request.startDate = new Date(before.startDate)\n request.endDate = new Date(before.endDate)\n request.timezone = before.timezone\n request.status = before.status\n request.unavailabilityReasonEntryId = before.unavailabilityReasonEntryId\n request.unavailabilityReasonValue = before.unavailabilityReasonValue\n request.note = before.note\n request.decisionComment = before.decisionComment\n request.decidedByUserId = before.decidedByUserId\n request.decidedAt = before.decidedAt ? new Date(before.decidedAt) : null\n request.updatedAt = new Date()\n await em.flush()\n\n const de = (ctx.container.resolve('dataEngine') as DataEngine)\n await emitCrudUndoSideEffects({\n dataEngine: de,\n action: 'updated',\n entity: request,\n identifiers: {\n id: request.id,\n organizationId: request.organizationId,\n tenantId: request.tenantId,\n },\n indexer: leaveRequestCrudIndexer,\n })\n },\n}\n\nconst deleteLeaveRequestCommand: CommandHandler<{ id: string }, { requestId: string }> = {\n id: 'staff.leave-requests.delete',\n async execute(rawInput, ctx) {\n const parsed = staffLeaveRequestDecisionSchema.pick({ id: true }).parse(rawInput)\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const request = await requireLeaveRequest(em, parsed.id)\n ensureTenantScope(ctx, request.tenantId)\n ensureOrganizationScope(ctx, request.organizationId)\n ensurePendingStatus(request)\n\n request.deletedAt = new Date()\n request.updatedAt = new Date()\n await em.flush()\n\n const de = (ctx.container.resolve('dataEngine') as DataEngine)\n await emitCrudSideEffects({\n dataEngine: de,\n action: 'deleted',\n entity: request,\n identifiers: {\n id: request.id,\n organizationId: request.organizationId,\n tenantId: request.tenantId,\n },\n indexer: leaveRequestCrudIndexer,\n })\n\n return { requestId: request.id }\n },\n captureAfter: async (_input, result, ctx) => {\n const em = (ctx.container.resolve('em') as EntityManager)\n return await loadLeaveRequestSnapshot(em, result.requestId)\n },\n buildLog: async ({ result, ctx }) => {\n const { translate } = await resolveTranslations()\n const em = (ctx.container.resolve('em') as EntityManager)\n const snapshot = await loadLeaveRequestSnapshot(em, result.requestId)\n return {\n actionLabel: translate('staff.audit.leaveRequests.delete', 'Delete leave request'),\n resourceKind: 'staff.leave_request',\n resourceId: result.requestId,\n tenantId: snapshot?.tenantId ?? null,\n organizationId: snapshot?.organizationId ?? null,\n snapshotAfter: snapshot ?? null,\n payload: {\n undo: {\n after: snapshot ?? null,\n } satisfies LeaveRequestUndoPayload,\n },\n }\n },\n undo: async ({ logEntry, ctx }) => {\n const payload = extractUndoPayload<LeaveRequestUndoPayload>(logEntry)\n const after = payload?.after\n if (!after) return\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const request = await em.findOne(StaffLeaveRequest, { id: after.id })\n if (!request) return\n request.deletedAt = null\n request.updatedAt = new Date()\n await em.flush()\n\n const de = (ctx.container.resolve('dataEngine') as DataEngine)\n await emitCrudUndoSideEffects({\n dataEngine: de,\n action: 'created',\n entity: request,\n identifiers: {\n id: request.id,\n organizationId: request.organizationId,\n tenantId: request.tenantId,\n },\n indexer: leaveRequestCrudIndexer,\n })\n },\n}\n\nconst acceptLeaveRequestCommand: CommandHandler<StaffLeaveRequestDecisionInput, { requestId: string; ruleIds: string[] }> = {\n id: 'staff.leave-requests.accept',\n async execute(rawInput, ctx) {\n const parsed = staffLeaveRequestDecisionSchema.parse(rawInput)\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const request = await requireLeaveRequest(em, parsed.id)\n ensureTenantScope(ctx, request.tenantId)\n ensureOrganizationScope(ctx, request.organizationId)\n ensurePendingStatus(request)\n\n const memberId = typeof request.member === 'string' ? request.member : request.member.id\n const decidedByUserId = parsed.decidedByUserId ?? resolveAuthUserId(ctx)\n const now = new Date()\n const dates = listDateKeysInRange(request.startDate, request.endDate)\n let createdRuleIds: string[] = []\n\n await em.transactional(async (trx) => {\n request.status = 'approved'\n request.decisionComment = parsed.decisionComment ?? null\n request.decidedByUserId = decidedByUserId\n request.decidedAt = now\n request.updatedAt = now\n trx.persist(request)\n\n createdRuleIds = await createUnavailabilityRules({\n em: trx,\n tenantId: request.tenantId,\n organizationId: request.organizationId,\n memberId,\n timezone: request.timezone,\n dates,\n note: request.note ?? null,\n reasonEntryId: request.unavailabilityReasonEntryId ?? null,\n reasonValue: request.unavailabilityReasonValue ?? null,\n })\n await trx.flush()\n })\n\n const de = (ctx.container.resolve('dataEngine') as DataEngine)\n await emitCrudSideEffects({\n dataEngine: de,\n action: 'updated',\n entity: request,\n identifiers: {\n id: request.id,\n organizationId: request.organizationId,\n tenantId: request.tenantId,\n },\n indexer: leaveRequestCrudIndexer,\n })\n if (createdRuleIds.length) {\n const rules = await em.find(PlannerAvailabilityRule, { id: { $in: createdRuleIds } })\n for (const rule of rules) {\n await emitCrudSideEffects({\n dataEngine: de,\n action: 'created',\n entity: rule,\n identifiers: {\n id: rule.id,\n organizationId: rule.organizationId,\n tenantId: rule.tenantId,\n },\n indexer: availabilityRuleCrudIndexer,\n })\n }\n }\n await invalidateAvailabilityCache({\n container: ctx.container,\n tenantId: request.tenantId,\n organizationId: request.organizationId,\n ruleIds: createdRuleIds,\n })\n\n // Send notification to the requester\n if (request.submittedByUserId) {\n try {\n const notificationService = resolveNotificationService(ctx.container)\n const typeDef = notificationTypes.find((type) => type.type === 'staff.leave_request.approved')\n if (typeDef) {\n const startDateStr = request.startDate.toLocaleDateString()\n const endDateStr = request.endDate.toLocaleDateString()\n\n const notificationInput = buildNotificationFromType(typeDef, {\n recipientUserId: request.submittedByUserId,\n bodyVariables: {\n startDate: startDateStr,\n endDate: endDateStr,\n },\n sourceEntityType: 'staff:leave_request',\n sourceEntityId: request.id,\n linkHref: `/backend/staff/leave-requests/${request.id}`,\n })\n\n await notificationService.create(notificationInput, {\n tenantId: request.tenantId,\n organizationId: request.organizationId,\n })\n }\n } catch {\n // Notification creation is non-critical, don't fail the command\n }\n }\n\n return { requestId: request.id, ruleIds: createdRuleIds }\n },\n buildLog: async ({ result, ctx, snapshots }) => {\n const { translate } = await resolveTranslations()\n const before = snapshots.before as LeaveRequestSnapshot | undefined\n const em = (ctx.container.resolve('em') as EntityManager)\n const after = await loadLeaveRequestSnapshot(em, result.requestId)\n return {\n actionLabel: translate('staff.audit.leaveRequests.accept', 'Approve leave request'),\n resourceKind: 'staff.leave_request',\n resourceId: result.requestId,\n tenantId: after?.tenantId ?? before?.tenantId ?? null,\n organizationId: after?.organizationId ?? before?.organizationId ?? null,\n snapshotBefore: before ?? null,\n snapshotAfter: after ?? null,\n payload: {\n undo: {\n before: before ?? null,\n after: after ?? null,\n availabilityRuleIds: result.ruleIds,\n } satisfies LeaveRequestUndoPayload,\n },\n }\n },\n async prepare(rawInput, ctx) {\n const parsed = staffLeaveRequestDecisionSchema.parse(rawInput)\n const em = (ctx.container.resolve('em') as EntityManager)\n const snapshot = await loadLeaveRequestSnapshot(em, parsed.id)\n return snapshot ? { before: snapshot } : {}\n },\n undo: async ({ logEntry, ctx }) => {\n const payload = extractUndoPayload<LeaveRequestUndoPayload>(logEntry)\n const before = payload?.before\n const availabilityRuleIds = payload?.availabilityRuleIds ?? []\n if (!before) return\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const request = await em.findOne(StaffLeaveRequest, { id: before.id })\n if (!request) return\n request.status = before.status\n request.decisionComment = before.decisionComment\n request.decidedByUserId = before.decidedByUserId\n request.decidedAt = before.decidedAt ? new Date(before.decidedAt) : null\n request.updatedAt = new Date()\n await em.flush()\n\n const de = (ctx.container.resolve('dataEngine') as DataEngine)\n await emitCrudUndoSideEffects({\n dataEngine: de,\n action: 'updated',\n entity: request,\n identifiers: {\n id: request.id,\n organizationId: request.organizationId,\n tenantId: request.tenantId,\n },\n indexer: leaveRequestCrudIndexer,\n })\n\n if (availabilityRuleIds.length) {\n const rules = await em.find(PlannerAvailabilityRule, { id: { $in: availabilityRuleIds } })\n const now = new Date()\n rules.forEach((rule) => {\n rule.deletedAt = now\n rule.updatedAt = now\n })\n await em.flush()\n\n const de = (ctx.container.resolve('dataEngine') as DataEngine)\n for (const rule of rules) {\n await emitCrudUndoSideEffects({\n dataEngine: de,\n action: 'deleted',\n entity: rule,\n identifiers: {\n id: rule.id,\n organizationId: rule.organizationId,\n tenantId: rule.tenantId,\n },\n indexer: availabilityRuleCrudIndexer,\n })\n }\n }\n await invalidateAvailabilityCache({\n container: ctx.container,\n tenantId: before.tenantId,\n organizationId: before.organizationId,\n ruleIds: availabilityRuleIds,\n })\n },\n}\n\nconst rejectLeaveRequestCommand: CommandHandler<StaffLeaveRequestDecisionInput, { requestId: string }> = {\n id: 'staff.leave-requests.reject',\n async execute(rawInput, ctx) {\n const parsed = staffLeaveRequestDecisionSchema.parse(rawInput)\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const request = await requireLeaveRequest(em, parsed.id)\n ensureTenantScope(ctx, request.tenantId)\n ensureOrganizationScope(ctx, request.organizationId)\n ensurePendingStatus(request)\n\n request.status = 'rejected'\n request.decisionComment = parsed.decisionComment ?? null\n request.decidedByUserId = parsed.decidedByUserId ?? resolveAuthUserId(ctx)\n request.decidedAt = new Date()\n request.updatedAt = new Date()\n await em.flush()\n\n const de = (ctx.container.resolve('dataEngine') as DataEngine)\n await emitCrudSideEffects({\n dataEngine: de,\n action: 'updated',\n entity: request,\n identifiers: {\n id: request.id,\n organizationId: request.organizationId,\n tenantId: request.tenantId,\n },\n indexer: leaveRequestCrudIndexer,\n })\n\n // Send notification to the requester\n if (request.submittedByUserId) {\n try {\n const notificationService = resolveNotificationService(ctx.container)\n const typeDef = notificationTypes.find((type) => type.type === 'staff.leave_request.rejected')\n if (typeDef) {\n const startDateStr = request.startDate.toLocaleDateString()\n const endDateStr = request.endDate.toLocaleDateString()\n\n const notificationInput = buildNotificationFromType(typeDef, {\n recipientUserId: request.submittedByUserId,\n bodyVariables: {\n startDate: startDateStr,\n endDate: endDateStr,\n reason: request.decisionComment ?? '',\n },\n sourceEntityType: 'staff:leave_request',\n sourceEntityId: request.id,\n linkHref: `/backend/staff/leave-requests/${request.id}`,\n })\n\n await notificationService.create(notificationInput, {\n tenantId: request.tenantId,\n organizationId: request.organizationId,\n })\n }\n } catch {\n // Notification creation is non-critical, don't fail the command\n }\n }\n\n return { requestId: request.id }\n },\n async prepare(rawInput, ctx) {\n const parsed = staffLeaveRequestDecisionSchema.parse(rawInput)\n const em = (ctx.container.resolve('em') as EntityManager)\n const snapshot = await loadLeaveRequestSnapshot(em, parsed.id)\n return snapshot ? { before: snapshot } : {}\n },\n buildLog: async ({ result, ctx, snapshots }) => {\n const { translate } = await resolveTranslations()\n const before = snapshots.before as LeaveRequestSnapshot | undefined\n const em = (ctx.container.resolve('em') as EntityManager)\n const after = await loadLeaveRequestSnapshot(em, result.requestId)\n return {\n actionLabel: translate('staff.audit.leaveRequests.reject', 'Reject leave request'),\n resourceKind: 'staff.leave_request',\n resourceId: result.requestId,\n tenantId: after?.tenantId ?? before?.tenantId ?? null,\n organizationId: after?.organizationId ?? before?.organizationId ?? null,\n snapshotBefore: before ?? null,\n snapshotAfter: after ?? null,\n payload: {\n undo: {\n before: before ?? null,\n after: after ?? null,\n } satisfies LeaveRequestUndoPayload,\n },\n }\n },\n undo: async ({ logEntry, ctx }) => {\n const payload = extractUndoPayload<LeaveRequestUndoPayload>(logEntry)\n const before = payload?.before\n if (!before) return\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const request = await em.findOne(StaffLeaveRequest, { id: before.id })\n if (!request) return\n request.status = before.status\n request.decisionComment = before.decisionComment\n request.decidedByUserId = before.decidedByUserId\n request.decidedAt = before.decidedAt ? new Date(before.decidedAt) : null\n request.updatedAt = new Date()\n await em.flush()\n\n const de = (ctx.container.resolve('dataEngine') as DataEngine)\n await emitCrudUndoSideEffects({\n dataEngine: de,\n action: 'updated',\n entity: request,\n identifiers: {\n id: request.id,\n organizationId: request.organizationId,\n tenantId: request.tenantId,\n },\n indexer: leaveRequestCrudIndexer,\n })\n },\n}\n\nregisterCommand(createLeaveRequestCommand)\nregisterCommand(updateLeaveRequestCommand)\nregisterCommand(deleteLeaveRequestCommand)\nregisterCommand(acceptLeaveRequestCommand)\nregisterCommand(rejectLeaveRequestCommand)\n"],
|
|
5
|
-
"mappings": "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",
|
|
4
|
+
"sourcesContent": ["import { randomUUID } from 'crypto'\nimport type { CommandHandler, CommandRuntimeContext } from '@open-mercato/shared/lib/commands'\nimport { registerCommand } from '@open-mercato/shared/lib/commands'\nimport type { EntityManager } from '@mikro-orm/postgresql'\nimport { CrudHttpError } from '@open-mercato/shared/lib/crud/errors'\nimport { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\nimport { emitCrudSideEffects, emitCrudUndoSideEffects, buildChanges } from '@open-mercato/shared/lib/commands/helpers'\nimport type { CrudIndexerConfig } from '@open-mercato/shared/lib/crud/types'\nimport type { DataEngine } from '@open-mercato/shared/lib/data/engine'\nimport { invalidateCrudCache } from '@open-mercato/shared/lib/crud/cache'\nimport { findOneWithDecryption } from '@open-mercato/shared/lib/encryption/find'\nimport { PlannerAvailabilityRule } from '@open-mercato/core/modules/planner/data/entities'\nimport { StaffLeaveRequest, type StaffLeaveRequestStatus } from '../data/entities'\nimport {\n staffLeaveRequestCreateSchema,\n staffLeaveRequestDecisionSchema,\n staffLeaveRequestUpdateSchema,\n type StaffLeaveRequestCreateInput,\n type StaffLeaveRequestDecisionInput,\n type StaffLeaveRequestUpdateInput,\n} from '../data/validators'\nimport { ensureOrganizationScope, ensureTenantScope, extractUndoPayload, requireTeamMember } from './shared'\nimport { E } from '#generated/entities.ids.generated'\n\nconst leaveRequestCrudIndexer: CrudIndexerConfig<StaffLeaveRequest> = {\n entityType: E.staff.staff_leave_request,\n}\n\nconst availabilityRuleCrudIndexer: CrudIndexerConfig<PlannerAvailabilityRule> = {\n entityType: E.planner.planner_availability_rule,\n cacheAliases: ['planner.availability'],\n}\n\ntype LeaveRequestSnapshot = {\n id: string\n tenantId: string\n organizationId: string\n memberId: string\n startDate: string\n endDate: string\n timezone: string\n status: StaffLeaveRequestStatus\n unavailabilityReasonEntryId: string | null\n unavailabilityReasonValue: string | null\n note: string | null\n decisionComment: string | null\n submittedByUserId: string | null\n decidedByUserId: string | null\n decidedAt: string | null\n deletedAt: string | null\n createdAt: string | null\n updatedAt: string | null\n}\n\ntype LeaveRequestUndoPayload = {\n before?: LeaveRequestSnapshot | null\n after?: LeaveRequestSnapshot | null\n availabilityRuleIds?: string[]\n}\n\nfunction parseUuidCandidate(value: string | null | undefined): string | null {\n if (!value) return null\n const uuidRegex = /^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-5][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}$/\n return uuidRegex.test(value) ? value : null\n}\n\nfunction resolveAuthUserId(ctx: { auth?: { sub?: string | null; isApiKey?: boolean } | null }): string | null {\n if (!ctx.auth || ctx.auth.isApiKey) return null\n return parseUuidCandidate(ctx.auth.sub ?? null)\n}\n\nfunction formatDateKey(value: Date): string {\n const year = value.getUTCFullYear()\n const month = String(value.getUTCMonth() + 1).padStart(2, '0')\n const day = String(value.getUTCDate()).padStart(2, '0')\n return `${year}-${month}-${day}`\n}\n\nfunction listDateKeysInRange(start: Date, end: Date): string[] {\n const dates: string[] = []\n const current = new Date(Date.UTC(start.getUTCFullYear(), start.getUTCMonth(), start.getUTCDate()))\n const last = new Date(Date.UTC(end.getUTCFullYear(), end.getUTCMonth(), end.getUTCDate()))\n while (current <= last) {\n dates.push(formatDateKey(current))\n current.setUTCDate(current.getUTCDate() + 1)\n }\n return dates\n}\n\nfunction formatDuration(minutes: number): string {\n const clamped = Math.max(1, minutes)\n const hours = Math.floor(clamped / 60)\n const mins = clamped % 60\n if (hours > 0 && mins > 0) return `PT${hours}H${mins}M`\n if (hours > 0) return `PT${hours}H`\n return `PT${mins}M`\n}\n\nfunction buildAvailabilityRrule(start: Date, end: Date): string {\n const dtStart = start.toISOString().replace(/[-:]/g, '').split('.')[0] + 'Z'\n const durationMinutes = Math.max(1, Math.round((end.getTime() - start.getTime()) / 60000))\n const duration = formatDuration(durationMinutes)\n return `DTSTART:${dtStart}\\nDURATION:${duration}\\nRRULE:FREQ=DAILY;COUNT=1`\n}\n\nfunction buildFullDayRrule(date: string): string | null {\n const [year, month, day] = date.split('-').map((part) => Number(part))\n if (!Number.isFinite(year) || !Number.isFinite(month) || !Number.isFinite(day)) return null\n const start = new Date(Date.UTC(year, month - 1, day, 0, 0, 0))\n const end = new Date(start.getTime() + 24 * 60 * 60 * 1000)\n return buildAvailabilityRrule(start, end)\n}\n\nasync function loadLeaveRequestSnapshot(em: EntityManager, id: string): Promise<LeaveRequestSnapshot | null> {\n const request = await findOneWithDecryption(em, StaffLeaveRequest, { id }, undefined, { tenantId: null, organizationId: null })\n if (!request) return null\n const memberId = typeof request.member === 'string' ? request.member : request.member.id\n return {\n id: request.id,\n tenantId: request.tenantId,\n organizationId: request.organizationId,\n memberId,\n startDate: request.startDate.toISOString(),\n endDate: request.endDate.toISOString(),\n timezone: request.timezone,\n status: request.status,\n unavailabilityReasonEntryId: request.unavailabilityReasonEntryId ?? null,\n unavailabilityReasonValue: request.unavailabilityReasonValue ?? null,\n note: request.note ?? null,\n decisionComment: request.decisionComment ?? null,\n submittedByUserId: request.submittedByUserId ?? null,\n decidedByUserId: request.decidedByUserId ?? null,\n decidedAt: request.decidedAt ? request.decidedAt.toISOString() : null,\n deletedAt: request.deletedAt ? request.deletedAt.toISOString() : null,\n createdAt: request.createdAt ? request.createdAt.toISOString() : null,\n updatedAt: request.updatedAt ? request.updatedAt.toISOString() : null,\n }\n}\n\nasync function requireLeaveRequest(em: EntityManager, id: string): Promise<StaffLeaveRequest> {\n const request = await findOneWithDecryption(em, StaffLeaveRequest, { id, deletedAt: null }, undefined, { tenantId: null, organizationId: null })\n if (!request) throw new CrudHttpError(404, { error: 'Leave request not found.' })\n return request\n}\n\nfunction ensurePendingStatus(request: StaffLeaveRequest): void {\n if (request.status !== 'pending') {\n throw new CrudHttpError(400, { error: 'Leave request is already finalized.' })\n }\n}\n\nasync function createUnavailabilityRules(params: {\n em: EntityManager\n tenantId: string\n organizationId: string\n memberId: string\n timezone: string\n dates: string[]\n note: string | null\n reasonEntryId: string | null\n reasonValue: string | null\n}): Promise<string[]> {\n const now = new Date()\n const createdIds: string[] = []\n params.dates.forEach((date) => {\n const rrule = buildFullDayRrule(date)\n if (!rrule) return\n const ruleId = randomUUID()\n const rule = params.em.create(PlannerAvailabilityRule, {\n id: ruleId,\n tenantId: params.tenantId,\n organizationId: params.organizationId,\n subjectType: 'member',\n subjectId: params.memberId,\n timezone: params.timezone,\n rrule,\n exdates: [],\n kind: 'unavailability',\n note: params.note,\n unavailabilityReasonEntryId: params.reasonEntryId,\n unavailabilityReasonValue: params.reasonValue,\n createdAt: now,\n updatedAt: now,\n deletedAt: null,\n })\n params.em.persist(rule)\n createdIds.push(ruleId)\n })\n return createdIds\n}\n\nasync function invalidateAvailabilityCache(params: {\n container: CommandRuntimeContext['container']\n tenantId: string | null\n organizationId: string | null\n ruleIds: string[]\n}) {\n if (!params.ruleIds.length) return\n const resource = 'planner.availability'\n const fallbackTenant = params.tenantId ?? null\n for (const ruleId of params.ruleIds) {\n await invalidateCrudCache(\n params.container,\n resource,\n { id: ruleId, organizationId: params.organizationId, tenantId: params.tenantId },\n fallbackTenant,\n 'updated',\n )\n }\n}\n\nconst createLeaveRequestCommand: CommandHandler<StaffLeaveRequestCreateInput, { requestId: string }> = {\n id: 'staff.leave-requests.create',\n async execute(rawInput, ctx) {\n const parsed = staffLeaveRequestCreateSchema.parse(rawInput)\n ensureTenantScope(ctx, parsed.tenantId)\n ensureOrganizationScope(ctx, parsed.organizationId)\n\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const member = await requireTeamMember(em, parsed.memberId, 'Team member not found')\n ensureTenantScope(ctx, member.tenantId)\n ensureOrganizationScope(ctx, member.organizationId)\n\n const submittedByUserId = parsed.submittedByUserId ?? resolveAuthUserId(ctx)\n const now = new Date()\n const request = em.create(StaffLeaveRequest, {\n tenantId: parsed.tenantId,\n organizationId: parsed.organizationId,\n member,\n startDate: parsed.startDate,\n endDate: parsed.endDate,\n timezone: parsed.timezone,\n status: 'pending',\n unavailabilityReasonEntryId: parsed.unavailabilityReasonEntryId ?? null,\n unavailabilityReasonValue: parsed.unavailabilityReasonValue ?? null,\n note: parsed.note ?? null,\n decisionComment: null,\n submittedByUserId,\n decidedByUserId: null,\n decidedAt: null,\n createdAt: now,\n updatedAt: now,\n deletedAt: null,\n })\n em.persist(request)\n await em.flush()\n\n const de = (ctx.container.resolve('dataEngine') as DataEngine)\n await emitCrudSideEffects({\n dataEngine: de,\n action: 'created',\n entity: request,\n identifiers: {\n id: request.id,\n organizationId: request.organizationId,\n tenantId: request.tenantId,\n },\n indexer: leaveRequestCrudIndexer,\n })\n\n return { requestId: request.id }\n },\n captureAfter: async (_input, result, ctx) => {\n const em = (ctx.container.resolve('em') as EntityManager)\n return await loadLeaveRequestSnapshot(em, result.requestId)\n },\n buildLog: async ({ result, ctx }) => {\n const { translate } = await resolveTranslations()\n const em = (ctx.container.resolve('em') as EntityManager)\n const snapshot = await loadLeaveRequestSnapshot(em, result.requestId)\n return {\n actionLabel: translate('staff.audit.leaveRequests.create', 'Create leave request'),\n resourceKind: 'staff.leave_request',\n resourceId: result.requestId,\n tenantId: snapshot?.tenantId ?? null,\n organizationId: snapshot?.organizationId ?? null,\n snapshotAfter: snapshot ?? null,\n payload: {\n undo: {\n after: snapshot ?? null,\n } satisfies LeaveRequestUndoPayload,\n },\n }\n },\n undo: async ({ logEntry, ctx }) => {\n const payload = extractUndoPayload<LeaveRequestUndoPayload>(logEntry)\n const after = payload?.after\n if (!after) return\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const request = await em.findOne(StaffLeaveRequest, { id: after.id })\n if (request) {\n request.deletedAt = new Date()\n request.updatedAt = new Date()\n await em.flush()\n\n const de = (ctx.container.resolve('dataEngine') as DataEngine)\n await emitCrudUndoSideEffects({\n dataEngine: de,\n action: 'deleted',\n entity: request,\n identifiers: {\n id: request.id,\n organizationId: request.organizationId,\n tenantId: request.tenantId,\n },\n indexer: leaveRequestCrudIndexer,\n })\n }\n },\n}\n\nconst updateLeaveRequestCommand: CommandHandler<StaffLeaveRequestUpdateInput, { requestId: string }> = {\n id: 'staff.leave-requests.update',\n async prepare(rawInput, ctx) {\n const parsed = staffLeaveRequestUpdateSchema.parse(rawInput)\n const em = (ctx.container.resolve('em') as EntityManager)\n const snapshot = await loadLeaveRequestSnapshot(em, parsed.id)\n return snapshot ? { before: snapshot } : {}\n },\n async execute(rawInput, ctx) {\n const parsed = staffLeaveRequestUpdateSchema.parse(rawInput)\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const request = await requireLeaveRequest(em, parsed.id)\n ensureTenantScope(ctx, request.tenantId)\n ensureOrganizationScope(ctx, request.organizationId)\n ensurePendingStatus(request)\n\n if (parsed.memberId !== undefined) {\n const member = await requireTeamMember(em, parsed.memberId, 'Team member not found')\n ensureTenantScope(ctx, member.tenantId)\n ensureOrganizationScope(ctx, member.organizationId)\n request.member = member\n }\n if (parsed.startDate !== undefined) request.startDate = parsed.startDate\n if (parsed.endDate !== undefined) request.endDate = parsed.endDate\n if (parsed.timezone !== undefined) request.timezone = parsed.timezone\n if (parsed.unavailabilityReasonEntryId !== undefined) request.unavailabilityReasonEntryId = parsed.unavailabilityReasonEntryId ?? null\n if (parsed.unavailabilityReasonValue !== undefined) request.unavailabilityReasonValue = parsed.unavailabilityReasonValue ?? null\n if (parsed.note !== undefined) request.note = parsed.note ?? null\n request.updatedAt = new Date()\n await em.flush()\n\n const de = (ctx.container.resolve('dataEngine') as DataEngine)\n await emitCrudSideEffects({\n dataEngine: de,\n action: 'updated',\n entity: request,\n identifiers: {\n id: request.id,\n organizationId: request.organizationId,\n tenantId: request.tenantId,\n },\n indexer: leaveRequestCrudIndexer,\n })\n\n return { requestId: request.id }\n },\n buildLog: async ({ snapshots, ctx }) => {\n const { translate } = await resolveTranslations()\n const before = snapshots.before as LeaveRequestSnapshot | undefined\n if (!before) return null\n const em = (ctx.container.resolve('em') as EntityManager)\n const after = await loadLeaveRequestSnapshot(em, before.id)\n const changes = after\n ? buildChanges(before as unknown as Record<string, unknown>, after as unknown as Record<string, unknown>, [\n 'memberId',\n 'startDate',\n 'endDate',\n 'timezone',\n 'unavailabilityReasonEntryId',\n 'unavailabilityReasonValue',\n 'note',\n ])\n : {}\n return {\n actionLabel: translate('staff.audit.leaveRequests.update', 'Update leave request'),\n resourceKind: 'staff.leave_request',\n resourceId: before.id,\n tenantId: before.tenantId,\n organizationId: before.organizationId,\n snapshotBefore: before,\n snapshotAfter: after ?? null,\n changes,\n payload: {\n undo: {\n before,\n after: after ?? null,\n } satisfies LeaveRequestUndoPayload,\n },\n }\n },\n undo: async ({ logEntry, ctx }) => {\n const payload = extractUndoPayload<LeaveRequestUndoPayload>(logEntry)\n const before = payload?.before\n const after = payload?.after\n if (!before || !after) return\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const request = await em.findOne(StaffLeaveRequest, { id: after.id })\n if (!request) return\n request.startDate = new Date(before.startDate)\n request.endDate = new Date(before.endDate)\n request.timezone = before.timezone\n request.status = before.status\n request.unavailabilityReasonEntryId = before.unavailabilityReasonEntryId\n request.unavailabilityReasonValue = before.unavailabilityReasonValue\n request.note = before.note\n request.decisionComment = before.decisionComment\n request.decidedByUserId = before.decidedByUserId\n request.decidedAt = before.decidedAt ? new Date(before.decidedAt) : null\n request.updatedAt = new Date()\n await em.flush()\n\n const de = (ctx.container.resolve('dataEngine') as DataEngine)\n await emitCrudUndoSideEffects({\n dataEngine: de,\n action: 'updated',\n entity: request,\n identifiers: {\n id: request.id,\n organizationId: request.organizationId,\n tenantId: request.tenantId,\n },\n indexer: leaveRequestCrudIndexer,\n })\n },\n}\n\nconst deleteLeaveRequestCommand: CommandHandler<{ id: string }, { requestId: string }> = {\n id: 'staff.leave-requests.delete',\n async execute(rawInput, ctx) {\n const parsed = staffLeaveRequestDecisionSchema.pick({ id: true }).parse(rawInput)\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const request = await requireLeaveRequest(em, parsed.id)\n ensureTenantScope(ctx, request.tenantId)\n ensureOrganizationScope(ctx, request.organizationId)\n ensurePendingStatus(request)\n\n request.deletedAt = new Date()\n request.updatedAt = new Date()\n await em.flush()\n\n const de = (ctx.container.resolve('dataEngine') as DataEngine)\n await emitCrudSideEffects({\n dataEngine: de,\n action: 'deleted',\n entity: request,\n identifiers: {\n id: request.id,\n organizationId: request.organizationId,\n tenantId: request.tenantId,\n },\n indexer: leaveRequestCrudIndexer,\n })\n\n return { requestId: request.id }\n },\n captureAfter: async (_input, result, ctx) => {\n const em = (ctx.container.resolve('em') as EntityManager)\n return await loadLeaveRequestSnapshot(em, result.requestId)\n },\n buildLog: async ({ result, ctx }) => {\n const { translate } = await resolveTranslations()\n const em = (ctx.container.resolve('em') as EntityManager)\n const snapshot = await loadLeaveRequestSnapshot(em, result.requestId)\n return {\n actionLabel: translate('staff.audit.leaveRequests.delete', 'Delete leave request'),\n resourceKind: 'staff.leave_request',\n resourceId: result.requestId,\n tenantId: snapshot?.tenantId ?? null,\n organizationId: snapshot?.organizationId ?? null,\n snapshotAfter: snapshot ?? null,\n payload: {\n undo: {\n after: snapshot ?? null,\n } satisfies LeaveRequestUndoPayload,\n },\n }\n },\n undo: async ({ logEntry, ctx }) => {\n const payload = extractUndoPayload<LeaveRequestUndoPayload>(logEntry)\n const after = payload?.after\n if (!after) return\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const request = await em.findOne(StaffLeaveRequest, { id: after.id })\n if (!request) return\n request.deletedAt = null\n request.updatedAt = new Date()\n await em.flush()\n\n const de = (ctx.container.resolve('dataEngine') as DataEngine)\n await emitCrudUndoSideEffects({\n dataEngine: de,\n action: 'created',\n entity: request,\n identifiers: {\n id: request.id,\n organizationId: request.organizationId,\n tenantId: request.tenantId,\n },\n indexer: leaveRequestCrudIndexer,\n })\n },\n}\n\nconst acceptLeaveRequestCommand: CommandHandler<StaffLeaveRequestDecisionInput, { requestId: string; ruleIds: string[] }> = {\n id: 'staff.leave-requests.accept',\n async execute(rawInput, ctx) {\n const parsed = staffLeaveRequestDecisionSchema.parse(rawInput)\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const request = await requireLeaveRequest(em, parsed.id)\n ensureTenantScope(ctx, request.tenantId)\n ensureOrganizationScope(ctx, request.organizationId)\n ensurePendingStatus(request)\n\n const memberId = typeof request.member === 'string' ? request.member : request.member.id\n const decidedByUserId = parsed.decidedByUserId ?? resolveAuthUserId(ctx)\n const now = new Date()\n const dates = listDateKeysInRange(request.startDate, request.endDate)\n let createdRuleIds: string[] = []\n\n await em.transactional(async (trx) => {\n request.status = 'approved'\n request.decisionComment = parsed.decisionComment ?? null\n request.decidedByUserId = decidedByUserId\n request.decidedAt = now\n request.updatedAt = now\n trx.persist(request)\n\n createdRuleIds = await createUnavailabilityRules({\n em: trx,\n tenantId: request.tenantId,\n organizationId: request.organizationId,\n memberId,\n timezone: request.timezone,\n dates,\n note: request.note ?? null,\n reasonEntryId: request.unavailabilityReasonEntryId ?? null,\n reasonValue: request.unavailabilityReasonValue ?? null,\n })\n await trx.flush()\n })\n\n const de = (ctx.container.resolve('dataEngine') as DataEngine)\n await emitCrudSideEffects({\n dataEngine: de,\n action: 'updated',\n entity: request,\n identifiers: {\n id: request.id,\n organizationId: request.organizationId,\n tenantId: request.tenantId,\n },\n indexer: leaveRequestCrudIndexer,\n })\n if (createdRuleIds.length) {\n const rules = await em.find(PlannerAvailabilityRule, { id: { $in: createdRuleIds } })\n for (const rule of rules) {\n await emitCrudSideEffects({\n dataEngine: de,\n action: 'created',\n entity: rule,\n identifiers: {\n id: rule.id,\n organizationId: rule.organizationId,\n tenantId: rule.tenantId,\n },\n indexer: availabilityRuleCrudIndexer,\n })\n }\n }\n await invalidateAvailabilityCache({\n container: ctx.container,\n tenantId: request.tenantId,\n organizationId: request.organizationId,\n ruleIds: createdRuleIds,\n })\n\n return { requestId: request.id, ruleIds: createdRuleIds }\n },\n buildLog: async ({ result, ctx, snapshots }) => {\n const { translate } = await resolveTranslations()\n const before = snapshots.before as LeaveRequestSnapshot | undefined\n const em = (ctx.container.resolve('em') as EntityManager)\n const after = await loadLeaveRequestSnapshot(em, result.requestId)\n return {\n actionLabel: translate('staff.audit.leaveRequests.accept', 'Approve leave request'),\n resourceKind: 'staff.leave_request',\n resourceId: result.requestId,\n tenantId: after?.tenantId ?? before?.tenantId ?? null,\n organizationId: after?.organizationId ?? before?.organizationId ?? null,\n snapshotBefore: before ?? null,\n snapshotAfter: after ?? null,\n payload: {\n undo: {\n before: before ?? null,\n after: after ?? null,\n availabilityRuleIds: result.ruleIds,\n } satisfies LeaveRequestUndoPayload,\n },\n }\n },\n async prepare(rawInput, ctx) {\n const parsed = staffLeaveRequestDecisionSchema.parse(rawInput)\n const em = (ctx.container.resolve('em') as EntityManager)\n const snapshot = await loadLeaveRequestSnapshot(em, parsed.id)\n return snapshot ? { before: snapshot } : {}\n },\n undo: async ({ logEntry, ctx }) => {\n const payload = extractUndoPayload<LeaveRequestUndoPayload>(logEntry)\n const before = payload?.before\n const availabilityRuleIds = payload?.availabilityRuleIds ?? []\n if (!before) return\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const request = await em.findOne(StaffLeaveRequest, { id: before.id })\n if (!request) return\n request.status = before.status\n request.decisionComment = before.decisionComment\n request.decidedByUserId = before.decidedByUserId\n request.decidedAt = before.decidedAt ? new Date(before.decidedAt) : null\n request.updatedAt = new Date()\n await em.flush()\n\n const de = (ctx.container.resolve('dataEngine') as DataEngine)\n await emitCrudUndoSideEffects({\n dataEngine: de,\n action: 'updated',\n entity: request,\n identifiers: {\n id: request.id,\n organizationId: request.organizationId,\n tenantId: request.tenantId,\n },\n indexer: leaveRequestCrudIndexer,\n })\n\n if (availabilityRuleIds.length) {\n const rules = await em.find(PlannerAvailabilityRule, { id: { $in: availabilityRuleIds } })\n const now = new Date()\n rules.forEach((rule) => {\n rule.deletedAt = now\n rule.updatedAt = now\n })\n await em.flush()\n\n const de = (ctx.container.resolve('dataEngine') as DataEngine)\n for (const rule of rules) {\n await emitCrudUndoSideEffects({\n dataEngine: de,\n action: 'deleted',\n entity: rule,\n identifiers: {\n id: rule.id,\n organizationId: rule.organizationId,\n tenantId: rule.tenantId,\n },\n indexer: availabilityRuleCrudIndexer,\n })\n }\n }\n await invalidateAvailabilityCache({\n container: ctx.container,\n tenantId: before.tenantId,\n organizationId: before.organizationId,\n ruleIds: availabilityRuleIds,\n })\n },\n}\n\nconst rejectLeaveRequestCommand: CommandHandler<StaffLeaveRequestDecisionInput, { requestId: string }> = {\n id: 'staff.leave-requests.reject',\n async execute(rawInput, ctx) {\n const parsed = staffLeaveRequestDecisionSchema.parse(rawInput)\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const request = await requireLeaveRequest(em, parsed.id)\n ensureTenantScope(ctx, request.tenantId)\n ensureOrganizationScope(ctx, request.organizationId)\n ensurePendingStatus(request)\n\n request.status = 'rejected'\n request.decisionComment = parsed.decisionComment ?? null\n request.decidedByUserId = parsed.decidedByUserId ?? resolveAuthUserId(ctx)\n request.decidedAt = new Date()\n request.updatedAt = new Date()\n await em.flush()\n\n const de = (ctx.container.resolve('dataEngine') as DataEngine)\n await emitCrudSideEffects({\n dataEngine: de,\n action: 'updated',\n entity: request,\n identifiers: {\n id: request.id,\n organizationId: request.organizationId,\n tenantId: request.tenantId,\n },\n indexer: leaveRequestCrudIndexer,\n })\n\n return { requestId: request.id }\n },\n async prepare(rawInput, ctx) {\n const parsed = staffLeaveRequestDecisionSchema.parse(rawInput)\n const em = (ctx.container.resolve('em') as EntityManager)\n const snapshot = await loadLeaveRequestSnapshot(em, parsed.id)\n return snapshot ? { before: snapshot } : {}\n },\n buildLog: async ({ result, ctx, snapshots }) => {\n const { translate } = await resolveTranslations()\n const before = snapshots.before as LeaveRequestSnapshot | undefined\n const em = (ctx.container.resolve('em') as EntityManager)\n const after = await loadLeaveRequestSnapshot(em, result.requestId)\n return {\n actionLabel: translate('staff.audit.leaveRequests.reject', 'Reject leave request'),\n resourceKind: 'staff.leave_request',\n resourceId: result.requestId,\n tenantId: after?.tenantId ?? before?.tenantId ?? null,\n organizationId: after?.organizationId ?? before?.organizationId ?? null,\n snapshotBefore: before ?? null,\n snapshotAfter: after ?? null,\n payload: {\n undo: {\n before: before ?? null,\n after: after ?? null,\n } satisfies LeaveRequestUndoPayload,\n },\n }\n },\n undo: async ({ logEntry, ctx }) => {\n const payload = extractUndoPayload<LeaveRequestUndoPayload>(logEntry)\n const before = payload?.before\n if (!before) return\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const request = await em.findOne(StaffLeaveRequest, { id: before.id })\n if (!request) return\n request.status = before.status\n request.decisionComment = before.decisionComment\n request.decidedByUserId = before.decidedByUserId\n request.decidedAt = before.decidedAt ? new Date(before.decidedAt) : null\n request.updatedAt = new Date()\n await em.flush()\n\n const de = (ctx.container.resolve('dataEngine') as DataEngine)\n await emitCrudUndoSideEffects({\n dataEngine: de,\n action: 'updated',\n entity: request,\n identifiers: {\n id: request.id,\n organizationId: request.organizationId,\n tenantId: request.tenantId,\n },\n indexer: leaveRequestCrudIndexer,\n })\n },\n}\n\nregisterCommand(createLeaveRequestCommand)\nregisterCommand(updateLeaveRequestCommand)\nregisterCommand(deleteLeaveRequestCommand)\nregisterCommand(acceptLeaveRequestCommand)\nregisterCommand(rejectLeaveRequestCommand)\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["de"]
|
|
7
7
|
}
|
|
@@ -18,6 +18,8 @@ const features = [
|
|
|
18
18
|
{ id: "workflows.tasks.complete", title: "Complete workflow tasks", module: moduleId },
|
|
19
19
|
{ id: "workflows.signals.send", title: "Send workflow signals", module: moduleId },
|
|
20
20
|
{ id: "workflows.events.view", title: "View workflow events", module: moduleId }
|
|
21
|
+
// Note: Event triggers are now embedded in workflow definitions.
|
|
22
|
+
// Trigger management permissions are covered by workflows.definitions.edit
|
|
21
23
|
];
|
|
22
24
|
var acl_default = features;
|
|
23
25
|
export {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/modules/workflows/acl.ts"],
|
|
4
|
-
"sourcesContent": ["const moduleId = 'workflows'\n\nexport const features = [\n { id: 'workflows.view', title: 'View workflows', module: moduleId },\n { id: 'workflows.manage', title: 'Manage workflows', module: moduleId },\n { id: 'workflows.view_logs', title: 'View workflow logs', module: moduleId },\n { id: 'workflows.view_tasks', title: 'View workflow tasks', module: moduleId },\n { id: 'workflows.definitions.view', title: 'View workflow definitions', module: moduleId },\n { id: 'workflows.definitions.create', title: 'Create workflow definitions', module: moduleId },\n { id: 'workflows.definitions.edit', title: 'Edit workflow definitions', module: moduleId },\n { id: 'workflows.definitions.delete', title: 'Delete workflow definitions', module: moduleId },\n { id: 'workflows.instances.view', title: 'View workflow instances', module: moduleId },\n { id: 'workflows.instances.create', title: 'Start workflow instances', module: moduleId },\n { id: 'workflows.instances.cancel', title: 'Cancel workflow instances', module: moduleId },\n { id: 'workflows.instances.retry', title: 'Retry workflow instances', module: moduleId },\n { id: 'workflows.instances.signal', title: 'Signal workflow instances', module: moduleId },\n { id: 'workflows.tasks.view', title: 'View user tasks', module: moduleId },\n { id: 'workflows.tasks.claim', title: 'Claim workflow tasks', module: moduleId },\n { id: 'workflows.tasks.complete', title: 'Complete workflow tasks', module: moduleId },\n { id: 'workflows.signals.send', title: 'Send workflow signals', module: moduleId },\n { id: 'workflows.events.view', title: 'View workflow events', module: moduleId },\n]\n\nexport default features\n"],
|
|
5
|
-
"mappings": "AAAA,MAAM,WAAW;AAEV,MAAM,WAAW;AAAA,EACtB,EAAE,IAAI,kBAAkB,OAAO,kBAAkB,QAAQ,SAAS;AAAA,EAClE,EAAE,IAAI,oBAAoB,OAAO,oBAAoB,QAAQ,SAAS;AAAA,EACtE,EAAE,IAAI,uBAAuB,OAAO,sBAAsB,QAAQ,SAAS;AAAA,EAC3E,EAAE,IAAI,wBAAwB,OAAO,uBAAuB,QAAQ,SAAS;AAAA,EAC7E,EAAE,IAAI,8BAA8B,OAAO,6BAA6B,QAAQ,SAAS;AAAA,EACzF,EAAE,IAAI,gCAAgC,OAAO,+BAA+B,QAAQ,SAAS;AAAA,EAC7F,EAAE,IAAI,8BAA8B,OAAO,6BAA6B,QAAQ,SAAS;AAAA,EACzF,EAAE,IAAI,gCAAgC,OAAO,+BAA+B,QAAQ,SAAS;AAAA,EAC7F,EAAE,IAAI,4BAA4B,OAAO,2BAA2B,QAAQ,SAAS;AAAA,EACrF,EAAE,IAAI,8BAA8B,OAAO,4BAA4B,QAAQ,SAAS;AAAA,EACxF,EAAE,IAAI,8BAA8B,OAAO,6BAA6B,QAAQ,SAAS;AAAA,EACzF,EAAE,IAAI,6BAA6B,OAAO,4BAA4B,QAAQ,SAAS;AAAA,EACvF,EAAE,IAAI,8BAA8B,OAAO,6BAA6B,QAAQ,SAAS;AAAA,EACzF,EAAE,IAAI,wBAAwB,OAAO,mBAAmB,QAAQ,SAAS;AAAA,EACzE,EAAE,IAAI,yBAAyB,OAAO,wBAAwB,QAAQ,SAAS;AAAA,EAC/E,EAAE,IAAI,4BAA4B,OAAO,2BAA2B,QAAQ,SAAS;AAAA,EACrF,EAAE,IAAI,0BAA0B,OAAO,yBAAyB,QAAQ,SAAS;AAAA,EACjF,EAAE,IAAI,yBAAyB,OAAO,wBAAwB,QAAQ,SAAS;
|
|
4
|
+
"sourcesContent": ["const moduleId = 'workflows'\n\nexport const features = [\n { id: 'workflows.view', title: 'View workflows', module: moduleId },\n { id: 'workflows.manage', title: 'Manage workflows', module: moduleId },\n { id: 'workflows.view_logs', title: 'View workflow logs', module: moduleId },\n { id: 'workflows.view_tasks', title: 'View workflow tasks', module: moduleId },\n { id: 'workflows.definitions.view', title: 'View workflow definitions', module: moduleId },\n { id: 'workflows.definitions.create', title: 'Create workflow definitions', module: moduleId },\n { id: 'workflows.definitions.edit', title: 'Edit workflow definitions', module: moduleId },\n { id: 'workflows.definitions.delete', title: 'Delete workflow definitions', module: moduleId },\n { id: 'workflows.instances.view', title: 'View workflow instances', module: moduleId },\n { id: 'workflows.instances.create', title: 'Start workflow instances', module: moduleId },\n { id: 'workflows.instances.cancel', title: 'Cancel workflow instances', module: moduleId },\n { id: 'workflows.instances.retry', title: 'Retry workflow instances', module: moduleId },\n { id: 'workflows.instances.signal', title: 'Signal workflow instances', module: moduleId },\n { id: 'workflows.tasks.view', title: 'View user tasks', module: moduleId },\n { id: 'workflows.tasks.claim', title: 'Claim workflow tasks', module: moduleId },\n { id: 'workflows.tasks.complete', title: 'Complete workflow tasks', module: moduleId },\n { id: 'workflows.signals.send', title: 'Send workflow signals', module: moduleId },\n { id: 'workflows.events.view', title: 'View workflow events', module: moduleId },\n // Note: Event triggers are now embedded in workflow definitions.\n // Trigger management permissions are covered by workflows.definitions.edit\n]\n\nexport default features\n"],
|
|
5
|
+
"mappings": "AAAA,MAAM,WAAW;AAEV,MAAM,WAAW;AAAA,EACtB,EAAE,IAAI,kBAAkB,OAAO,kBAAkB,QAAQ,SAAS;AAAA,EAClE,EAAE,IAAI,oBAAoB,OAAO,oBAAoB,QAAQ,SAAS;AAAA,EACtE,EAAE,IAAI,uBAAuB,OAAO,sBAAsB,QAAQ,SAAS;AAAA,EAC3E,EAAE,IAAI,wBAAwB,OAAO,uBAAuB,QAAQ,SAAS;AAAA,EAC7E,EAAE,IAAI,8BAA8B,OAAO,6BAA6B,QAAQ,SAAS;AAAA,EACzF,EAAE,IAAI,gCAAgC,OAAO,+BAA+B,QAAQ,SAAS;AAAA,EAC7F,EAAE,IAAI,8BAA8B,OAAO,6BAA6B,QAAQ,SAAS;AAAA,EACzF,EAAE,IAAI,gCAAgC,OAAO,+BAA+B,QAAQ,SAAS;AAAA,EAC7F,EAAE,IAAI,4BAA4B,OAAO,2BAA2B,QAAQ,SAAS;AAAA,EACrF,EAAE,IAAI,8BAA8B,OAAO,4BAA4B,QAAQ,SAAS;AAAA,EACxF,EAAE,IAAI,8BAA8B,OAAO,6BAA6B,QAAQ,SAAS;AAAA,EACzF,EAAE,IAAI,6BAA6B,OAAO,4BAA4B,QAAQ,SAAS;AAAA,EACvF,EAAE,IAAI,8BAA8B,OAAO,6BAA6B,QAAQ,SAAS;AAAA,EACzF,EAAE,IAAI,wBAAwB,OAAO,mBAAmB,QAAQ,SAAS;AAAA,EACzE,EAAE,IAAI,yBAAyB,OAAO,wBAAwB,QAAQ,SAAS;AAAA,EAC/E,EAAE,IAAI,4BAA4B,OAAO,2BAA2B,QAAQ,SAAS;AAAA,EACrF,EAAE,IAAI,0BAA0B,OAAO,yBAAyB,QAAQ,SAAS;AAAA,EACjF,EAAE,IAAI,yBAAyB,OAAO,wBAAwB,QAAQ,SAAS;AAAA;AAAA;AAGjF;AAEA,IAAO,cAAQ;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -46,16 +46,28 @@ async function GET(request) {
|
|
|
46
46
|
where.workflowId = workflowId;
|
|
47
47
|
}
|
|
48
48
|
if (status) {
|
|
49
|
-
|
|
49
|
+
const statuses = status.split(",").map((s) => s.trim()).filter(Boolean);
|
|
50
|
+
if (statuses.length === 1) {
|
|
51
|
+
where.status = statuses[0];
|
|
52
|
+
} else if (statuses.length > 1) {
|
|
53
|
+
where.status = { $in: statuses };
|
|
54
|
+
}
|
|
50
55
|
}
|
|
51
56
|
if (correlationKey) {
|
|
52
57
|
where.correlationKey = correlationKey;
|
|
53
58
|
}
|
|
54
|
-
if (entityType) {
|
|
55
|
-
where
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
+
if (entityType || entityId) {
|
|
60
|
+
where.$and = where.$and || [];
|
|
61
|
+
if (entityType) {
|
|
62
|
+
where.$and.push({
|
|
63
|
+
metadata: { $contains: { entityType } }
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
if (entityId) {
|
|
67
|
+
where.$and.push({
|
|
68
|
+
metadata: { $contains: { entityId } }
|
|
69
|
+
});
|
|
70
|
+
}
|
|
59
71
|
}
|
|
60
72
|
const [instances, total] = await em.findAndCount(
|
|
61
73
|
WorkflowInstance,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../src/modules/workflows/api/instances/route.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n * Workflow Instances API\n *\n * Endpoints:\n * - GET /api/workflows/instances - List workflow instances\n * - POST /api/workflows/instances - Start a new workflow instance\n */\n\nimport { NextRequest, NextResponse } from 'next/server'\nimport { z } from 'zod'\nimport { createRequestContainer } from '@open-mercato/shared/lib/di/container'\nimport { getAuthFromRequest } from '@open-mercato/shared/lib/auth/server'\nimport { resolveOrganizationScopeForRequest } from '@open-mercato/core/modules/directory/utils/organizationScope'\nimport { WorkflowInstance } from '../../data/entities'\nimport {\n startWorkflowInputSchema,\n type StartWorkflowApiInput,\n workflowInstanceStatusSchema,\n} from '../../data/validators'\nimport * as workflowExecutor from '../../lib/workflow-executor'\n\nexport const metadata = {\n requireAuth: true,\n requireFeatures: ['workflows.instances.view'],\n}\n\n/**\n * GET /api/workflows/instances\n *\n * List workflow instances with optional filters\n */\nexport async function GET(request: NextRequest) {\n try {\n const container = await createRequestContainer()\n const em = container.resolve('em')\n const auth = await getAuthFromRequest(request)\n\n if (!auth) {\n return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })\n }\n\n const scope = await resolveOrganizationScopeForRequest({ container, auth, request })\n const tenantId = auth.tenantId\n const organizationId = scope?.selectedId ?? auth.orgId\n\n if (!tenantId || !organizationId) {\n return NextResponse.json(\n { error: 'Missing tenant or organization context' },\n { status: 400 }\n )\n }\n\n const { searchParams } = new URL(request.url)\n const workflowId = searchParams.get('workflowId')\n const status = searchParams.get('status')\n const correlationKey = searchParams.get('correlationKey')\n const entityType = searchParams.get('entityType')\n const entityId = searchParams.get('entityId')\n const limit = parseInt(searchParams.get('limit') || '50')\n const offset = parseInt(searchParams.get('offset') || '0')\n\n // Build where clause with tenant scoping\n const where: any = {\n tenantId,\n organizationId,\n }\n\n if (workflowId) {\n where.workflowId = workflowId\n }\n\n if (status) {\n where.status = status\n }\n\n if (correlationKey) {\n where.correlationKey = correlationKey\n }\n\n if (entityType) {\n where['metadata.entityType'] = entityType\n }\n\n if (entityId) {\n where['metadata.entityId'] = entityId\n }\n\n const [instances, total] = await em.findAndCount(\n WorkflowInstance,\n where,\n {\n orderBy: { createdAt: 'DESC' },\n limit,\n offset,\n }\n )\n\n return NextResponse.json({\n data: instances,\n pagination: {\n total,\n limit,\n offset,\n hasMore: offset + limit < total,\n },\n })\n } catch (error) {\n console.error('Error listing workflow instances:', error)\n return NextResponse.json(\n { error: 'Failed to list workflow instances' },\n { status: 500 }\n )\n }\n}\n\n/**\n * POST /api/workflows/instances\n *\n * Start a new workflow instance\n */\nexport async function POST(request: NextRequest) {\n try {\n const container = await createRequestContainer()\n const em = container.resolve('em')\n const auth = await getAuthFromRequest(request)\n\n if (!auth) {\n return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })\n }\n\n const scope = await resolveOrganizationScopeForRequest({ container, auth, request })\n const tenantId = auth.tenantId\n const organizationId = scope?.selectedId ?? auth.orgId\n\n if (!tenantId || !organizationId) {\n return NextResponse.json(\n { error: 'Missing tenant or organization context' },\n { status: 400 }\n )\n }\n\n // Check create permission\n const rbacService = container.resolve('rbacService')\n const hasPermission = await rbacService.userHasAllFeatures(\n auth.sub,\n ['workflows.instances.create'],\n {\n tenantId,\n organizationId,\n }\n )\n\n if (!hasPermission) {\n return NextResponse.json(\n { error: 'Insufficient permissions' },\n { status: 403 }\n )\n }\n\n const body = await request.json()\n\n // Validate input\n const validation = startWorkflowInputSchema.safeParse(body)\n if (!validation.success) {\n return NextResponse.json(\n {\n error: 'Validation failed',\n details: validation.error.issues,\n },\n { status: 400 }\n )\n }\n\n const input: StartWorkflowApiInput = validation.data\n\n // Inject metadata.initiatedBy if not provided\n const metadata = {\n ...input.metadata,\n initiatedBy: input.metadata?.initiatedBy || auth.sub,\n }\n\n // Start workflow\n const instance = await workflowExecutor.startWorkflow(em, {\n workflowId: input.workflowId,\n version: input.version,\n initialContext: input.initialContext || {},\n correlationKey: input.correlationKey,\n metadata,\n tenantId,\n organizationId,\n })\n\n // Execute workflow in background (non-blocking for demo visibility)\n // This allows the frontend to see step-by-step progress via polling\n setImmediate(async () => {\n try {\n // Create new container and EM for background execution\n const bgContainer = await createRequestContainer()\n const bgEm = bgContainer.resolve('em')\n await workflowExecutor.executeWorkflow(bgEm, bgContainer, instance.id)\n } catch (error) {\n console.error('Background workflow execution error:', error)\n }\n })\n\n return NextResponse.json(\n {\n data: {\n instance,\n execution: {\n status: instance.status,\n currentStep: instance.currentStepId,\n message: 'Workflow execution started in background',\n },\n },\n message: 'Workflow started successfully',\n },\n { status: 201 }\n )\n } catch (error) {\n console.error('Error starting workflow:', error)\n\n // Handle specific errors\n if (error instanceof workflowExecutor.WorkflowExecutionError) {\n if (error.code === 'DEFINITION_NOT_FOUND') {\n return NextResponse.json(\n { error: error.message },\n { status: 404 }\n )\n }\n if (error.code === 'DEFINITION_DISABLED') {\n return NextResponse.json(\n { error: error.message },\n { status: 400 }\n )\n }\n if (error.code === 'INVALID_DEFINITION') {\n return NextResponse.json(\n { error: error.message },\n { status: 400 }\n )\n }\n if (error.code === 'START_PRE_CONDITIONS_FAILED') {\n return NextResponse.json(\n {\n error: error.message,\n code: error.code,\n details: error.details,\n },\n { status: 422 }\n )\n }\n }\n\n return NextResponse.json(\n { error: 'Failed to start workflow' },\n { status: 500 }\n )\n }\n}\n\nexport const openApi = {\n methods: {\n GET: {\n summary: 'List workflow instances',\n description: 'Get a list of workflow instances with optional filters. Supports pagination and filtering by status, workflowId, correlationKey, etc.',\n tags: ['Workflows'],\n query: z.object({\n workflowId: z.string().optional(),\n status: workflowInstanceStatusSchema.optional(),\n correlationKey: z.string().optional(),\n entityType: z.string().optional(),\n entityId: z.string().optional(),\n limit: z.number().int().positive().default(50).optional(),\n offset: z.number().int().min(0).default(0).optional(),\n }),\n responses: [\n {\n status: 200,\n description: 'List of workflow instances',\n schema: z.object({\n data: z.array(z.any()),\n pagination: z.object({\n total: z.number(),\n limit: z.number(),\n offset: z.number(),\n hasMore: z.boolean(),\n }),\n }),\n },\n {\n status: 401,\n description: 'Unauthorized',\n schema: z.object({ error: z.string() }),\n },\n {\n status: 500,\n description: 'Internal server error',\n schema: z.object({ error: z.string() }),\n },\n ],\n },\n POST: {\n summary: 'Start workflow instance',\n description: 'Start a new workflow instance from a workflow definition. The workflow will execute immediately.',\n tags: ['Workflows'],\n requestBody: {\n contentType: 'application/json',\n schema: startWorkflowInputSchema,\n description: 'Workflow instance configuration including workflowId, initial context, and metadata.',\n },\n responses: [\n {\n status: 201,\n description: 'Workflow started successfully',\n schema: z.object({\n data: z.object({\n instance: z.any(),\n execution: z.any(),\n }),\n message: z.string(),\n }),\n },\n {\n status: 400,\n description: 'Bad request - Validation failed or definition disabled/invalid',\n schema: z.object({\n error: z.string(),\n details: z.any().optional(),\n }),\n },\n {\n status: 401,\n description: 'Unauthorized',\n schema: z.object({ error: z.string() }),\n },\n {\n status: 403,\n description: 'Forbidden - Insufficient permissions',\n schema: z.object({ error: z.string() }),\n },\n {\n status: 404,\n description: 'Workflow definition not found',\n schema: z.object({ error: z.string() }),\n },\n {\n status: 500,\n description: 'Internal server error',\n schema: z.object({ error: z.string() }),\n },\n ],\n },\n },\n}\n"],
|
|
5
|
-
"mappings": "AAQA,SAAsB,oBAAoB;AAC1C,SAAS,SAAS;AAClB,SAAS,8BAA8B;AACvC,SAAS,0BAA0B;AACnC,SAAS,0CAA0C;AACnD,SAAS,wBAAwB;AACjC;AAAA,EACE;AAAA,EAEA;AAAA,OACK;AACP,YAAY,sBAAsB;AAE3B,MAAM,WAAW;AAAA,EACtB,aAAa;AAAA,EACb,iBAAiB,CAAC,0BAA0B;AAC9C;AAOA,eAAsB,IAAI,SAAsB;AAC9C,MAAI;AACF,UAAM,YAAY,MAAM,uBAAuB;AAC/C,UAAM,KAAK,UAAU,QAAQ,IAAI;AACjC,UAAM,OAAO,MAAM,mBAAmB,OAAO;AAE7C,QAAI,CAAC,MAAM;AACT,aAAO,aAAa,KAAK,EAAE,OAAO,eAAe,GAAG,EAAE,QAAQ,IAAI,CAAC;AAAA,IACrE;AAEA,UAAM,QAAQ,MAAM,mCAAmC,EAAE,WAAW,MAAM,QAAQ,CAAC;AACnF,UAAM,WAAW,KAAK;AACtB,UAAM,iBAAiB,OAAO,cAAc,KAAK;AAEjD,QAAI,CAAC,YAAY,CAAC,gBAAgB;AAChC,aAAO,aAAa;AAAA,QAClB,EAAE,OAAO,yCAAyC;AAAA,QAClD,EAAE,QAAQ,IAAI;AAAA,MAChB;AAAA,IACF;AAEA,UAAM,EAAE,aAAa,IAAI,IAAI,IAAI,QAAQ,GAAG;AAC5C,UAAM,aAAa,aAAa,IAAI,YAAY;AAChD,UAAM,SAAS,aAAa,IAAI,QAAQ;AACxC,UAAM,iBAAiB,aAAa,IAAI,gBAAgB;AACxD,UAAM,aAAa,aAAa,IAAI,YAAY;AAChD,UAAM,WAAW,aAAa,IAAI,UAAU;AAC5C,UAAM,QAAQ,SAAS,aAAa,IAAI,OAAO,KAAK,IAAI;AACxD,UAAM,SAAS,SAAS,aAAa,IAAI,QAAQ,KAAK,GAAG;AAGzD,UAAM,QAAa;AAAA,MACjB;AAAA,MACA;AAAA,IACF;AAEA,QAAI,YAAY;AACd,YAAM,aAAa;AAAA,IACrB;AAEA,QAAI,QAAQ;
|
|
4
|
+
"sourcesContent": ["/**\n * Workflow Instances API\n *\n * Endpoints:\n * - GET /api/workflows/instances - List workflow instances\n * - POST /api/workflows/instances - Start a new workflow instance\n */\n\nimport { NextRequest, NextResponse } from 'next/server'\nimport { z } from 'zod'\nimport { createRequestContainer } from '@open-mercato/shared/lib/di/container'\nimport { getAuthFromRequest } from '@open-mercato/shared/lib/auth/server'\nimport { resolveOrganizationScopeForRequest } from '@open-mercato/core/modules/directory/utils/organizationScope'\nimport { WorkflowInstance } from '../../data/entities'\nimport {\n startWorkflowInputSchema,\n type StartWorkflowApiInput,\n workflowInstanceStatusSchema,\n} from '../../data/validators'\nimport * as workflowExecutor from '../../lib/workflow-executor'\n\nexport const metadata = {\n requireAuth: true,\n requireFeatures: ['workflows.instances.view'],\n}\n\n/**\n * GET /api/workflows/instances\n *\n * List workflow instances with optional filters\n */\nexport async function GET(request: NextRequest) {\n try {\n const container = await createRequestContainer()\n const em = container.resolve('em')\n const auth = await getAuthFromRequest(request)\n\n if (!auth) {\n return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })\n }\n\n const scope = await resolveOrganizationScopeForRequest({ container, auth, request })\n const tenantId = auth.tenantId\n const organizationId = scope?.selectedId ?? auth.orgId\n\n if (!tenantId || !organizationId) {\n return NextResponse.json(\n { error: 'Missing tenant or organization context' },\n { status: 400 }\n )\n }\n\n const { searchParams } = new URL(request.url)\n const workflowId = searchParams.get('workflowId')\n const status = searchParams.get('status')\n const correlationKey = searchParams.get('correlationKey')\n const entityType = searchParams.get('entityType')\n const entityId = searchParams.get('entityId')\n const limit = parseInt(searchParams.get('limit') || '50')\n const offset = parseInt(searchParams.get('offset') || '0')\n\n // Build where clause with tenant scoping\n const where: any = {\n tenantId,\n organizationId,\n }\n\n if (workflowId) {\n where.workflowId = workflowId\n }\n\n if (status) {\n // Support comma-separated status values (e.g., \"RUNNING,PAUSED,WAITING_FOR_ACTIVITIES\")\n const statuses = status.split(',').map(s => s.trim()).filter(Boolean)\n if (statuses.length === 1) {\n where.status = statuses[0]\n } else if (statuses.length > 1) {\n where.status = { $in: statuses }\n }\n }\n\n if (correlationKey) {\n where.correlationKey = correlationKey\n }\n\n // For JSONB metadata filtering, use $contains with explicit key-value pairs\n // MikroORM's dot notation creates table joins, not JSON access\n if (entityType || entityId) {\n where.$and = where.$and || []\n if (entityType) {\n where.$and.push({\n metadata: { $contains: { entityType: entityType } }\n })\n }\n if (entityId) {\n where.$and.push({\n metadata: { $contains: { entityId: entityId } }\n })\n }\n }\n\n const [instances, total] = await em.findAndCount(\n WorkflowInstance,\n where,\n {\n orderBy: { createdAt: 'DESC' },\n limit,\n offset,\n }\n )\n\n return NextResponse.json({\n data: instances,\n pagination: {\n total,\n limit,\n offset,\n hasMore: offset + limit < total,\n },\n })\n } catch (error) {\n console.error('Error listing workflow instances:', error)\n return NextResponse.json(\n { error: 'Failed to list workflow instances' },\n { status: 500 }\n )\n }\n}\n\n/**\n * POST /api/workflows/instances\n *\n * Start a new workflow instance\n */\nexport async function POST(request: NextRequest) {\n try {\n const container = await createRequestContainer()\n const em = container.resolve('em')\n const auth = await getAuthFromRequest(request)\n\n if (!auth) {\n return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })\n }\n\n const scope = await resolveOrganizationScopeForRequest({ container, auth, request })\n const tenantId = auth.tenantId\n const organizationId = scope?.selectedId ?? auth.orgId\n\n if (!tenantId || !organizationId) {\n return NextResponse.json(\n { error: 'Missing tenant or organization context' },\n { status: 400 }\n )\n }\n\n // Check create permission\n const rbacService = container.resolve('rbacService')\n const hasPermission = await rbacService.userHasAllFeatures(\n auth.sub,\n ['workflows.instances.create'],\n {\n tenantId,\n organizationId,\n }\n )\n\n if (!hasPermission) {\n return NextResponse.json(\n { error: 'Insufficient permissions' },\n { status: 403 }\n )\n }\n\n const body = await request.json()\n\n // Validate input\n const validation = startWorkflowInputSchema.safeParse(body)\n if (!validation.success) {\n return NextResponse.json(\n {\n error: 'Validation failed',\n details: validation.error.issues,\n },\n { status: 400 }\n )\n }\n\n const input: StartWorkflowApiInput = validation.data\n\n // Inject metadata.initiatedBy if not provided\n const metadata = {\n ...input.metadata,\n initiatedBy: input.metadata?.initiatedBy || auth.sub,\n }\n\n // Start workflow\n const instance = await workflowExecutor.startWorkflow(em, {\n workflowId: input.workflowId,\n version: input.version,\n initialContext: input.initialContext || {},\n correlationKey: input.correlationKey,\n metadata,\n tenantId,\n organizationId,\n })\n\n // Execute workflow in background (non-blocking for demo visibility)\n // This allows the frontend to see step-by-step progress via polling\n setImmediate(async () => {\n try {\n // Create new container and EM for background execution\n const bgContainer = await createRequestContainer()\n const bgEm = bgContainer.resolve('em')\n await workflowExecutor.executeWorkflow(bgEm, bgContainer, instance.id)\n } catch (error) {\n console.error('Background workflow execution error:', error)\n }\n })\n\n return NextResponse.json(\n {\n data: {\n instance,\n execution: {\n status: instance.status,\n currentStep: instance.currentStepId,\n message: 'Workflow execution started in background',\n },\n },\n message: 'Workflow started successfully',\n },\n { status: 201 }\n )\n } catch (error) {\n console.error('Error starting workflow:', error)\n\n // Handle specific errors\n if (error instanceof workflowExecutor.WorkflowExecutionError) {\n if (error.code === 'DEFINITION_NOT_FOUND') {\n return NextResponse.json(\n { error: error.message },\n { status: 404 }\n )\n }\n if (error.code === 'DEFINITION_DISABLED') {\n return NextResponse.json(\n { error: error.message },\n { status: 400 }\n )\n }\n if (error.code === 'INVALID_DEFINITION') {\n return NextResponse.json(\n { error: error.message },\n { status: 400 }\n )\n }\n if (error.code === 'START_PRE_CONDITIONS_FAILED') {\n return NextResponse.json(\n {\n error: error.message,\n code: error.code,\n details: error.details,\n },\n { status: 422 }\n )\n }\n }\n\n return NextResponse.json(\n { error: 'Failed to start workflow' },\n { status: 500 }\n )\n }\n}\n\nexport const openApi = {\n methods: {\n GET: {\n summary: 'List workflow instances',\n description: 'Get a list of workflow instances with optional filters. Supports pagination and filtering by status, workflowId, correlationKey, etc.',\n tags: ['Workflows'],\n query: z.object({\n workflowId: z.string().optional(),\n status: workflowInstanceStatusSchema.optional(),\n correlationKey: z.string().optional(),\n entityType: z.string().optional(),\n entityId: z.string().optional(),\n limit: z.number().int().positive().default(50).optional(),\n offset: z.number().int().min(0).default(0).optional(),\n }),\n responses: [\n {\n status: 200,\n description: 'List of workflow instances',\n schema: z.object({\n data: z.array(z.any()),\n pagination: z.object({\n total: z.number(),\n limit: z.number(),\n offset: z.number(),\n hasMore: z.boolean(),\n }),\n }),\n },\n {\n status: 401,\n description: 'Unauthorized',\n schema: z.object({ error: z.string() }),\n },\n {\n status: 500,\n description: 'Internal server error',\n schema: z.object({ error: z.string() }),\n },\n ],\n },\n POST: {\n summary: 'Start workflow instance',\n description: 'Start a new workflow instance from a workflow definition. The workflow will execute immediately.',\n tags: ['Workflows'],\n requestBody: {\n contentType: 'application/json',\n schema: startWorkflowInputSchema,\n description: 'Workflow instance configuration including workflowId, initial context, and metadata.',\n },\n responses: [\n {\n status: 201,\n description: 'Workflow started successfully',\n schema: z.object({\n data: z.object({\n instance: z.any(),\n execution: z.any(),\n }),\n message: z.string(),\n }),\n },\n {\n status: 400,\n description: 'Bad request - Validation failed or definition disabled/invalid',\n schema: z.object({\n error: z.string(),\n details: z.any().optional(),\n }),\n },\n {\n status: 401,\n description: 'Unauthorized',\n schema: z.object({ error: z.string() }),\n },\n {\n status: 403,\n description: 'Forbidden - Insufficient permissions',\n schema: z.object({ error: z.string() }),\n },\n {\n status: 404,\n description: 'Workflow definition not found',\n schema: z.object({ error: z.string() }),\n },\n {\n status: 500,\n description: 'Internal server error',\n schema: z.object({ error: z.string() }),\n },\n ],\n },\n },\n}\n"],
|
|
5
|
+
"mappings": "AAQA,SAAsB,oBAAoB;AAC1C,SAAS,SAAS;AAClB,SAAS,8BAA8B;AACvC,SAAS,0BAA0B;AACnC,SAAS,0CAA0C;AACnD,SAAS,wBAAwB;AACjC;AAAA,EACE;AAAA,EAEA;AAAA,OACK;AACP,YAAY,sBAAsB;AAE3B,MAAM,WAAW;AAAA,EACtB,aAAa;AAAA,EACb,iBAAiB,CAAC,0BAA0B;AAC9C;AAOA,eAAsB,IAAI,SAAsB;AAC9C,MAAI;AACF,UAAM,YAAY,MAAM,uBAAuB;AAC/C,UAAM,KAAK,UAAU,QAAQ,IAAI;AACjC,UAAM,OAAO,MAAM,mBAAmB,OAAO;AAE7C,QAAI,CAAC,MAAM;AACT,aAAO,aAAa,KAAK,EAAE,OAAO,eAAe,GAAG,EAAE,QAAQ,IAAI,CAAC;AAAA,IACrE;AAEA,UAAM,QAAQ,MAAM,mCAAmC,EAAE,WAAW,MAAM,QAAQ,CAAC;AACnF,UAAM,WAAW,KAAK;AACtB,UAAM,iBAAiB,OAAO,cAAc,KAAK;AAEjD,QAAI,CAAC,YAAY,CAAC,gBAAgB;AAChC,aAAO,aAAa;AAAA,QAClB,EAAE,OAAO,yCAAyC;AAAA,QAClD,EAAE,QAAQ,IAAI;AAAA,MAChB;AAAA,IACF;AAEA,UAAM,EAAE,aAAa,IAAI,IAAI,IAAI,QAAQ,GAAG;AAC5C,UAAM,aAAa,aAAa,IAAI,YAAY;AAChD,UAAM,SAAS,aAAa,IAAI,QAAQ;AACxC,UAAM,iBAAiB,aAAa,IAAI,gBAAgB;AACxD,UAAM,aAAa,aAAa,IAAI,YAAY;AAChD,UAAM,WAAW,aAAa,IAAI,UAAU;AAC5C,UAAM,QAAQ,SAAS,aAAa,IAAI,OAAO,KAAK,IAAI;AACxD,UAAM,SAAS,SAAS,aAAa,IAAI,QAAQ,KAAK,GAAG;AAGzD,UAAM,QAAa;AAAA,MACjB;AAAA,MACA;AAAA,IACF;AAEA,QAAI,YAAY;AACd,YAAM,aAAa;AAAA,IACrB;AAEA,QAAI,QAAQ;AAEV,YAAM,WAAW,OAAO,MAAM,GAAG,EAAE,IAAI,OAAK,EAAE,KAAK,CAAC,EAAE,OAAO,OAAO;AACpE,UAAI,SAAS,WAAW,GAAG;AACzB,cAAM,SAAS,SAAS,CAAC;AAAA,MAC3B,WAAW,SAAS,SAAS,GAAG;AAC9B,cAAM,SAAS,EAAE,KAAK,SAAS;AAAA,MACjC;AAAA,IACF;AAEA,QAAI,gBAAgB;AAClB,YAAM,iBAAiB;AAAA,IACzB;AAIA,QAAI,cAAc,UAAU;AAC1B,YAAM,OAAO,MAAM,QAAQ,CAAC;AAC5B,UAAI,YAAY;AACd,cAAM,KAAK,KAAK;AAAA,UACd,UAAU,EAAE,WAAW,EAAE,WAAuB,EAAE;AAAA,QACpD,CAAC;AAAA,MACH;AACA,UAAI,UAAU;AACZ,cAAM,KAAK,KAAK;AAAA,UACd,UAAU,EAAE,WAAW,EAAE,SAAmB,EAAE;AAAA,QAChD,CAAC;AAAA,MACH;AAAA,IACF;AAEA,UAAM,CAAC,WAAW,KAAK,IAAI,MAAM,GAAG;AAAA,MAClC;AAAA,MACA;AAAA,MACA;AAAA,QACE,SAAS,EAAE,WAAW,OAAO;AAAA,QAC7B;AAAA,QACA;AAAA,MACF;AAAA,IACF;AAEA,WAAO,aAAa,KAAK;AAAA,MACvB,MAAM;AAAA,MACN,YAAY;AAAA,QACV;AAAA,QACA;AAAA,QACA;AAAA,QACA,SAAS,SAAS,QAAQ;AAAA,MAC5B;AAAA,IACF,CAAC;AAAA,EACH,SAAS,OAAO;AACd,YAAQ,MAAM,qCAAqC,KAAK;AACxD,WAAO,aAAa;AAAA,MAClB,EAAE,OAAO,oCAAoC;AAAA,MAC7C,EAAE,QAAQ,IAAI;AAAA,IAChB;AAAA,EACF;AACF;AAOA,eAAsB,KAAK,SAAsB;AAC/C,MAAI;AACF,UAAM,YAAY,MAAM,uBAAuB;AAC/C,UAAM,KAAK,UAAU,QAAQ,IAAI;AACjC,UAAM,OAAO,MAAM,mBAAmB,OAAO;AAE7C,QAAI,CAAC,MAAM;AACT,aAAO,aAAa,KAAK,EAAE,OAAO,eAAe,GAAG,EAAE,QAAQ,IAAI,CAAC;AAAA,IACrE;AAEA,UAAM,QAAQ,MAAM,mCAAmC,EAAE,WAAW,MAAM,QAAQ,CAAC;AACnF,UAAM,WAAW,KAAK;AACtB,UAAM,iBAAiB,OAAO,cAAc,KAAK;AAEjD,QAAI,CAAC,YAAY,CAAC,gBAAgB;AAChC,aAAO,aAAa;AAAA,QAClB,EAAE,OAAO,yCAAyC;AAAA,QAClD,EAAE,QAAQ,IAAI;AAAA,MAChB;AAAA,IACF;AAGA,UAAM,cAAc,UAAU,QAAQ,aAAa;AACnD,UAAM,gBAAgB,MAAM,YAAY;AAAA,MACtC,KAAK;AAAA,MACL,CAAC,4BAA4B;AAAA,MAC7B;AAAA,QACE;AAAA,QACA;AAAA,MACF;AAAA,IACF;AAEA,QAAI,CAAC,eAAe;AAClB,aAAO,aAAa;AAAA,QAClB,EAAE,OAAO,2BAA2B;AAAA,QACpC,EAAE,QAAQ,IAAI;AAAA,MAChB;AAAA,IACF;AAEA,UAAM,OAAO,MAAM,QAAQ,KAAK;AAGhC,UAAM,aAAa,yBAAyB,UAAU,IAAI;AAC1D,QAAI,CAAC,WAAW,SAAS;AACvB,aAAO,aAAa;AAAA,QAClB;AAAA,UACE,OAAO;AAAA,UACP,SAAS,WAAW,MAAM;AAAA,QAC5B;AAAA,QACA,EAAE,QAAQ,IAAI;AAAA,MAChB;AAAA,IACF;AAEA,UAAM,QAA+B,WAAW;AAGhD,UAAMA,YAAW;AAAA,MACf,GAAG,MAAM;AAAA,MACT,aAAa,MAAM,UAAU,eAAe,KAAK;AAAA,IACnD;AAGA,UAAM,WAAW,MAAM,iBAAiB,cAAc,IAAI;AAAA,MACxD,YAAY,MAAM;AAAA,MAClB,SAAS,MAAM;AAAA,MACf,gBAAgB,MAAM,kBAAkB,CAAC;AAAA,MACzC,gBAAgB,MAAM;AAAA,MACtB,UAAAA;AAAA,MACA;AAAA,MACA;AAAA,IACF,CAAC;AAID,iBAAa,YAAY;AACvB,UAAI;AAEF,cAAM,cAAc,MAAM,uBAAuB;AACjD,cAAM,OAAO,YAAY,QAAQ,IAAI;AACrC,cAAM,iBAAiB,gBAAgB,MAAM,aAAa,SAAS,EAAE;AAAA,MACvE,SAAS,OAAO;AACd,gBAAQ,MAAM,wCAAwC,KAAK;AAAA,MAC7D;AAAA,IACF,CAAC;AAED,WAAO,aAAa;AAAA,MAClB;AAAA,QACE,MAAM;AAAA,UACJ;AAAA,UACA,WAAW;AAAA,YACT,QAAQ,SAAS;AAAA,YACjB,aAAa,SAAS;AAAA,YACtB,SAAS;AAAA,UACX;AAAA,QACF;AAAA,QACA,SAAS;AAAA,MACX;AAAA,MACA,EAAE,QAAQ,IAAI;AAAA,IAChB;AAAA,EACF,SAAS,OAAO;AACd,YAAQ,MAAM,4BAA4B,KAAK;AAG/C,QAAI,iBAAiB,iBAAiB,wBAAwB;AAC5D,UAAI,MAAM,SAAS,wBAAwB;AACzC,eAAO,aAAa;AAAA,UAClB,EAAE,OAAO,MAAM,QAAQ;AAAA,UACvB,EAAE,QAAQ,IAAI;AAAA,QAChB;AAAA,MACF;AACA,UAAI,MAAM,SAAS,uBAAuB;AACxC,eAAO,aAAa;AAAA,UAClB,EAAE,OAAO,MAAM,QAAQ;AAAA,UACvB,EAAE,QAAQ,IAAI;AAAA,QAChB;AAAA,MACF;AACA,UAAI,MAAM,SAAS,sBAAsB;AACvC,eAAO,aAAa;AAAA,UAClB,EAAE,OAAO,MAAM,QAAQ;AAAA,UACvB,EAAE,QAAQ,IAAI;AAAA,QAChB;AAAA,MACF;AACA,UAAI,MAAM,SAAS,+BAA+B;AAChD,eAAO,aAAa;AAAA,UAClB;AAAA,YACE,OAAO,MAAM;AAAA,YACb,MAAM,MAAM;AAAA,YACZ,SAAS,MAAM;AAAA,UACjB;AAAA,UACA,EAAE,QAAQ,IAAI;AAAA,QAChB;AAAA,MACF;AAAA,IACF;AAEA,WAAO,aAAa;AAAA,MAClB,EAAE,OAAO,2BAA2B;AAAA,MACpC,EAAE,QAAQ,IAAI;AAAA,IAChB;AAAA,EACF;AACF;AAEO,MAAM,UAAU;AAAA,EACrB,SAAS;AAAA,IACP,KAAK;AAAA,MACH,SAAS;AAAA,MACT,aAAa;AAAA,MACb,MAAM,CAAC,WAAW;AAAA,MAClB,OAAO,EAAE,OAAO;AAAA,QACd,YAAY,EAAE,OAAO,EAAE,SAAS;AAAA,QAChC,QAAQ,6BAA6B,SAAS;AAAA,QAC9C,gBAAgB,EAAE,OAAO,EAAE,SAAS;AAAA,QACpC,YAAY,EAAE,OAAO,EAAE,SAAS;AAAA,QAChC,UAAU,EAAE,OAAO,EAAE,SAAS;AAAA,QAC9B,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAE,EAAE,SAAS;AAAA,QACxD,QAAQ,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,EAAE,QAAQ,CAAC,EAAE,SAAS;AAAA,MACtD,CAAC;AAAA,MACD,WAAW;AAAA,QACT;AAAA,UACE,QAAQ;AAAA,UACR,aAAa;AAAA,UACb,QAAQ,EAAE,OAAO;AAAA,YACf,MAAM,EAAE,MAAM,EAAE,IAAI,CAAC;AAAA,YACrB,YAAY,EAAE,OAAO;AAAA,cACnB,OAAO,EAAE,OAAO;AAAA,cAChB,OAAO,EAAE,OAAO;AAAA,cAChB,QAAQ,EAAE,OAAO;AAAA,cACjB,SAAS,EAAE,QAAQ;AAAA,YACrB,CAAC;AAAA,UACH,CAAC;AAAA,QACH;AAAA,QACA;AAAA,UACE,QAAQ;AAAA,UACR,aAAa;AAAA,UACb,QAAQ,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC;AAAA,QACxC;AAAA,QACA;AAAA,UACE,QAAQ;AAAA,UACR,aAAa;AAAA,UACb,QAAQ,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC;AAAA,QACxC;AAAA,MACF;AAAA,IACF;AAAA,IACA,MAAM;AAAA,MACJ,SAAS;AAAA,MACT,aAAa;AAAA,MACb,MAAM,CAAC,WAAW;AAAA,MAClB,aAAa;AAAA,QACX,aAAa;AAAA,QACb,QAAQ;AAAA,QACR,aAAa;AAAA,MACf;AAAA,MACA,WAAW;AAAA,QACT;AAAA,UACE,QAAQ;AAAA,UACR,aAAa;AAAA,UACb,QAAQ,EAAE,OAAO;AAAA,YACf,MAAM,EAAE,OAAO;AAAA,cACb,UAAU,EAAE,IAAI;AAAA,cAChB,WAAW,EAAE,IAAI;AAAA,YACnB,CAAC;AAAA,YACD,SAAS,EAAE,OAAO;AAAA,UACpB,CAAC;AAAA,QACH;AAAA,QACA;AAAA,UACE,QAAQ;AAAA,UACR,aAAa;AAAA,UACb,QAAQ,EAAE,OAAO;AAAA,YACf,OAAO,EAAE,OAAO;AAAA,YAChB,SAAS,EAAE,IAAI,EAAE,SAAS;AAAA,UAC5B,CAAC;AAAA,QACH;AAAA,QACA;AAAA,UACE,QAAQ;AAAA,UACR,aAAa;AAAA,UACb,QAAQ,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC;AAAA,QACxC;AAAA,QACA;AAAA,UACE,QAAQ;AAAA,UACR,aAAa;AAAA,UACb,QAAQ,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC;AAAA,QACxC;AAAA,QACA;AAAA,UACE,QAAQ;AAAA,UACR,aAAa;AAAA,UACb,QAAQ,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC;AAAA,QACxC;AAAA,QACA;AAAA,UACE,QAAQ;AAAA,UACR,aAAa;AAAA,UACb,QAAQ,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC;AAAA,QACxC;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;",
|
|
6
6
|
"names": ["metadata"]
|
|
7
7
|
}
|