@open-mercato/core 0.6.5-develop.4516.1.88e6ab71a9 → 0.6.5-develop.4544.1.71c003c861
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/.turbo/turbo-build.log +2 -2
- package/AGENTS.md +5 -0
- package/dist/generated/entities/role/index.js +3 -1
- package/dist/generated/entities/role/index.js.map +2 -2
- package/dist/generated/entities/step_instance/index.js +2 -0
- package/dist/generated/entities/step_instance/index.js.map +2 -2
- package/dist/generated/entities/user/index.js +3 -1
- package/dist/generated/entities/user/index.js.map +2 -2
- package/dist/generated/entities/user_task/index.js +2 -0
- package/dist/generated/entities/user_task/index.js.map +2 -2
- package/dist/generated/entities/workflow_branch_instance/index.js +39 -0
- package/dist/generated/entities/workflow_branch_instance/index.js.map +7 -0
- package/dist/generated/entities/workflow_event/index.js +2 -0
- package/dist/generated/entities/workflow_event/index.js.map +2 -2
- package/dist/generated/entities/workflow_instance/index.js +2 -0
- package/dist/generated/entities/workflow_instance/index.js.map +2 -2
- package/dist/generated/entities.ids.generated.js +1 -0
- package/dist/generated/entities.ids.generated.js.map +2 -2
- package/dist/generated/entity-fields-registry.js +26 -0
- package/dist/generated/entity-fields-registry.js.map +2 -2
- package/dist/helpers/integration/optimisticLockUi.js +104 -0
- package/dist/helpers/integration/optimisticLockUi.js.map +7 -0
- package/dist/helpers/integration/salesFixtures.js +17 -0
- package/dist/helpers/integration/salesFixtures.js.map +2 -2
- package/dist/modules/api_keys/backend/api-keys/page.js +9 -5
- package/dist/modules/api_keys/backend/api-keys/page.js.map +2 -2
- package/dist/modules/attachments/components/AttachmentPartitionSettings.js +17 -9
- package/dist/modules/attachments/components/AttachmentPartitionSettings.js.map +2 -2
- package/dist/modules/auth/api/roles/acl/route.js +32 -13
- package/dist/modules/auth/api/roles/acl/route.js.map +2 -2
- package/dist/modules/auth/api/roles/route.js +3 -1
- package/dist/modules/auth/api/roles/route.js.map +2 -2
- package/dist/modules/auth/api/sidebar/preferences/route.js +71 -3
- package/dist/modules/auth/api/sidebar/preferences/route.js.map +2 -2
- package/dist/modules/auth/api/users/acl/route.js +42 -19
- package/dist/modules/auth/api/users/acl/route.js.map +2 -2
- package/dist/modules/auth/api/users/route.js +3 -1
- package/dist/modules/auth/api/users/route.js.map +2 -2
- package/dist/modules/auth/backend/roles/[id]/edit/page.js +24 -4
- package/dist/modules/auth/backend/roles/[id]/edit/page.js.map +2 -2
- package/dist/modules/auth/backend/roles/page.js +8 -4
- package/dist/modules/auth/backend/roles/page.js.map +2 -2
- package/dist/modules/auth/backend/users/[id]/edit/page.js +27 -5
- package/dist/modules/auth/backend/users/[id]/edit/page.js.map +2 -2
- package/dist/modules/auth/backend/users/page.js +6 -2
- package/dist/modules/auth/backend/users/page.js.map +2 -2
- package/dist/modules/auth/components/AclEditor.js +3 -1
- package/dist/modules/auth/components/AclEditor.js.map +2 -2
- package/dist/modules/auth/data/entities.js +6 -0
- package/dist/modules/auth/data/entities.js.map +2 -2
- package/dist/modules/auth/services/sidebarPreferencesService.js +32 -4
- package/dist/modules/auth/services/sidebarPreferencesService.js.map +2 -2
- package/dist/modules/business_rules/api/rules/route.js +28 -0
- package/dist/modules/business_rules/api/rules/route.js.map +2 -2
- package/dist/modules/business_rules/api/sets/route.js +28 -0
- package/dist/modules/business_rules/api/sets/route.js.map +2 -2
- package/dist/modules/business_rules/backend/rules/[id]/page.js +11 -4
- package/dist/modules/business_rules/backend/rules/[id]/page.js.map +3 -3
- package/dist/modules/business_rules/backend/rules/page.js +20 -11
- package/dist/modules/business_rules/backend/rules/page.js.map +2 -2
- package/dist/modules/business_rules/backend/sets/[id]/page.js +11 -4
- package/dist/modules/business_rules/backend/sets/[id]/page.js.map +2 -2
- package/dist/modules/business_rules/backend/sets/page.js +20 -11
- package/dist/modules/business_rules/backend/sets/page.js.map +2 -2
- package/dist/modules/catalog/api/categories/route.js +2 -0
- package/dist/modules/catalog/api/categories/route.js.map +2 -2
- package/dist/modules/catalog/api/products/route.js +2 -1
- package/dist/modules/catalog/api/products/route.js.map +2 -2
- package/dist/modules/catalog/backend/catalog/categories/[id]/edit/page.js +2 -0
- package/dist/modules/catalog/backend/catalog/categories/[id]/edit/page.js.map +2 -2
- package/dist/modules/catalog/backend/catalog/products/[id]/page.js +94 -40
- package/dist/modules/catalog/backend/catalog/products/[id]/page.js.map +2 -2
- package/dist/modules/catalog/backend/catalog/products/[productId]/variants/[variantId]/page.js +37 -8
- package/dist/modules/catalog/backend/catalog/products/[productId]/variants/[variantId]/page.js.map +2 -2
- package/dist/modules/catalog/backend/catalog/products/optionSchemaClient.js.map +2 -2
- package/dist/modules/catalog/commands/variants.js +32 -31
- package/dist/modules/catalog/commands/variants.js.map +2 -2
- package/dist/modules/catalog/components/PriceKindSettings.js +12 -5
- package/dist/modules/catalog/components/PriceKindSettings.js.map +2 -2
- package/dist/modules/catalog/components/categories/CategoriesDataTable.js.map +2 -2
- package/dist/modules/catalog/components/products/ProductMediaManager.js.map +2 -2
- package/dist/modules/catalog/components/products/ProductsDataTable.js +5 -3
- package/dist/modules/catalog/components/products/ProductsDataTable.js.map +2 -2
- package/dist/modules/catalog/components/products/productForm.js.map +2 -2
- package/dist/modules/catalog/components/products/variantForm.js +2 -1
- package/dist/modules/catalog/components/products/variantForm.js.map +2 -2
- package/dist/modules/communication_channels/backend/profile/communication-channels/page.js +5 -0
- package/dist/modules/communication_channels/backend/profile/communication-channels/page.js.map +2 -2
- package/dist/modules/currencies/backend/currencies/[id]/page.js +6 -3
- package/dist/modules/currencies/backend/currencies/[id]/page.js.map +2 -2
- package/dist/modules/currencies/backend/currencies/page.js +18 -11
- package/dist/modules/currencies/backend/currencies/page.js.map +2 -2
- package/dist/modules/currencies/backend/exchange-rates/[id]/page.js +1 -0
- package/dist/modules/currencies/backend/exchange-rates/[id]/page.js.map +2 -2
- package/dist/modules/currencies/backend/exchange-rates/page.js +10 -6
- package/dist/modules/currencies/backend/exchange-rates/page.js.map +2 -2
- package/dist/modules/currencies/commands/currencies.js +7 -5
- package/dist/modules/currencies/commands/currencies.js.map +2 -2
- package/dist/modules/currencies/components/CurrencyFetchingConfig.js +26 -19
- package/dist/modules/currencies/components/CurrencyFetchingConfig.js.map +2 -2
- package/dist/modules/customer_accounts/api/admin/roles/[id].js +28 -5
- package/dist/modules/customer_accounts/api/admin/roles/[id].js.map +2 -2
- package/dist/modules/customer_accounts/api/admin/roles.js +4 -2
- package/dist/modules/customer_accounts/api/admin/roles.js.map +2 -2
- package/dist/modules/customer_accounts/api/admin/users/[id].js +28 -5
- package/dist/modules/customer_accounts/api/admin/users/[id].js.map +2 -2
- package/dist/modules/customer_accounts/api/admin/users.js +2 -0
- package/dist/modules/customer_accounts/api/admin/users.js.map +2 -2
- package/dist/modules/customer_accounts/backend/customer_accounts/roles/[id]/page.js +16 -8
- package/dist/modules/customer_accounts/backend/customer_accounts/roles/[id]/page.js.map +2 -2
- package/dist/modules/customer_accounts/backend/customer_accounts/roles/page.js +8 -4
- package/dist/modules/customer_accounts/backend/customer_accounts/roles/page.js.map +2 -2
- package/dist/modules/customer_accounts/backend/customer_accounts/settings/domain/page.js +8 -4
- package/dist/modules/customer_accounts/backend/customer_accounts/settings/domain/page.js.map +2 -2
- package/dist/modules/customer_accounts/backend/customer_accounts/users/[id]/page.js +29 -18
- package/dist/modules/customer_accounts/backend/customer_accounts/users/[id]/page.js.map +2 -2
- package/dist/modules/customer_accounts/backend/customer_accounts/users/page.js +18 -11
- package/dist/modules/customer_accounts/backend/customer_accounts/users/page.js.map +2 -2
- package/dist/modules/customers/api/companies/route.js +13 -2
- package/dist/modules/customers/api/companies/route.js.map +2 -2
- package/dist/modules/customers/api/deals/route.js +2 -0
- package/dist/modules/customers/api/deals/route.js.map +2 -2
- package/dist/modules/customers/api/people/route.js +11 -2
- package/dist/modules/customers/api/people/route.js.map +2 -2
- package/dist/modules/customers/api/todos/route.js +1 -0
- package/dist/modules/customers/api/todos/route.js.map +2 -2
- package/dist/modules/customers/backend/config/customers/deals/page.js.map +2 -2
- package/dist/modules/customers/backend/config/customers/pipeline-stages/page.js +34 -21
- package/dist/modules/customers/backend/config/customers/pipeline-stages/page.js.map +2 -2
- package/dist/modules/customers/backend/customers/companies/[id]/page.js +45 -27
- package/dist/modules/customers/backend/customers/companies/[id]/page.js.map +2 -2
- package/dist/modules/customers/backend/customers/companies/page.js.map +2 -2
- package/dist/modules/customers/backend/customers/companies-v2/[id]/page.js +22 -5
- package/dist/modules/customers/backend/customers/companies-v2/[id]/page.js.map +2 -2
- package/dist/modules/customers/backend/customers/deals/[id]/hooks/useDealFormHandlers.js +30 -8
- package/dist/modules/customers/backend/customers/deals/[id]/hooks/useDealFormHandlers.js.map +2 -2
- package/dist/modules/customers/backend/customers/deals/[id]/page.js +1 -0
- package/dist/modules/customers/backend/customers/deals/[id]/page.js.map +2 -2
- package/dist/modules/customers/backend/customers/deals/page.js +16 -6
- package/dist/modules/customers/backend/customers/deals/page.js.map +2 -2
- package/dist/modules/customers/backend/customers/deals/pipeline/page.js +62 -39
- package/dist/modules/customers/backend/customers/deals/pipeline/page.js.map +2 -2
- package/dist/modules/customers/backend/customers/people/[id]/page.js +41 -26
- package/dist/modules/customers/backend/customers/people/[id]/page.js.map +2 -2
- package/dist/modules/customers/backend/customers/people/page.js.map +2 -2
- package/dist/modules/customers/backend/customers/people-v2/[id]/page.js +50 -23
- package/dist/modules/customers/backend/customers/people-v2/[id]/page.js.map +2 -2
- package/dist/modules/customers/commands/addresses.js +16 -14
- package/dist/modules/customers/commands/addresses.js.map +2 -2
- package/dist/modules/customers/commands/companies.js +1 -1
- package/dist/modules/customers/commands/companies.js.map +2 -2
- package/dist/modules/customers/commands/interactions.js +41 -4
- package/dist/modules/customers/commands/interactions.js.map +2 -2
- package/dist/modules/customers/commands/people.js +1 -1
- package/dist/modules/customers/commands/people.js.map +2 -2
- package/dist/modules/customers/commands/personCompanyLinks.js +8 -5
- package/dist/modules/customers/commands/personCompanyLinks.js.map +2 -2
- package/dist/modules/customers/commands/pipeline-stages.js +13 -11
- package/dist/modules/customers/commands/pipeline-stages.js.map +3 -3
- package/dist/modules/customers/components/AddressFormatSettings.js.map +2 -2
- package/dist/modules/customers/components/DictionarySettings.js +20 -13
- package/dist/modules/customers/components/DictionarySettings.js.map +2 -2
- package/dist/modules/customers/components/DictionarySortSettings.js +4 -0
- package/dist/modules/customers/components/DictionarySortSettings.js.map +2 -2
- package/dist/modules/customers/components/PipelineSettings.js +38 -23
- package/dist/modules/customers/components/PipelineSettings.js.map +2 -2
- package/dist/modules/customers/components/detail/ActivityTimeline.js +1 -1
- package/dist/modules/customers/components/detail/ActivityTimeline.js.map +2 -2
- package/dist/modules/customers/components/detail/AddressesSection.js +4 -0
- package/dist/modules/customers/components/detail/AddressesSection.js.map +2 -2
- package/dist/modules/customers/components/detail/CompanyPeopleSection.js +28 -22
- package/dist/modules/customers/components/detail/CompanyPeopleSection.js.map +2 -2
- package/dist/modules/customers/components/detail/DealsSection.js +36 -24
- package/dist/modules/customers/components/detail/DealsSection.js.map +2 -2
- package/dist/modules/customers/components/detail/EmailCardActions.js +5 -0
- package/dist/modules/customers/components/detail/EmailCardActions.js.map +2 -2
- package/dist/modules/customers/components/detail/EntityTagsDialog.js +7 -0
- package/dist/modules/customers/components/detail/EntityTagsDialog.js.map +2 -2
- package/dist/modules/customers/components/detail/ManageTagsDialog.js +34 -22
- package/dist/modules/customers/components/detail/ManageTagsDialog.js.map +2 -2
- package/dist/modules/customers/components/detail/PersonCompaniesSection.js +41 -29
- package/dist/modules/customers/components/detail/PersonCompaniesSection.js.map +2 -2
- package/dist/modules/customers/components/detail/RoleAssignmentRow.js +14 -8
- package/dist/modules/customers/components/detail/RoleAssignmentRow.js.map +2 -2
- package/dist/modules/customers/components/detail/ScheduleActivityDialog.js +14 -6
- package/dist/modules/customers/components/detail/ScheduleActivityDialog.js.map +2 -2
- package/dist/modules/customers/components/detail/hooks/useInteractionMutations.js +29 -13
- package/dist/modules/customers/components/detail/hooks/useInteractionMutations.js.map +2 -2
- package/dist/modules/customers/components/detail/hooks/useInteractions.js +77 -35
- package/dist/modules/customers/components/detail/hooks/useInteractions.js.map +2 -2
- package/dist/modules/customers/components/detail/hooks/usePersonTasks.js +25 -17
- package/dist/modules/customers/components/detail/hooks/usePersonTasks.js.map +2 -2
- package/dist/modules/customers/components/detail/schedule/useScheduleFormState.js.map +2 -2
- package/dist/modules/customers/components/formConfig.js.map +2 -2
- package/dist/modules/customers/data/guards.js +66 -0
- package/dist/modules/customers/data/guards.js.map +7 -0
- package/dist/modules/customers/di.js +37 -0
- package/dist/modules/customers/di.js.map +2 -2
- package/dist/modules/customers/lib/todoCompatibility.js +11 -0
- package/dist/modules/customers/lib/todoCompatibility.js.map +2 -2
- package/dist/modules/dashboards/components/WidgetVisibilityEditor.js.map +2 -2
- package/dist/modules/data_sync/api/options.js +4 -4
- package/dist/modules/data_sync/api/options.js.map +2 -2
- package/dist/modules/data_sync/api/schedules/route.js +9 -1
- package/dist/modules/data_sync/api/schedules/route.js.map +2 -2
- package/dist/modules/data_sync/backend/data-sync/page.js +17 -8
- package/dist/modules/data_sync/backend/data-sync/page.js.map +2 -2
- package/dist/modules/data_sync/components/IntegrationScheduleTab.js +43 -22
- package/dist/modules/data_sync/components/IntegrationScheduleTab.js.map +2 -2
- package/dist/modules/data_sync/lib/sync-schedule-service.js +9 -0
- package/dist/modules/data_sync/lib/sync-schedule-service.js.map +2 -2
- package/dist/modules/dictionaries/api/[dictionaryId]/entries/[entryId]/route.js +8 -1
- package/dist/modules/dictionaries/api/[dictionaryId]/entries/[entryId]/route.js.map +2 -2
- package/dist/modules/dictionaries/api/[dictionaryId]/route.js +17 -1
- package/dist/modules/dictionaries/api/[dictionaryId]/route.js.map +2 -2
- package/dist/modules/dictionaries/components/DictionariesManager.js +31 -10
- package/dist/modules/dictionaries/components/DictionariesManager.js.map +2 -2
- package/dist/modules/dictionaries/components/DictionaryEntriesEditor.js +28 -15
- package/dist/modules/dictionaries/components/DictionaryEntriesEditor.js.map +2 -2
- package/dist/modules/directory/api/organizations/route.js +3 -0
- package/dist/modules/directory/api/organizations/route.js.map +2 -2
- package/dist/modules/directory/backend/directory/organizations/[id]/edit/page.js +2 -0
- package/dist/modules/directory/backend/directory/organizations/[id]/edit/page.js.map +2 -2
- package/dist/modules/directory/backend/directory/organizations/page.js +9 -5
- package/dist/modules/directory/backend/directory/organizations/page.js.map +2 -2
- package/dist/modules/directory/backend/directory/tenants/[id]/edit/page.js +7 -3
- package/dist/modules/directory/backend/directory/tenants/[id]/edit/page.js.map +2 -2
- package/dist/modules/directory/backend/directory/tenants/page.js +8 -4
- package/dist/modules/directory/backend/directory/tenants/page.js.map +2 -2
- package/dist/modules/directory/commands/organizations.js +7 -2
- package/dist/modules/directory/commands/organizations.js.map +2 -2
- package/dist/modules/entities/api/records.js +66 -0
- package/dist/modules/entities/api/records.js.map +2 -2
- package/dist/modules/entities/backend/entities/user/[entityId]/records/[recordId]/page.js +1 -0
- package/dist/modules/entities/backend/entities/user/[entityId]/records/[recordId]/page.js.map +2 -2
- package/dist/modules/entities/backend/entities/user/[entityId]/records/page.js +8 -4
- package/dist/modules/entities/backend/entities/user/[entityId]/records/page.js.map +2 -2
- package/dist/modules/entities/lib/helpers.js +17 -0
- package/dist/modules/entities/lib/helpers.js.map +2 -2
- package/dist/modules/feature_toggles/api/global/[id]/override/route.js +2 -1
- package/dist/modules/feature_toggles/api/global/[id]/override/route.js.map +2 -2
- package/dist/modules/feature_toggles/api/overrides/route.js +15 -0
- package/dist/modules/feature_toggles/api/overrides/route.js.map +2 -2
- package/dist/modules/feature_toggles/backend/feature-toggles/global/[id]/edit/page.js +15 -14
- package/dist/modules/feature_toggles/backend/feature-toggles/global/[id]/edit/page.js.map +2 -2
- package/dist/modules/feature_toggles/components/FeatureToggleOverrideCard.js +20 -12
- package/dist/modules/feature_toggles/components/FeatureToggleOverrideCard.js.map +2 -2
- package/dist/modules/feature_toggles/components/FeatureTogglesTable.js +6 -2
- package/dist/modules/feature_toggles/components/FeatureTogglesTable.js.map +2 -2
- package/dist/modules/feature_toggles/components/formConfig.js +2 -1
- package/dist/modules/feature_toggles/components/formConfig.js.map +2 -2
- package/dist/modules/feature_toggles/components/overrideFormConfig.js +5 -1
- package/dist/modules/feature_toggles/components/overrideFormConfig.js.map +2 -2
- package/dist/modules/feature_toggles/data/validators.js +7 -4
- package/dist/modules/feature_toggles/data/validators.js.map +2 -2
- package/dist/modules/inbox_ops/api/settings/route.js +17 -2
- package/dist/modules/inbox_ops/api/settings/route.js.map +2 -2
- package/dist/modules/inbox_ops/backend/inbox-ops/settings/page.js +13 -8
- package/dist/modules/inbox_ops/backend/inbox-ops/settings/page.js.map +2 -2
- package/dist/modules/inbox_ops/components/proposals/EditActionDialog.js +9 -4
- package/dist/modules/inbox_ops/components/proposals/EditActionDialog.js.map +2 -2
- package/dist/modules/integrations/backend/integrations/bundle/[id]/page.js +18 -11
- package/dist/modules/integrations/backend/integrations/bundle/[id]/page.js.map +2 -2
- package/dist/modules/integrations/backend/integrations/page.js +12 -8
- package/dist/modules/integrations/backend/integrations/page.js.map +2 -2
- package/dist/modules/messages/commands/messages.js +13 -10
- package/dist/modules/messages/commands/messages.js.map +2 -2
- package/dist/modules/perspectives/api/[tableId]/route.js +39 -30
- package/dist/modules/perspectives/api/[tableId]/route.js.map +2 -2
- package/dist/modules/perspectives/services/perspectiveService.js +7 -0
- package/dist/modules/perspectives/services/perspectiveService.js.map +2 -2
- package/dist/modules/planner/backend/planner/availability-rulesets/[id]/page.js +6 -14
- package/dist/modules/planner/backend/planner/availability-rulesets/[id]/page.js.map +3 -3
- package/dist/modules/planner/backend/planner/availability-rulesets/page.js +4 -2
- package/dist/modules/planner/backend/planner/availability-rulesets/page.js.map +2 -2
- package/dist/modules/planner/components/AvailabilityRuleSetForm.js +2 -0
- package/dist/modules/planner/components/AvailabilityRuleSetForm.js.map +2 -2
- package/dist/modules/planner/components/AvailabilityRulesEditor.js +36 -11
- package/dist/modules/planner/components/AvailabilityRulesEditor.js.map +2 -2
- package/dist/modules/planner/components/AvailabilitySchedule.js +9 -5
- package/dist/modules/planner/components/AvailabilitySchedule.js.map +2 -2
- package/dist/modules/progress/api/jobs/[id]/route.js +7 -1
- package/dist/modules/progress/api/jobs/[id]/route.js.map +2 -2
- package/dist/modules/query_index/lib/engine.js +19 -0
- package/dist/modules/query_index/lib/engine.js.map +2 -2
- package/dist/modules/resources/backend/resources/resource-types/[id]/edit/page.js +1 -0
- package/dist/modules/resources/backend/resources/resource-types/[id]/edit/page.js.map +2 -2
- package/dist/modules/resources/backend/resources/resource-types/page.js +4 -2
- package/dist/modules/resources/backend/resources/resource-types/page.js.map +2 -2
- package/dist/modules/resources/backend/resources/resources/[id]/page.js +14 -3
- package/dist/modules/resources/backend/resources/resources/[id]/page.js.map +2 -2
- package/dist/modules/resources/backend/resources/resources/page.js +8 -4
- package/dist/modules/resources/backend/resources/resources/page.js.map +2 -2
- package/dist/modules/resources/components/ResourceCrudForm.js +2 -0
- package/dist/modules/resources/components/ResourceCrudForm.js.map +2 -2
- package/dist/modules/resources/components/ResourceTypeCrudForm.js +1 -0
- package/dist/modules/resources/components/ResourceTypeCrudForm.js.map +2 -2
- package/dist/modules/sales/api/documents/factory.js +7 -2
- package/dist/modules/sales/api/documents/factory.js.map +2 -2
- package/dist/modules/sales/backend/sales/channels/[channelId]/edit/page.js +3 -1
- package/dist/modules/sales/backend/sales/channels/[channelId]/edit/page.js.map +2 -2
- package/dist/modules/sales/backend/sales/channels/offers/page.js +13 -4
- package/dist/modules/sales/backend/sales/channels/offers/page.js.map +2 -2
- package/dist/modules/sales/backend/sales/channels/page.js +16 -4
- package/dist/modules/sales/backend/sales/channels/page.js.map +2 -2
- package/dist/modules/sales/backend/sales/documents/[id]/page.js +68 -22
- package/dist/modules/sales/backend/sales/documents/[id]/page.js.map +2 -2
- package/dist/modules/sales/backend/sales/documents/create/page.js.map +2 -2
- package/dist/modules/sales/commands/documentAddresses.js +181 -2
- package/dist/modules/sales/commands/documentAddresses.js.map +2 -2
- package/dist/modules/sales/commands/documents.js +29 -1
- package/dist/modules/sales/commands/documents.js.map +2 -2
- package/dist/modules/sales/commands/returns.js +12 -2
- package/dist/modules/sales/commands/returns.js.map +2 -2
- package/dist/modules/sales/commands/shared.js +15 -0
- package/dist/modules/sales/commands/shared.js.map +2 -2
- package/dist/modules/sales/commands/shipments.js +4 -1
- package/dist/modules/sales/commands/shipments.js.map +2 -2
- package/dist/modules/sales/components/AdjustmentKindSettings.js +19 -11
- package/dist/modules/sales/components/AdjustmentKindSettings.js.map +2 -2
- package/dist/modules/sales/components/DocumentNumberSettings.js.map +2 -2
- package/dist/modules/sales/components/OrderEditingSettings.js.map +2 -2
- package/dist/modules/sales/components/PaymentMethodsSettings.js +12 -4
- package/dist/modules/sales/components/PaymentMethodsSettings.js.map +2 -2
- package/dist/modules/sales/components/ShippingMethodsSettings.js +12 -4
- package/dist/modules/sales/components/ShippingMethodsSettings.js.map +2 -2
- package/dist/modules/sales/components/StatusSettings.js +18 -11
- package/dist/modules/sales/components/StatusSettings.js.map +2 -2
- package/dist/modules/sales/components/TaxRatesSettings.js +12 -4
- package/dist/modules/sales/components/TaxRatesSettings.js.map +2 -2
- package/dist/modules/sales/components/channels/ChannelOfferForm.js +47 -16
- package/dist/modules/sales/components/channels/ChannelOfferForm.js.map +2 -2
- package/dist/modules/sales/components/channels/SalesChannelOffersPanel.js +8 -4
- package/dist/modules/sales/components/channels/SalesChannelOffersPanel.js.map +2 -2
- package/dist/modules/sales/components/documents/AddressesSection.js +44 -25
- package/dist/modules/sales/components/documents/AddressesSection.js.map +2 -2
- package/dist/modules/sales/components/documents/AdjustmentsSection.js +43 -23
- package/dist/modules/sales/components/documents/AdjustmentsSection.js.map +2 -2
- package/dist/modules/sales/components/documents/ItemsSection.js +22 -13
- package/dist/modules/sales/components/documents/ItemsSection.js.map +2 -2
- package/dist/modules/sales/components/documents/LineItemDialog.js +23 -10
- package/dist/modules/sales/components/documents/LineItemDialog.js.map +2 -2
- package/dist/modules/sales/components/documents/PaymentDialog.js +29 -14
- package/dist/modules/sales/components/documents/PaymentDialog.js.map +2 -2
- package/dist/modules/sales/components/documents/PaymentsSection.js +20 -10
- package/dist/modules/sales/components/documents/PaymentsSection.js.map +2 -2
- package/dist/modules/sales/components/documents/ReturnDialog.js +26 -17
- package/dist/modules/sales/components/documents/ReturnDialog.js.map +2 -2
- package/dist/modules/sales/components/documents/ReturnsSection.js +3 -1
- package/dist/modules/sales/components/documents/ReturnsSection.js.map +2 -2
- package/dist/modules/sales/components/documents/SalesDocumentsTable.js +10 -5
- package/dist/modules/sales/components/documents/SalesDocumentsTable.js.map +2 -2
- package/dist/modules/sales/components/documents/ShipmentDialog.js +21 -7
- package/dist/modules/sales/components/documents/ShipmentDialog.js.map +2 -2
- package/dist/modules/sales/components/documents/ShipmentsSection.js +19 -10
- package/dist/modules/sales/components/documents/ShipmentsSection.js.map +2 -2
- package/dist/modules/sales/components/documents/optimisticLock.js +27 -0
- package/dist/modules/sales/components/documents/optimisticLock.js.map +7 -0
- package/dist/modules/sales/di.js +18 -0
- package/dist/modules/sales/di.js.map +2 -2
- package/dist/modules/shipping_carriers/api/cancel/route.js +2 -2
- package/dist/modules/shipping_carriers/api/cancel/route.js.map +2 -2
- package/dist/modules/shipping_carriers/lib/status-sync.js +8 -1
- package/dist/modules/shipping_carriers/lib/status-sync.js.map +2 -2
- package/dist/modules/staff/api/job-histories.js +11 -2
- package/dist/modules/staff/api/job-histories.js.map +2 -2
- package/dist/modules/staff/api/timesheets/time-entries/route.js +11 -4
- package/dist/modules/staff/api/timesheets/time-entries/route.js.map +2 -2
- package/dist/modules/staff/backend/staff/leave-requests/[id]/page.js +13 -8
- package/dist/modules/staff/backend/staff/leave-requests/[id]/page.js.map +2 -2
- package/dist/modules/staff/backend/staff/my-leave-requests/[id]/page.js +2 -1
- package/dist/modules/staff/backend/staff/my-leave-requests/[id]/page.js.map +2 -2
- package/dist/modules/staff/backend/staff/team-members/[id]/page.js +7 -4
- package/dist/modules/staff/backend/staff/team-members/[id]/page.js.map +2 -2
- package/dist/modules/staff/backend/staff/team-members/page.js +4 -2
- package/dist/modules/staff/backend/staff/team-members/page.js.map +2 -2
- package/dist/modules/staff/backend/staff/team-roles/[id]/edit/page.js +1 -0
- package/dist/modules/staff/backend/staff/team-roles/[id]/edit/page.js.map +2 -2
- package/dist/modules/staff/backend/staff/team-roles/page.js +4 -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 +5 -2
- package/dist/modules/staff/backend/staff/teams/[id]/edit/page.js.map +2 -2
- package/dist/modules/staff/backend/staff/teams/page.js +12 -3
- package/dist/modules/staff/backend/staff/teams/page.js.map +2 -2
- package/dist/modules/staff/backend/staff/timesheets/page.js +4 -1
- package/dist/modules/staff/backend/staff/timesheets/page.js.map +2 -2
- package/dist/modules/staff/backend/staff/timesheets/projects/[id]/page.js.map +2 -2
- package/dist/modules/staff/backend/staff/timesheets/projects/page.js +12 -3
- package/dist/modules/staff/backend/staff/timesheets/projects/page.js.map +2 -2
- package/dist/modules/staff/commands/job-histories.js +40 -3
- package/dist/modules/staff/commands/job-histories.js.map +2 -2
- package/dist/modules/staff/components/LeaveRequestForm.js +1 -0
- package/dist/modules/staff/components/LeaveRequestForm.js.map +2 -2
- package/dist/modules/staff/components/TeamForm.js +1 -0
- package/dist/modules/staff/components/TeamForm.js.map +2 -2
- package/dist/modules/staff/components/TeamMemberForm.js +1 -0
- package/dist/modules/staff/components/TeamMemberForm.js.map +2 -2
- package/dist/modules/staff/components/TeamRoleForm.js +1 -0
- package/dist/modules/staff/components/TeamRoleForm.js.map +2 -2
- package/dist/modules/staff/components/detail/JobHistorySection.js +20 -7
- package/dist/modules/staff/components/detail/JobHistorySection.js.map +2 -2
- package/dist/modules/staff/data/validators.js +7 -1
- package/dist/modules/staff/data/validators.js.map +2 -2
- package/dist/modules/staff/lib/leaveRequestHelpers.js +2 -1
- package/dist/modules/staff/lib/leaveRequestHelpers.js.map +2 -2
- package/dist/modules/translations/components/TranslationManager.js +12 -8
- package/dist/modules/translations/components/TranslationManager.js.map +2 -2
- package/dist/modules/workflows/api/definitions/[id]/route.js +106 -0
- package/dist/modules/workflows/api/definitions/[id]/route.js.map +2 -2
- package/dist/modules/workflows/backend/definitions/[id]/page.js +11 -3
- package/dist/modules/workflows/backend/definitions/[id]/page.js.map +2 -2
- package/dist/modules/workflows/backend/definitions/page.js +19 -8
- package/dist/modules/workflows/backend/definitions/page.js.map +2 -2
- package/dist/modules/workflows/backend/definitions/visual-editor/page.js +29 -16
- package/dist/modules/workflows/backend/definitions/visual-editor/page.js.map +2 -2
- package/dist/modules/workflows/components/NodeEditDialog.js +3 -1
- package/dist/modules/workflows/components/NodeEditDialog.js.map +2 -2
- package/dist/modules/workflows/components/WorkflowGraphImpl.js +4 -2
- package/dist/modules/workflows/components/WorkflowGraphImpl.js.map +2 -2
- package/dist/modules/workflows/components/formConfig.js +4 -1
- package/dist/modules/workflows/components/formConfig.js.map +2 -2
- package/dist/modules/workflows/components/nodes/ParallelForkNode.js +49 -0
- package/dist/modules/workflows/components/nodes/ParallelForkNode.js.map +7 -0
- package/dist/modules/workflows/components/nodes/ParallelJoinNode.js +49 -0
- package/dist/modules/workflows/components/nodes/ParallelJoinNode.js.map +7 -0
- package/dist/modules/workflows/components/nodes/index.js +4 -0
- package/dist/modules/workflows/components/nodes/index.js.map +2 -2
- package/dist/modules/workflows/data/entities.js +81 -0
- package/dist/modules/workflows/data/entities.js.map +2 -2
- package/dist/modules/workflows/data/validators.js +146 -1
- package/dist/modules/workflows/data/validators.js.map +2 -2
- package/dist/modules/workflows/di.js +12 -0
- package/dist/modules/workflows/di.js.map +2 -2
- package/dist/modules/workflows/events.js +7 -1
- package/dist/modules/workflows/events.js.map +2 -2
- package/dist/modules/workflows/lib/activity-executor.js +4 -2
- package/dist/modules/workflows/lib/activity-executor.js.map +2 -2
- package/dist/modules/workflows/lib/activity-queue-types.js.map +2 -2
- package/dist/modules/workflows/lib/event-logger.js +2 -0
- package/dist/modules/workflows/lib/event-logger.js.map +2 -2
- package/dist/modules/workflows/lib/execution-token.js +98 -0
- package/dist/modules/workflows/lib/execution-token.js.map +7 -0
- package/dist/modules/workflows/lib/node-type-icons.js +14 -5
- package/dist/modules/workflows/lib/node-type-icons.js.map +2 -2
- package/dist/modules/workflows/lib/parallel-handler.js +364 -0
- package/dist/modules/workflows/lib/parallel-handler.js.map +7 -0
- package/dist/modules/workflows/lib/signal-handler.js +63 -1
- package/dist/modules/workflows/lib/signal-handler.js.map +2 -2
- package/dist/modules/workflows/lib/step-handler.js +74 -30
- package/dist/modules/workflows/lib/step-handler.js.map +2 -2
- package/dist/modules/workflows/lib/task-handler.js +26 -0
- package/dist/modules/workflows/lib/task-handler.js.map +2 -2
- package/dist/modules/workflows/lib/timer-handler.js +26 -1
- package/dist/modules/workflows/lib/timer-handler.js.map +2 -2
- package/dist/modules/workflows/lib/transition-handler.js +33 -21
- package/dist/modules/workflows/lib/transition-handler.js.map +2 -2
- package/dist/modules/workflows/lib/workflow-executor.js +39 -1
- package/dist/modules/workflows/lib/workflow-executor.js.map +2 -2
- package/dist/modules/workflows/migrations/Migration20260602120000.js +24 -0
- package/dist/modules/workflows/migrations/Migration20260602120000.js.map +7 -0
- package/dist/modules/workflows/workers/workflow-activities.worker.js +8 -4
- package/dist/modules/workflows/workers/workflow-activities.worker.js.map +2 -2
- package/generated/entities/role/index.ts +1 -0
- package/generated/entities/step_instance/index.ts +1 -0
- package/generated/entities/user/index.ts +1 -0
- package/generated/entities/user_task/index.ts +1 -0
- package/generated/entities/workflow_branch_instance/index.ts +18 -0
- package/generated/entities/workflow_event/index.ts +1 -0
- package/generated/entities/workflow_instance/index.ts +1 -0
- package/generated/entities.ids.generated.ts +1 -0
- package/generated/entity-fields-registry.ts +26 -0
- package/jest.setup.ts +17 -0
- package/package.json +8 -7
- package/src/helpers/integration/optimisticLockUi.ts +172 -0
- package/src/helpers/integration/salesFixtures.ts +29 -0
- package/src/modules/api_keys/backend/api-keys/page.tsx +10 -5
- package/src/modules/attachments/components/AttachmentPartitionSettings.tsx +19 -9
- package/src/modules/auth/api/roles/acl/route.ts +37 -11
- package/src/modules/auth/api/roles/route.ts +2 -0
- package/src/modules/auth/api/sidebar/preferences/route.ts +73 -0
- package/src/modules/auth/api/users/acl/route.ts +46 -18
- package/src/modules/auth/api/users/route.ts +2 -0
- package/src/modules/auth/backend/roles/[id]/edit/page.tsx +29 -4
- package/src/modules/auth/backend/roles/page.tsx +9 -4
- package/src/modules/auth/backend/users/[id]/edit/page.tsx +37 -4
- package/src/modules/auth/backend/users/page.tsx +7 -2
- package/src/modules/auth/components/AclEditor.tsx +10 -1
- package/src/modules/auth/data/entities.ts +7 -1
- package/src/modules/auth/services/sidebarPreferencesService.ts +38 -4
- package/src/modules/business_rules/api/rules/route.ts +30 -0
- package/src/modules/business_rules/api/sets/route.ts +30 -0
- package/src/modules/business_rules/backend/rules/[id]/page.tsx +16 -4
- package/src/modules/business_rules/backend/rules/page.tsx +20 -11
- package/src/modules/business_rules/backend/sets/[id]/page.tsx +16 -4
- package/src/modules/business_rules/backend/sets/page.tsx +20 -11
- package/src/modules/catalog/api/categories/route.ts +3 -0
- package/src/modules/catalog/api/products/route.ts +4 -0
- package/src/modules/catalog/backend/catalog/categories/[id]/edit/page.tsx +5 -0
- package/src/modules/catalog/backend/catalog/products/[id]/page.tsx +112 -35
- package/src/modules/catalog/backend/catalog/products/[productId]/variants/[variantId]/page.tsx +56 -7
- package/src/modules/catalog/backend/catalog/products/optionSchemaClient.ts +2 -0
- package/src/modules/catalog/commands/variants.ts +32 -32
- package/src/modules/catalog/components/PriceKindSettings.tsx +20 -7
- package/src/modules/catalog/components/categories/CategoriesDataTable.tsx +1 -0
- package/src/modules/catalog/components/products/ProductMediaManager.tsx +2 -0
- package/src/modules/catalog/components/products/ProductsDataTable.tsx +8 -4
- package/src/modules/catalog/components/products/productForm.ts +3 -0
- package/src/modules/catalog/components/products/variantForm.ts +9 -0
- package/src/modules/communication_channels/backend/profile/communication-channels/page.tsx +5 -0
- package/src/modules/currencies/backend/currencies/[id]/page.tsx +13 -6
- package/src/modules/currencies/backend/currencies/page.tsx +18 -11
- package/src/modules/currencies/backend/exchange-rates/[id]/page.tsx +3 -0
- package/src/modules/currencies/backend/exchange-rates/page.tsx +10 -6
- package/src/modules/currencies/commands/currencies.ts +10 -5
- package/src/modules/currencies/components/CurrencyFetchingConfig.tsx +31 -21
- package/src/modules/customer_accounts/api/admin/roles/[id].ts +35 -5
- package/src/modules/customer_accounts/api/admin/roles.ts +2 -0
- package/src/modules/customer_accounts/api/admin/users/[id].ts +38 -5
- package/src/modules/customer_accounts/api/admin/users.ts +2 -0
- package/src/modules/customer_accounts/backend/customer_accounts/roles/[id]/page.tsx +34 -20
- package/src/modules/customer_accounts/backend/customer_accounts/roles/page.tsx +9 -4
- package/src/modules/customer_accounts/backend/customer_accounts/settings/domain/page.tsx +11 -4
- package/src/modules/customer_accounts/backend/customer_accounts/users/[id]/page.tsx +28 -17
- package/src/modules/customer_accounts/backend/customer_accounts/users/page.tsx +19 -11
- package/src/modules/customers/AGENTS.md +2 -2
- package/src/modules/customers/api/companies/route.ts +14 -1
- package/src/modules/customers/api/deals/route.ts +3 -0
- package/src/modules/customers/api/people/route.ts +12 -1
- package/src/modules/customers/api/todos/route.ts +1 -0
- package/src/modules/customers/backend/config/customers/deals/page.tsx +1 -0
- package/src/modules/customers/backend/config/customers/pipeline-stages/page.tsx +36 -21
- package/src/modules/customers/backend/customers/companies/[id]/page.tsx +52 -27
- package/src/modules/customers/backend/customers/companies/page.tsx +2 -0
- package/src/modules/customers/backend/customers/companies-v2/[id]/page.tsx +27 -5
- package/src/modules/customers/backend/customers/deals/[id]/hooks/useDealFormHandlers.ts +39 -7
- package/src/modules/customers/backend/customers/deals/[id]/page.tsx +1 -0
- package/src/modules/customers/backend/customers/deals/page.tsx +18 -6
- package/src/modules/customers/backend/customers/deals/pipeline/page.tsx +64 -39
- package/src/modules/customers/backend/customers/people/[id]/page.tsx +46 -26
- package/src/modules/customers/backend/customers/people/page.tsx +2 -0
- package/src/modules/customers/backend/customers/people-v2/[id]/page.tsx +84 -24
- package/src/modules/customers/commands/addresses.ts +16 -14
- package/src/modules/customers/commands/companies.ts +3 -1
- package/src/modules/customers/commands/interactions.ts +50 -4
- package/src/modules/customers/commands/people.ts +2 -1
- package/src/modules/customers/commands/personCompanyLinks.ts +8 -5
- package/src/modules/customers/commands/pipeline-stages.ts +16 -16
- package/src/modules/customers/components/AddressFormatSettings.tsx +1 -0
- package/src/modules/customers/components/DictionarySettings.tsx +18 -13
- package/src/modules/customers/components/DictionarySortSettings.tsx +4 -0
- package/src/modules/customers/components/PipelineSettings.tsx +42 -21
- package/src/modules/customers/components/detail/ActivityTimeline.tsx +3 -3
- package/src/modules/customers/components/detail/AddressesSection.tsx +4 -0
- package/src/modules/customers/components/detail/CompanyPeopleSection.tsx +2 -0
- package/src/modules/customers/components/detail/DealsSection.tsx +4 -0
- package/src/modules/customers/components/detail/EmailCardActions.tsx +5 -0
- package/src/modules/customers/components/detail/EntityTagsDialog.tsx +7 -0
- package/src/modules/customers/components/detail/ManageTagsDialog.tsx +4 -0
- package/src/modules/customers/components/detail/PersonCompaniesSection.tsx +4 -0
- package/src/modules/customers/components/detail/RoleAssignmentRow.tsx +2 -0
- package/src/modules/customers/components/detail/ScheduleActivityDialog.tsx +23 -7
- package/src/modules/customers/components/detail/hooks/useInteractionMutations.ts +25 -15
- package/src/modules/customers/components/detail/hooks/useInteractions.ts +76 -35
- package/src/modules/customers/components/detail/hooks/usePersonTasks.ts +30 -17
- package/src/modules/customers/components/detail/schedule/useScheduleFormState.ts +2 -0
- package/src/modules/customers/components/detail/types.ts +1 -0
- package/src/modules/customers/components/formConfig.tsx +2 -0
- package/src/modules/customers/data/guards.ts +67 -0
- package/src/modules/customers/di.ts +66 -0
- package/src/modules/customers/i18n/de.json +2 -0
- package/src/modules/customers/i18n/en.json +2 -0
- package/src/modules/customers/i18n/es.json +2 -0
- package/src/modules/customers/i18n/pl.json +2 -0
- package/src/modules/customers/lib/todoCompatibility.ts +14 -0
- package/src/modules/dashboards/components/WidgetVisibilityEditor.tsx +2 -0
- package/src/modules/data_sync/api/options.ts +7 -4
- package/src/modules/data_sync/api/schedules/route.ts +9 -1
- package/src/modules/data_sync/backend/data-sync/page.tsx +18 -5
- package/src/modules/data_sync/components/IntegrationScheduleTab.tsx +46 -19
- package/src/modules/data_sync/lib/sync-schedule-service.ts +11 -0
- package/src/modules/dictionaries/api/[dictionaryId]/entries/[entryId]/route.ts +8 -1
- package/src/modules/dictionaries/api/[dictionaryId]/route.ts +23 -0
- package/src/modules/dictionaries/components/DictionariesManager.tsx +32 -9
- package/src/modules/dictionaries/components/DictionaryEntriesEditor.tsx +30 -14
- package/src/modules/dictionaries/i18n/de.json +1 -0
- package/src/modules/dictionaries/i18n/en.json +1 -0
- package/src/modules/dictionaries/i18n/es.json +1 -0
- package/src/modules/dictionaries/i18n/pl.json +1 -0
- package/src/modules/directory/api/organizations/route.ts +3 -0
- package/src/modules/directory/backend/directory/organizations/[id]/edit/page.tsx +8 -0
- package/src/modules/directory/backend/directory/organizations/page.tsx +10 -5
- package/src/modules/directory/backend/directory/tenants/[id]/edit/page.tsx +16 -5
- package/src/modules/directory/backend/directory/tenants/page.tsx +8 -4
- package/src/modules/directory/commands/organizations.ts +7 -4
- package/src/modules/entities/api/records.ts +99 -0
- package/src/modules/entities/backend/entities/user/[entityId]/records/[recordId]/page.tsx +7 -0
- package/src/modules/entities/backend/entities/user/[entityId]/records/page.tsx +8 -4
- package/src/modules/entities/lib/helpers.ts +17 -0
- package/src/modules/feature_toggles/api/global/[id]/override/route.ts +1 -0
- package/src/modules/feature_toggles/api/overrides/route.ts +19 -0
- package/src/modules/feature_toggles/backend/feature-toggles/global/[id]/edit/page.tsx +19 -13
- package/src/modules/feature_toggles/components/FeatureToggleOverrideCard.tsx +22 -12
- package/src/modules/feature_toggles/components/FeatureTogglesTable.tsx +7 -2
- package/src/modules/feature_toggles/components/formConfig.tsx +2 -1
- package/src/modules/feature_toggles/components/overrideFormConfig.tsx +10 -1
- package/src/modules/feature_toggles/data/validators.ts +11 -3
- package/src/modules/inbox_ops/api/settings/route.ts +18 -0
- package/src/modules/inbox_ops/backend/inbox-ops/settings/page.tsx +15 -10
- package/src/modules/inbox_ops/components/proposals/EditActionDialog.tsx +9 -4
- package/src/modules/integrations/backend/integrations/bundle/[id]/page.tsx +20 -11
- package/src/modules/integrations/backend/integrations/page.tsx +13 -8
- package/src/modules/messages/commands/messages.ts +27 -15
- package/src/modules/perspectives/api/[tableId]/route.ts +11 -2
- package/src/modules/perspectives/services/perspectiveService.ts +13 -1
- package/src/modules/planner/backend/planner/availability-rulesets/[id]/page.tsx +16 -14
- package/src/modules/planner/backend/planner/availability-rulesets/page.tsx +6 -3
- package/src/modules/planner/components/AvailabilityRuleSetForm.tsx +3 -0
- package/src/modules/planner/components/AvailabilityRulesEditor.tsx +58 -15
- package/src/modules/planner/components/AvailabilitySchedule.tsx +22 -7
- package/src/modules/progress/api/jobs/[id]/route.ts +7 -0
- package/src/modules/query_index/lib/engine.ts +34 -0
- package/src/modules/resources/backend/resources/resource-types/[id]/edit/page.tsx +7 -1
- package/src/modules/resources/backend/resources/resource-types/page.tsx +6 -3
- package/src/modules/resources/backend/resources/resources/[id]/page.tsx +23 -3
- package/src/modules/resources/backend/resources/resources/page.tsx +15 -4
- package/src/modules/resources/components/ResourceCrudForm.tsx +3 -0
- package/src/modules/resources/components/ResourceTypeCrudForm.tsx +2 -0
- package/src/modules/sales/api/documents/factory.ts +13 -1
- package/src/modules/sales/backend/sales/channels/[channelId]/edit/page.tsx +6 -0
- package/src/modules/sales/backend/sales/channels/offers/page.tsx +10 -4
- package/src/modules/sales/backend/sales/channels/page.tsx +19 -4
- package/src/modules/sales/backend/sales/documents/[id]/page.tsx +73 -20
- package/src/modules/sales/backend/sales/documents/create/page.tsx +2 -0
- package/src/modules/sales/commands/documentAddresses.ts +226 -4
- package/src/modules/sales/commands/documents.ts +28 -0
- package/src/modules/sales/commands/returns.ts +12 -3
- package/src/modules/sales/commands/shared.ts +36 -0
- package/src/modules/sales/commands/shipments.ts +17 -1
- package/src/modules/sales/components/AdjustmentKindSettings.tsx +20 -11
- package/src/modules/sales/components/DocumentNumberSettings.tsx +1 -0
- package/src/modules/sales/components/OrderEditingSettings.tsx +1 -0
- package/src/modules/sales/components/PaymentMethodsSettings.tsx +12 -4
- package/src/modules/sales/components/ShippingMethodsSettings.tsx +12 -4
- package/src/modules/sales/components/StatusSettings.tsx +20 -11
- package/src/modules/sales/components/TaxRatesSettings.tsx +12 -5
- package/src/modules/sales/components/channels/ChannelOfferForm.tsx +67 -14
- package/src/modules/sales/components/channels/SalesChannelOffersPanel.tsx +7 -4
- package/src/modules/sales/components/documents/AddressesSection.tsx +35 -25
- package/src/modules/sales/components/documents/AdjustmentsSection.tsx +50 -25
- package/src/modules/sales/components/documents/ItemsSection.tsx +24 -13
- package/src/modules/sales/components/documents/LineItemDialog.tsx +26 -9
- package/src/modules/sales/components/documents/PaymentDialog.tsx +33 -14
- package/src/modules/sales/components/documents/PaymentsSection.tsx +22 -10
- package/src/modules/sales/components/documents/ReturnDialog.tsx +28 -17
- package/src/modules/sales/components/documents/ReturnsSection.tsx +4 -1
- package/src/modules/sales/components/documents/SalesDocumentsTable.tsx +11 -4
- package/src/modules/sales/components/documents/ShipmentDialog.tsx +23 -8
- package/src/modules/sales/components/documents/ShipmentsSection.tsx +20 -10
- package/src/modules/sales/components/documents/optimisticLock.ts +34 -0
- package/src/modules/sales/components/documents/shipmentTypes.ts +1 -0
- package/src/modules/sales/di.ts +35 -0
- package/src/modules/sales/i18n/de.json +3 -0
- package/src/modules/sales/i18n/en.json +3 -0
- package/src/modules/sales/i18n/es.json +3 -0
- package/src/modules/sales/i18n/pl.json +3 -0
- package/src/modules/shipping_carriers/api/cancel/route.ts +2 -2
- package/src/modules/shipping_carriers/lib/status-sync.ts +19 -0
- package/src/modules/staff/api/job-histories.ts +12 -2
- package/src/modules/staff/api/timesheets/time-entries/route.ts +16 -4
- package/src/modules/staff/backend/staff/leave-requests/[id]/page.tsx +12 -7
- package/src/modules/staff/backend/staff/my-leave-requests/[id]/page.tsx +2 -0
- package/src/modules/staff/backend/staff/team-members/[id]/page.tsx +16 -5
- package/src/modules/staff/backend/staff/team-members/page.tsx +6 -2
- package/src/modules/staff/backend/staff/team-roles/[id]/edit/page.tsx +8 -0
- package/src/modules/staff/backend/staff/team-roles/page.tsx +6 -2
- package/src/modules/staff/backend/staff/teams/[id]/edit/page.tsx +13 -3
- package/src/modules/staff/backend/staff/teams/page.tsx +9 -3
- package/src/modules/staff/backend/staff/timesheets/page.tsx +10 -1
- package/src/modules/staff/backend/staff/timesheets/projects/[id]/page.tsx +4 -0
- package/src/modules/staff/backend/staff/timesheets/projects/page.tsx +9 -3
- package/src/modules/staff/commands/job-histories.ts +42 -3
- package/src/modules/staff/components/LeaveRequestForm.tsx +2 -0
- package/src/modules/staff/components/TeamForm.tsx +2 -0
- package/src/modules/staff/components/TeamMemberForm.tsx +2 -0
- package/src/modules/staff/components/TeamRoleForm.tsx +2 -0
- package/src/modules/staff/components/detail/JobHistorySection.tsx +28 -6
- package/src/modules/staff/data/validators.ts +6 -0
- package/src/modules/staff/i18n/de.json +1 -0
- package/src/modules/staff/i18n/en.json +1 -0
- package/src/modules/staff/i18n/es.json +1 -0
- package/src/modules/staff/i18n/pl.json +1 -0
- package/src/modules/staff/lib/leaveRequestHelpers.ts +4 -0
- package/src/modules/translations/components/TranslationManager.tsx +13 -8
- package/src/modules/workflows/api/definitions/[id]/route.ts +112 -0
- package/src/modules/workflows/backend/definitions/[id]/page.tsx +20 -4
- package/src/modules/workflows/backend/definitions/page.tsx +20 -9
- package/src/modules/workflows/backend/definitions/visual-editor/page.tsx +29 -16
- package/src/modules/workflows/components/NodeEditDialog.tsx +2 -0
- package/src/modules/workflows/components/WorkflowGraphImpl.tsx +3 -1
- package/src/modules/workflows/components/formConfig.tsx +5 -0
- package/src/modules/workflows/components/nodes/ParallelForkNode.tsx +66 -0
- package/src/modules/workflows/components/nodes/ParallelJoinNode.tsx +66 -0
- package/src/modules/workflows/components/nodes/index.ts +6 -0
- package/src/modules/workflows/data/entities.ts +109 -0
- package/src/modules/workflows/data/validators.ts +223 -0
- package/src/modules/workflows/di.ts +20 -0
- package/src/modules/workflows/events.ts +7 -0
- package/src/modules/workflows/i18n/de.json +13 -0
- package/src/modules/workflows/i18n/en.json +13 -0
- package/src/modules/workflows/i18n/es.json +13 -0
- package/src/modules/workflows/i18n/pl.json +13 -0
- package/src/modules/workflows/lib/activity-executor.ts +8 -2
- package/src/modules/workflows/lib/activity-queue-types.ts +3 -0
- package/src/modules/workflows/lib/event-logger.ts +3 -0
- package/src/modules/workflows/lib/execution-token.ts +166 -0
- package/src/modules/workflows/lib/node-type-icons.ts +11 -2
- package/src/modules/workflows/lib/parallel-handler.ts +575 -0
- package/src/modules/workflows/lib/signal-handler.ts +72 -1
- package/src/modules/workflows/lib/step-handler.ts +94 -34
- package/src/modules/workflows/lib/task-handler.ts +32 -0
- package/src/modules/workflows/lib/timer-handler.ts +30 -1
- package/src/modules/workflows/lib/transition-handler.ts +56 -24
- package/src/modules/workflows/lib/workflow-executor.ts +53 -1
- package/src/modules/workflows/migrations/.snapshot-open-mercato.json +263 -0
- package/src/modules/workflows/migrations/Migration20260602120000.ts +25 -0
- package/src/modules/workflows/workers/workflow-activities.worker.ts +9 -4
|
@@ -7,12 +7,16 @@ import { User, Hash, Users, Building2 } from 'lucide-react'
|
|
|
7
7
|
import { Page, PageBody } from '@open-mercato/ui/backend/Page'
|
|
8
8
|
import { CrudForm } from '@open-mercato/ui/backend/CrudForm'
|
|
9
9
|
import { CollapsibleZoneLayout, type ZoneSectionDescriptor } from '@open-mercato/ui/backend/crud/CollapsibleZoneLayout'
|
|
10
|
+
import { useIsMobile } from '@open-mercato/ui/hooks/useIsMobile'
|
|
10
11
|
import { updateCrud, deleteCrud } from '@open-mercato/ui/backend/utils/crud'
|
|
11
12
|
import { apiCallOrThrow } from '@open-mercato/ui/backend/utils/apiCall'
|
|
12
13
|
import { readApiResultOrThrow } from '@open-mercato/ui/backend/utils/apiCall'
|
|
14
|
+
import { withScopedApiRequestHeaders } from '@open-mercato/ui/backend/utils/apiCall'
|
|
15
|
+
import { buildOptimisticLockHeader } from '@open-mercato/ui/backend/utils/optimisticLock'
|
|
13
16
|
import { createCrudFormError } from '@open-mercato/ui/backend/utils/serverErrors'
|
|
14
17
|
import { E } from '#generated/entities.ids.generated'
|
|
15
18
|
import { flash } from '@open-mercato/ui/backend/FlashMessages'
|
|
19
|
+
import { surfaceRecordConflict } from '@open-mercato/ui/backend/conflicts'
|
|
16
20
|
import { useT } from '@open-mercato/shared/lib/i18n/context'
|
|
17
21
|
import { useOrganizationScopeDetail } from '@open-mercato/shared/lib/frontend/useOrganizationScope'
|
|
18
22
|
import { Button } from '@open-mercato/ui/primitives/button'
|
|
@@ -53,6 +57,7 @@ export default function PersonDetailV2Page({ params }: { params?: { id?: string
|
|
|
53
57
|
const router = useRouter()
|
|
54
58
|
const searchParams = useSearchParams()
|
|
55
59
|
const { organizationId } = useOrganizationScopeDetail()
|
|
60
|
+
const isMobile = useIsMobile()
|
|
56
61
|
const { confirm, ConfirmDialogElement } = useConfirmDialog()
|
|
57
62
|
|
|
58
63
|
const detailTranslator = React.useMemo(() => createTranslatorWithFallback(t), [t])
|
|
@@ -62,6 +67,15 @@ export default function PersonDetailV2Page({ params }: { params?: { id?: string
|
|
|
62
67
|
const fields = React.useMemo(() => createPersonEditFields(t), [t])
|
|
63
68
|
|
|
64
69
|
const [data, setData] = React.useState<PersonOverview | null>(null)
|
|
70
|
+
// Mirror the latest `data` into a ref so save handlers always read the current
|
|
71
|
+
// optimistic-lock token (`person.updatedAt`) instead of the value captured in
|
|
72
|
+
// their `useCallback` closure. Without this, a header-field save issued after a
|
|
73
|
+
// prior in-page reload would send a stale token (or none), letting a concurrent
|
|
74
|
+
// two-tab overwrite slip through without the 409 + conflict bar (#2055, Alina A7).
|
|
75
|
+
const dataRef = React.useRef<PersonOverview | null>(null)
|
|
76
|
+
React.useEffect(() => {
|
|
77
|
+
dataRef.current = data
|
|
78
|
+
}, [data])
|
|
65
79
|
const [isLoading, setIsLoading] = React.useState(true)
|
|
66
80
|
const [error, setError] = React.useState<string | null>(null)
|
|
67
81
|
const [isNotFound, setIsNotFound] = React.useState(false)
|
|
@@ -124,7 +138,7 @@ export default function PersonDetailV2Page({ params }: { params?: { id?: string
|
|
|
124
138
|
|
|
125
139
|
// Data loading
|
|
126
140
|
const initialLoadDoneRef = React.useRef(false)
|
|
127
|
-
const loadData = React.useCallback(async () => {
|
|
141
|
+
const loadData = React.useCallback(async (lockTokenOverride?: string | null) => {
|
|
128
142
|
if (!id) {
|
|
129
143
|
setIsNotFound(true)
|
|
130
144
|
setIsLoading(false)
|
|
@@ -141,7 +155,15 @@ export default function PersonDetailV2Page({ params }: { params?: { id?: string
|
|
|
141
155
|
undefined,
|
|
142
156
|
{ errorMessage: t('customers.people.detail.error.load', 'Failed to load person.') },
|
|
143
157
|
)
|
|
144
|
-
|
|
158
|
+
// When the caller is the save handler, pin the optimistic-lock token to the
|
|
159
|
+
// value the write itself returned rather than the one this GET observed — a
|
|
160
|
+
// concurrent third-party bump between save and reload must stay stale so the
|
|
161
|
+
// next in-page save 409s (#2055, Alina A7). Applied in the same state update
|
|
162
|
+
// as the refresh to avoid a redundant second re-render.
|
|
163
|
+
const next = lockTokenOverride && payload?.person
|
|
164
|
+
? { ...payload, person: { ...payload.person, updatedAt: lockTokenOverride, updated_at: lockTokenOverride } }
|
|
165
|
+
: payload
|
|
166
|
+
setData(next as PersonOverview)
|
|
145
167
|
} catch (err) {
|
|
146
168
|
if ((err as { status?: number }).status === 404) {
|
|
147
169
|
setIsNotFound(true)
|
|
@@ -230,6 +252,7 @@ export default function PersonDetailV2Page({ params }: { params?: { id?: string
|
|
|
230
252
|
// moment instead of "today" (#1807 prefill).
|
|
231
253
|
const editPayload = {
|
|
232
254
|
id: activity.id,
|
|
255
|
+
updatedAt: typeof raw.updatedAt === 'string' ? raw.updatedAt as string : typeof raw.updated_at === 'string' ? raw.updated_at as string : null,
|
|
233
256
|
interactionType: typeof activity.interactionType === 'string' ? activity.interactionType : undefined,
|
|
234
257
|
title: typeof activity.title === 'string' ? activity.title : null,
|
|
235
258
|
body: typeof activity.body === 'string' ? activity.body : null,
|
|
@@ -329,9 +352,27 @@ export default function PersonDetailV2Page({ params }: { params?: { id?: string
|
|
|
329
352
|
throw err
|
|
330
353
|
}
|
|
331
354
|
|
|
332
|
-
|
|
355
|
+
// Attach the current optimistic-lock token directly on this write path so
|
|
356
|
+
// every header-field edit (displayName/status/…) carries `updatedAt`, not
|
|
357
|
+
// just the fields the embedded CrudForm intercepts. Read from `dataRef` so
|
|
358
|
+
// the token reflects the latest in-page reload rather than a stale closure
|
|
359
|
+
// capture, and let the 409 propagate to CrudForm's surfaceRecordConflict so
|
|
360
|
+
// the unified conflict bar renders (#2055, Alina A7).
|
|
361
|
+
const lockedUpdatedAt = dataRef.current?.person?.updatedAt
|
|
362
|
+
?? dataRef.current?.person?.updated_at
|
|
363
|
+
?? null
|
|
364
|
+
const updateResponse = await withScopedApiRequestHeaders(
|
|
365
|
+
buildOptimisticLockHeader(lockedUpdatedAt),
|
|
366
|
+
() => updateCrud<{ updatedAt?: string | null }>('customers/people', payload),
|
|
367
|
+
)
|
|
333
368
|
flash(t('customers.people.form.updateSuccess', 'Person updated.'), 'success')
|
|
334
|
-
|
|
369
|
+
// Refresh the view and pin the optimistic-lock token to the write's OWN
|
|
370
|
+
// authoritative `updatedAt` in a single reload (see loadData) so a
|
|
371
|
+
// concurrent third-party bump stays stale on the next save (#2055, Alina A7).
|
|
372
|
+
const savedUpdatedAt = typeof updateResponse.result?.updatedAt === 'string'
|
|
373
|
+
? updateResponse.result.updatedAt
|
|
374
|
+
: null
|
|
375
|
+
await loadData(savedUpdatedAt)
|
|
335
376
|
} finally {
|
|
336
377
|
setIsSaving(false)
|
|
337
378
|
}
|
|
@@ -351,10 +392,28 @@ export default function PersonDetailV2Page({ params }: { params?: { id?: string
|
|
|
351
392
|
variant: 'destructive',
|
|
352
393
|
})
|
|
353
394
|
if (!approved) return
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
395
|
+
try {
|
|
396
|
+
await runMutationWithContext(
|
|
397
|
+
() => withScopedApiRequestHeaders(
|
|
398
|
+
buildOptimisticLockHeader(data?.person?.updatedAt ?? data?.person?.updated_at ?? null),
|
|
399
|
+
() => deleteCrud('customers/people', { id: personId }),
|
|
400
|
+
),
|
|
401
|
+
{ id: personId, operation: 'deletePerson' },
|
|
402
|
+
)
|
|
403
|
+
} catch (err) {
|
|
404
|
+
// The guarded mutation routes a 409 to the unified conflict bar; surface
|
|
405
|
+
// any other server error (e.g. a linked-records delete guard) as a flash
|
|
406
|
+
// instead of letting it crash the page.
|
|
407
|
+
if (!surfaceRecordConflict(err, t)) {
|
|
408
|
+
flash(
|
|
409
|
+
err instanceof Error && err.message.trim().length > 0
|
|
410
|
+
? err.message
|
|
411
|
+
: t('customers.people.detail.deleteError', 'Failed to delete person.'),
|
|
412
|
+
'error',
|
|
413
|
+
)
|
|
414
|
+
}
|
|
415
|
+
return
|
|
416
|
+
}
|
|
358
417
|
flash(t('customers.people.list.deleteSuccess', 'Person deleted.'), 'success')
|
|
359
418
|
router.push('/backend/customers/people')
|
|
360
419
|
},
|
|
@@ -464,6 +523,7 @@ export default function PersonDetailV2Page({ params }: { params?: { id?: string
|
|
|
464
523
|
fields={fields}
|
|
465
524
|
groups={groups}
|
|
466
525
|
initialValues={initialValues}
|
|
526
|
+
optimisticLockUpdatedAt={data.person.updatedAt ?? data.person.updated_at ?? null}
|
|
467
527
|
onSubmit={handleFormSubmit}
|
|
468
528
|
onDelete={handleFormDelete}
|
|
469
529
|
hideFooterActions
|
|
@@ -602,22 +662,22 @@ export default function PersonDetailV2Page({ params }: { params?: { id?: string
|
|
|
602
662
|
</div>
|
|
603
663
|
</PersonDetailTabs>
|
|
604
664
|
)
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
665
|
+
// Render only the layout variant that matches the viewport. Mounting
|
|
666
|
+
// both the mobile and desktop layouts at once would create two
|
|
667
|
+
// CrudForm instances bound to one `formWrapperRef`, so header Save
|
|
668
|
+
// could submit the hidden instance's stale values and silently
|
|
669
|
+
// discard the edit (#2453). `useIsMobile` is SSR-safe.
|
|
670
|
+
return isMobile ? (
|
|
671
|
+
<MobilePersonDetail zone1={zone1Content} zone2={zone2Content} />
|
|
672
|
+
) : (
|
|
673
|
+
<CollapsibleZoneLayout
|
|
674
|
+
pageType="person-v2"
|
|
675
|
+
entityName={personName}
|
|
676
|
+
isDirty={isDirty}
|
|
677
|
+
sections={zoneSections}
|
|
678
|
+
zone1={zone1Content}
|
|
679
|
+
zone2={zone2Content}
|
|
680
|
+
/>
|
|
621
681
|
)
|
|
622
682
|
})()}
|
|
623
683
|
|
|
@@ -213,22 +213,24 @@ const updateAddressCommand: CommandHandler<AddressUpdateInput, { addressId: stri
|
|
|
213
213
|
ensureSameScope(entity, address.organizationId, address.tenantId)
|
|
214
214
|
address.entity = entity
|
|
215
215
|
}
|
|
216
|
-
if (parsed.name !== undefined) address.name = parsed.name ?? null
|
|
217
|
-
if (parsed.purpose !== undefined) address.purpose = parsed.purpose ?? null
|
|
218
|
-
if (parsed.companyName !== undefined) address.companyName = parsed.companyName ?? null
|
|
219
|
-
if (parsed.addressLine1 !== undefined) address.addressLine1 = parsed.addressLine1
|
|
220
|
-
if (parsed.addressLine2 !== undefined) address.addressLine2 = parsed.addressLine2 ?? null
|
|
221
|
-
if (parsed.buildingNumber !== undefined) address.buildingNumber = parsed.buildingNumber ?? null
|
|
222
|
-
if (parsed.flatNumber !== undefined) address.flatNumber = parsed.flatNumber ?? null
|
|
223
|
-
if (parsed.city !== undefined) address.city = parsed.city ?? null
|
|
224
|
-
if (parsed.region !== undefined) address.region = parsed.region ?? null
|
|
225
|
-
if (parsed.postalCode !== undefined) address.postalCode = parsed.postalCode ?? null
|
|
226
|
-
if (parsed.country !== undefined) address.country = parsed.country ?? null
|
|
227
|
-
if (parsed.latitude !== undefined) address.latitude = parsed.latitude ?? null
|
|
228
|
-
if (parsed.longitude !== undefined) address.longitude = parsed.longitude ?? null
|
|
229
|
-
if (parsed.isPrimary !== undefined) address.isPrimary = parsed.isPrimary
|
|
230
216
|
|
|
231
217
|
await withAtomicFlush(em, [
|
|
218
|
+
() => {
|
|
219
|
+
if (parsed.name !== undefined) address.name = parsed.name ?? null
|
|
220
|
+
if (parsed.purpose !== undefined) address.purpose = parsed.purpose ?? null
|
|
221
|
+
if (parsed.companyName !== undefined) address.companyName = parsed.companyName ?? null
|
|
222
|
+
if (parsed.addressLine1 !== undefined) address.addressLine1 = parsed.addressLine1
|
|
223
|
+
if (parsed.addressLine2 !== undefined) address.addressLine2 = parsed.addressLine2 ?? null
|
|
224
|
+
if (parsed.buildingNumber !== undefined) address.buildingNumber = parsed.buildingNumber ?? null
|
|
225
|
+
if (parsed.flatNumber !== undefined) address.flatNumber = parsed.flatNumber ?? null
|
|
226
|
+
if (parsed.city !== undefined) address.city = parsed.city ?? null
|
|
227
|
+
if (parsed.region !== undefined) address.region = parsed.region ?? null
|
|
228
|
+
if (parsed.postalCode !== undefined) address.postalCode = parsed.postalCode ?? null
|
|
229
|
+
if (parsed.country !== undefined) address.country = parsed.country ?? null
|
|
230
|
+
if (parsed.latitude !== undefined) address.latitude = parsed.latitude ?? null
|
|
231
|
+
if (parsed.longitude !== undefined) address.longitude = parsed.longitude ?? null
|
|
232
|
+
if (parsed.isPrimary !== undefined) address.isPrimary = parsed.isPrimary
|
|
233
|
+
},
|
|
232
234
|
async () => {
|
|
233
235
|
if (address.isPrimary) {
|
|
234
236
|
await enforcePrimaryAddress(em, typeof address.entity === 'string' ? address.entity : address.entity.id, address.id)
|
|
@@ -677,7 +677,9 @@ const updateCompanyCommand: CommandHandler<CompanyUpdateInput, { entityId: strin
|
|
|
677
677
|
})
|
|
678
678
|
await emitQueryIndexUpsertEvents(ctx, [companyEntityIndexEntry(record)])
|
|
679
679
|
|
|
680
|
-
|
|
680
|
+
// Expose the freshly-bumped updatedAt so the CRUD update response can hand it to
|
|
681
|
+
// inline-edit detail pages for sequential-save lock-token refresh (#2055).
|
|
682
|
+
return { entityId: record.id, updatedAt: record.updatedAt }
|
|
681
683
|
},
|
|
682
684
|
captureAfter: async (_input, result, ctx) => {
|
|
683
685
|
const em = (ctx.container.resolve('em') as EntityManager).fork()
|
|
@@ -38,6 +38,7 @@ import {
|
|
|
38
38
|
buildCustomFieldResetMap,
|
|
39
39
|
} from '@open-mercato/shared/lib/commands/customFieldSnapshots'
|
|
40
40
|
import { CrudHttpError } from '@open-mercato/shared/lib/crud/errors'
|
|
41
|
+
import { enforceRecordGoneIsConflict, enforceCommandOptimisticLock } from '@open-mercato/shared/lib/crud/optimistic-lock-command'
|
|
41
42
|
import { findOneWithDecryption } from '@open-mercato/shared/lib/encryption/find'
|
|
42
43
|
import type { CrudIndexerConfig, CrudEventsConfig } from '@open-mercato/shared/lib/crud/types'
|
|
43
44
|
import { recomputeNextInteraction } from '../lib/interactionProjection'
|
|
@@ -451,10 +452,25 @@ const updateInteractionCommand: CommandHandler<InteractionUpdateInput, { interac
|
|
|
451
452
|
const em = (ctx.container.resolve('em') as EntityManager).fork()
|
|
452
453
|
const { interaction, entityId, nextInteractionId } = await runInTransaction(em, async (trx) => {
|
|
453
454
|
const interaction = await findOneWithDecryption(trx, CustomerInteraction, { id: parsed.id, deletedAt: null })
|
|
454
|
-
if (!interaction)
|
|
455
|
+
if (!interaction) {
|
|
456
|
+
enforceRecordGoneIsConflict({ resourceKind: 'customers.interaction', resourceId: parsed.id, request: ctx.request ?? null })
|
|
457
|
+
throw new CrudHttpError(404, { error: 'Interaction not found' })
|
|
458
|
+
}
|
|
455
459
|
ensureTenantScope(ctx, interaction.tenantId)
|
|
456
460
|
ensureOrganizationScope(ctx, interaction.organizationId)
|
|
457
461
|
|
|
462
|
+
// Concurrent-edit guard for command-driven callers (e.g. the legacy
|
|
463
|
+
// /api/customers/todos route, which bypasses the makeCrudRoute lock guard):
|
|
464
|
+
// when the client opted into optimistic locking, a stale edit fails with the
|
|
465
|
+
// unified 409 instead of silently overwriting (#2055). Strictly additive —
|
|
466
|
+
// no-op when no expected-version header is present.
|
|
467
|
+
enforceCommandOptimisticLock({
|
|
468
|
+
resourceKind: 'customers.interaction',
|
|
469
|
+
resourceId: interaction.id,
|
|
470
|
+
current: interaction.updatedAt,
|
|
471
|
+
request: ctx.request ?? null,
|
|
472
|
+
})
|
|
473
|
+
|
|
458
474
|
// Email visibility is an access-controlled field: only the interaction's
|
|
459
475
|
// author may change a
|
|
460
476
|
// private email's visibility (mirrors the dedicated PATCH .../visibility
|
|
@@ -709,10 +725,20 @@ const completeInteractionCommand: CommandHandler<InteractionCompleteInput, { int
|
|
|
709
725
|
const em = (ctx.container.resolve('em') as EntityManager).fork()
|
|
710
726
|
const { interaction, entityId, nextInteractionId } = await runInTransaction(em, async (trx) => {
|
|
711
727
|
const interaction = await findOneWithDecryption(trx, CustomerInteraction, { id: parsed.id, deletedAt: null })
|
|
712
|
-
if (!interaction)
|
|
728
|
+
if (!interaction) {
|
|
729
|
+
enforceRecordGoneIsConflict({ resourceKind: 'customers.interaction', resourceId: parsed.id, request: ctx.request ?? null })
|
|
730
|
+
throw new CrudHttpError(404, { error: 'Interaction not found' })
|
|
731
|
+
}
|
|
713
732
|
ensureTenantScope(ctx, interaction.tenantId)
|
|
714
733
|
ensureOrganizationScope(ctx, interaction.organizationId)
|
|
715
734
|
|
|
735
|
+
enforceCommandOptimisticLock({
|
|
736
|
+
resourceKind: 'customers.interaction',
|
|
737
|
+
resourceId: interaction.id,
|
|
738
|
+
current: interaction.updatedAt,
|
|
739
|
+
request: ctx.request ?? null,
|
|
740
|
+
})
|
|
741
|
+
|
|
716
742
|
interaction.status = 'done'
|
|
717
743
|
interaction.occurredAt = parsed.occurredAt ?? new Date()
|
|
718
744
|
await trx.flush()
|
|
@@ -839,10 +865,20 @@ const cancelInteractionCommand: CommandHandler<InteractionCancelInput, { interac
|
|
|
839
865
|
const em = (ctx.container.resolve('em') as EntityManager).fork()
|
|
840
866
|
const { interaction, entityId, nextInteractionId } = await runInTransaction(em, async (trx) => {
|
|
841
867
|
const interaction = await findOneWithDecryption(trx, CustomerInteraction, { id: parsed.id, deletedAt: null })
|
|
842
|
-
if (!interaction)
|
|
868
|
+
if (!interaction) {
|
|
869
|
+
enforceRecordGoneIsConflict({ resourceKind: 'customers.interaction', resourceId: parsed.id, request: ctx.request ?? null })
|
|
870
|
+
throw new CrudHttpError(404, { error: 'Interaction not found' })
|
|
871
|
+
}
|
|
843
872
|
ensureTenantScope(ctx, interaction.tenantId)
|
|
844
873
|
ensureOrganizationScope(ctx, interaction.organizationId)
|
|
845
874
|
|
|
875
|
+
enforceCommandOptimisticLock({
|
|
876
|
+
resourceKind: 'customers.interaction',
|
|
877
|
+
resourceId: interaction.id,
|
|
878
|
+
current: interaction.updatedAt,
|
|
879
|
+
request: ctx.request ?? null,
|
|
880
|
+
})
|
|
881
|
+
|
|
846
882
|
interaction.status = 'canceled'
|
|
847
883
|
await trx.flush()
|
|
848
884
|
|
|
@@ -967,10 +1003,20 @@ const deleteInteractionCommand: CommandHandler<{ body?: Record<string, unknown>;
|
|
|
967
1003
|
const em = (ctx.container.resolve('em') as EntityManager).fork()
|
|
968
1004
|
const { interaction, entityId, nextInteractionId } = await runInTransaction(em, async (trx) => {
|
|
969
1005
|
const interaction = await findOneWithDecryption(trx, CustomerInteraction, { id, deletedAt: null })
|
|
970
|
-
if (!interaction)
|
|
1006
|
+
if (!interaction) {
|
|
1007
|
+
enforceRecordGoneIsConflict({ resourceKind: 'customers.interaction', resourceId: id, request: ctx.request ?? null })
|
|
1008
|
+
throw new CrudHttpError(404, { error: 'Interaction not found' })
|
|
1009
|
+
}
|
|
971
1010
|
ensureTenantScope(ctx, interaction.tenantId)
|
|
972
1011
|
ensureOrganizationScope(ctx, interaction.organizationId)
|
|
973
1012
|
|
|
1013
|
+
enforceCommandOptimisticLock({
|
|
1014
|
+
resourceKind: 'customers.interaction',
|
|
1015
|
+
resourceId: interaction.id,
|
|
1016
|
+
current: interaction.updatedAt,
|
|
1017
|
+
request: ctx.request ?? null,
|
|
1018
|
+
})
|
|
1019
|
+
|
|
974
1020
|
const entityId = typeof interaction.entity === 'string' ? interaction.entity : interaction.entity.id
|
|
975
1021
|
interaction.deletedAt = new Date()
|
|
976
1022
|
await trx.flush()
|
|
@@ -866,7 +866,8 @@ const updatePersonCommand: CommandHandler<PersonUpdateInput, { entityId: string
|
|
|
866
866
|
})
|
|
867
867
|
await emitQueryIndexUpsertEvents(ctx, [personEntityIndexEntry(record)])
|
|
868
868
|
|
|
869
|
-
|
|
869
|
+
// Expose the freshly-bumped updatedAt for inline-edit sequential-save lock refresh (#2055).
|
|
870
|
+
return { entityId: record.id, updatedAt: record.updatedAt }
|
|
870
871
|
},
|
|
871
872
|
captureAfter: async (_input, result, ctx) => {
|
|
872
873
|
const em = (ctx.container.resolve('em') as EntityManager).fork()
|
|
@@ -382,6 +382,7 @@ const updatePersonCompanyLinkCommand: CommandHandler<PersonCompanyLinkUpdateInpu
|
|
|
382
382
|
const profile = await requirePersonProfile(em, person)
|
|
383
383
|
const linkedCompany = await requireCompanyEntity(em, companyId, parsed.tenantId, parsed.organizationId)
|
|
384
384
|
|
|
385
|
+
const linkWasPrimary = link.isPrimary
|
|
385
386
|
await withAtomicFlush(em, [
|
|
386
387
|
async () => {
|
|
387
388
|
if (parsed.isPrimary) {
|
|
@@ -389,16 +390,18 @@ const updatePersonCompanyLinkCommand: CommandHandler<PersonCompanyLinkUpdateInpu
|
|
|
389
390
|
link.isPrimary = true
|
|
390
391
|
profile.company = linkedCompany
|
|
391
392
|
} else if (!parsed.isPrimary) {
|
|
392
|
-
const linkWasPrimary = link.isPrimary
|
|
393
393
|
link.isPrimary = false
|
|
394
|
-
if (linkWasPrimary) {
|
|
395
|
-
const remainingLinks = (await loadPersonCompanyLinks(em, person)).filter((entry) => entry.id !== link.id)
|
|
396
|
-
await promoteFallbackPrimaryLink(em, person, profile, remainingLinks, companyId)
|
|
397
|
-
} else if (profile.company && typeof profile.company !== 'string' && profile.company.id === companyId) {
|
|
394
|
+
if (!linkWasPrimary && profile.company && typeof profile.company !== 'string' && profile.company.id === companyId) {
|
|
398
395
|
profile.company = null
|
|
399
396
|
}
|
|
400
397
|
}
|
|
401
398
|
},
|
|
399
|
+
async () => {
|
|
400
|
+
if (!parsed.isPrimary && linkWasPrimary) {
|
|
401
|
+
const remainingLinks = (await loadPersonCompanyLinks(em, person)).filter((entry) => entry.id !== link.id)
|
|
402
|
+
await promoteFallbackPrimaryLink(em, person, profile, remainingLinks, companyId)
|
|
403
|
+
}
|
|
404
|
+
},
|
|
402
405
|
], { transaction: true })
|
|
403
406
|
|
|
404
407
|
const dataEngine = ctx.container.resolve('dataEngine') as DataEngine
|
|
@@ -49,18 +49,6 @@ const createPipelineStageCommand: CommandHandler<PipelineStageCreateInput, { sta
|
|
|
49
49
|
? existingStages.length
|
|
50
50
|
: Math.max(0, Math.min(requestedOrder, existingStages.length))
|
|
51
51
|
|
|
52
|
-
// Shift the order of every stage at or after the insert position. Skipping
|
|
53
|
-
// this step would either duplicate `order` values (silently corrupting kanban
|
|
54
|
-
// ordering) or push the new stage to the wrong spot when re-sorting.
|
|
55
|
-
if (requestedOrder !== undefined) {
|
|
56
|
-
for (const stage of existingStages) {
|
|
57
|
-
if (stage.order >= insertOrder) {
|
|
58
|
-
stage.order += 1
|
|
59
|
-
stage.updatedAt = new Date()
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
|
|
64
52
|
const stage = em.create(CustomerPipelineStage, {
|
|
65
53
|
organizationId: parsed.organizationId,
|
|
66
54
|
tenantId: parsed.tenantId,
|
|
@@ -73,6 +61,17 @@ const createPipelineStageCommand: CommandHandler<PipelineStageCreateInput, { sta
|
|
|
73
61
|
|
|
74
62
|
await withAtomicFlush(em, [
|
|
75
63
|
() => {
|
|
64
|
+
// Shift the order of every stage at or after the insert position. Skipping
|
|
65
|
+
// this step would either duplicate `order` values (silently corrupting kanban
|
|
66
|
+
// ordering) or push the new stage to the wrong spot when re-sorting.
|
|
67
|
+
if (requestedOrder !== undefined) {
|
|
68
|
+
for (const existing of existingStages) {
|
|
69
|
+
if (existing.order >= insertOrder) {
|
|
70
|
+
existing.order += 1
|
|
71
|
+
existing.updatedAt = new Date()
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
76
75
|
em.persist(stage)
|
|
77
76
|
},
|
|
78
77
|
async () => {
|
|
@@ -112,11 +111,12 @@ const updatePipelineStageCommand: CommandHandler<PipelineStageUpdateInput, void>
|
|
|
112
111
|
ensureTenantScope(ctx, stage.tenantId)
|
|
113
112
|
ensureOrganizationScope(ctx, stage.organizationId)
|
|
114
113
|
|
|
115
|
-
if (parsed.label !== undefined) stage.label = parsed.label
|
|
116
|
-
if (parsed.order !== undefined) stage.order = parsed.order
|
|
117
|
-
stage.updatedAt = new Date()
|
|
118
|
-
|
|
119
114
|
await withAtomicFlush(em, [
|
|
115
|
+
() => {
|
|
116
|
+
if (parsed.label !== undefined) stage.label = parsed.label
|
|
117
|
+
if (parsed.order !== undefined) stage.order = parsed.order
|
|
118
|
+
stage.updatedAt = new Date()
|
|
119
|
+
},
|
|
120
120
|
async () => {
|
|
121
121
|
if (parsed.label !== undefined || parsed.color !== undefined || parsed.icon !== undefined) {
|
|
122
122
|
await ensureDictionaryEntry(em, {
|
|
@@ -87,6 +87,7 @@ export function AddressFormatSettings() {
|
|
|
87
87
|
setPending(next)
|
|
88
88
|
setError(null)
|
|
89
89
|
try {
|
|
90
|
+
// optimistic-lock-exempt: single-row tenant address-format preference toggle — no per-record version / concurrent record edit
|
|
90
91
|
const call = await apiCall<Record<string, unknown>>(
|
|
91
92
|
'/api/customers/settings/address-format',
|
|
92
93
|
{
|
|
@@ -8,7 +8,8 @@ import {
|
|
|
8
8
|
DialogTitle,
|
|
9
9
|
} from '@open-mercato/ui/primitives/dialog'
|
|
10
10
|
import { flash } from '@open-mercato/ui/backend/FlashMessages'
|
|
11
|
-
import { apiCallOrThrow, readApiResultOrThrow } from '@open-mercato/ui/backend/utils/apiCall'
|
|
11
|
+
import { apiCallOrThrow, readApiResultOrThrow, withScopedApiRequestHeaders } from '@open-mercato/ui/backend/utils/apiCall'
|
|
12
|
+
import { buildOptimisticLockHeader } from '@open-mercato/ui/backend/utils/optimisticLock'
|
|
12
13
|
import { useOrganizationScopeVersion } from '@open-mercato/shared/lib/frontend/useOrganizationScope'
|
|
13
14
|
import { useT } from '@open-mercato/shared/lib/i18n/context'
|
|
14
15
|
import { useConfirmDialog } from '@open-mercato/ui/backend/confirm-dialog'
|
|
@@ -220,10 +221,12 @@ function CustomerDictionarySection({ kind, title, description }: CustomerDiction
|
|
|
220
221
|
})
|
|
221
222
|
if (!confirmed) return
|
|
222
223
|
try {
|
|
223
|
-
await
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
224
|
+
await withScopedApiRequestHeaders(buildOptimisticLockHeader(entry.updatedAt), () =>
|
|
225
|
+
apiCallOrThrow(
|
|
226
|
+
`/api/customers/dictionaries/${kind}/${encodeURIComponent(entry.id)}`,
|
|
227
|
+
{ method: 'DELETE' },
|
|
228
|
+
{ errorMessage: errorDelete },
|
|
229
|
+
),
|
|
227
230
|
)
|
|
228
231
|
flash(successDelete, 'success')
|
|
229
232
|
await loadEntries()
|
|
@@ -281,14 +284,16 @@ function CustomerDictionarySection({ kind, title, description }: CustomerDiction
|
|
|
281
284
|
closeDialog()
|
|
282
285
|
return
|
|
283
286
|
}
|
|
284
|
-
await
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
287
|
+
await withScopedApiRequestHeaders(buildOptimisticLockHeader(target.updatedAt), () =>
|
|
288
|
+
apiCallOrThrow(
|
|
289
|
+
`/api/customers/dictionaries/${kind}/${encodeURIComponent(target.id)}`,
|
|
290
|
+
{
|
|
291
|
+
method: 'PATCH',
|
|
292
|
+
headers: { 'content-type': 'application/json' },
|
|
293
|
+
body: JSON.stringify(body),
|
|
294
|
+
},
|
|
295
|
+
{ errorMessage: errorSave },
|
|
296
|
+
),
|
|
292
297
|
)
|
|
293
298
|
flash(successSave, 'success')
|
|
294
299
|
}
|
|
@@ -170,6 +170,10 @@ export function DictionarySortSettings() {
|
|
|
170
170
|
setError(null)
|
|
171
171
|
try {
|
|
172
172
|
await runMutation({
|
|
173
|
+
// optimistic-lock-exempt: tenant-scoped settings blob (dictionary sort
|
|
174
|
+
// modes), not a versioned per-record entity — there is no `updatedAt`
|
|
175
|
+
// round-trip to lock against, and concurrent writes converge on the
|
|
176
|
+
// last-selected preference. Mirrors other singleton settings PATCHes.
|
|
173
177
|
operation: async () => {
|
|
174
178
|
await apiCallOrThrow(
|
|
175
179
|
'/api/customers/settings/dictionary-sort-modes',
|
|
@@ -13,7 +13,8 @@ import {
|
|
|
13
13
|
DialogTitle,
|
|
14
14
|
} from '@open-mercato/ui/primitives/dialog'
|
|
15
15
|
import { flash } from '@open-mercato/ui/backend/FlashMessages'
|
|
16
|
-
import { apiCall, readApiResultOrThrow } from '@open-mercato/ui/backend/utils/apiCall'
|
|
16
|
+
import { apiCall, readApiResultOrThrow, withScopedApiRequestHeaders } from '@open-mercato/ui/backend/utils/apiCall'
|
|
17
|
+
import { buildOptimisticLockHeader } from '@open-mercato/ui/backend/utils/optimisticLock'
|
|
17
18
|
import { raiseCrudError } from '@open-mercato/ui/backend/utils/serverErrors'
|
|
18
19
|
import { useOrganizationScopeVersion } from '@open-mercato/shared/lib/frontend/useOrganizationScope'
|
|
19
20
|
import { useT } from '@open-mercato/shared/lib/i18n/context'
|
|
@@ -40,6 +41,7 @@ type Pipeline = {
|
|
|
40
41
|
isDefault: boolean
|
|
41
42
|
organizationId: string
|
|
42
43
|
tenantId: string
|
|
44
|
+
updatedAt?: string | null
|
|
43
45
|
}
|
|
44
46
|
|
|
45
47
|
type PipelineStage = {
|
|
@@ -49,6 +51,7 @@ type PipelineStage = {
|
|
|
49
51
|
order: number
|
|
50
52
|
color: string | null
|
|
51
53
|
icon: string | null
|
|
54
|
+
updatedAt?: string | null
|
|
52
55
|
}
|
|
53
56
|
|
|
54
57
|
type PipelineDialogState =
|
|
@@ -66,6 +69,7 @@ function normalizePipeline(raw: Record<string, unknown>): Pipeline {
|
|
|
66
69
|
isDefault: raw.isDefault === true || raw.is_default === true,
|
|
67
70
|
organizationId: typeof raw.organizationId === 'string' ? raw.organizationId : (typeof raw.organization_id === 'string' ? raw.organization_id : ''),
|
|
68
71
|
tenantId: typeof raw.tenantId === 'string' ? raw.tenantId : (typeof raw.tenant_id === 'string' ? raw.tenant_id : ''),
|
|
72
|
+
updatedAt: typeof raw.updatedAt === 'string' ? raw.updatedAt : (typeof raw.updated_at === 'string' ? raw.updated_at : null),
|
|
69
73
|
}
|
|
70
74
|
}
|
|
71
75
|
|
|
@@ -77,6 +81,7 @@ function normalizeStage(raw: Record<string, unknown>): PipelineStage {
|
|
|
77
81
|
order: typeof raw.order === 'number' ? raw.order : 0,
|
|
78
82
|
color: typeof raw.color === 'string' && raw.color.trim().length ? raw.color.trim() : null,
|
|
79
83
|
icon: typeof raw.icon === 'string' && raw.icon.trim().length ? raw.icon.trim() : null,
|
|
84
|
+
updatedAt: typeof raw.updatedAt === 'string' ? raw.updatedAt : (typeof raw.updated_at === 'string' ? raw.updated_at : null),
|
|
80
85
|
}
|
|
81
86
|
}
|
|
82
87
|
|
|
@@ -171,11 +176,15 @@ export default function PipelineSettings(): React.ReactElement {
|
|
|
171
176
|
}
|
|
172
177
|
flash(t('customers.pipelines.flash.created', 'Pipeline created'), 'success')
|
|
173
178
|
} else if (pipelineDialog?.mode === 'edit') {
|
|
174
|
-
const res = await
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
+
const res = await withScopedApiRequestHeaders(
|
|
180
|
+
buildOptimisticLockHeader(pipelineDialog.entry.updatedAt),
|
|
181
|
+
() =>
|
|
182
|
+
apiCall('/api/customers/pipelines', {
|
|
183
|
+
method: 'PUT',
|
|
184
|
+
headers: { 'content-type': 'application/json' },
|
|
185
|
+
body: JSON.stringify({ id: pipelineDialog.entry.id, name: pipelineForm.name.trim(), isDefault: pipelineForm.isDefault }),
|
|
186
|
+
}),
|
|
187
|
+
)
|
|
179
188
|
if (!res.ok) {
|
|
180
189
|
await raiseCrudError(res.response, t('customers.pipelines.errors.updateFailed', 'Failed to update pipeline'))
|
|
181
190
|
return
|
|
@@ -197,11 +206,15 @@ export default function PipelineSettings(): React.ReactElement {
|
|
|
197
206
|
variant: 'destructive',
|
|
198
207
|
})
|
|
199
208
|
if (!confirmed) return
|
|
200
|
-
const res = await
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
209
|
+
const res = await withScopedApiRequestHeaders(
|
|
210
|
+
buildOptimisticLockHeader(pipeline.updatedAt),
|
|
211
|
+
() =>
|
|
212
|
+
apiCall('/api/customers/pipelines', {
|
|
213
|
+
method: 'DELETE',
|
|
214
|
+
headers: { 'content-type': 'application/json' },
|
|
215
|
+
body: JSON.stringify({ id: pipeline.id }),
|
|
216
|
+
}),
|
|
217
|
+
)
|
|
205
218
|
if (!res.ok) {
|
|
206
219
|
const body = (res.result ?? {}) as Record<string, unknown>
|
|
207
220
|
const msg = typeof body.error === 'string' ? body.error : t('customers.pipelines.errors.deleteFailed', 'Failed to delete pipeline')
|
|
@@ -248,11 +261,15 @@ export default function PipelineSettings(): React.ReactElement {
|
|
|
248
261
|
flash(t('customers.pipelines.flash.stageCreated', 'Stage created'), 'success')
|
|
249
262
|
await loadStages(stageDialog.pipelineId)
|
|
250
263
|
} else if (stageDialog?.mode === 'edit') {
|
|
251
|
-
const res = await
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
264
|
+
const res = await withScopedApiRequestHeaders(
|
|
265
|
+
buildOptimisticLockHeader(stageDialog.entry.updatedAt),
|
|
266
|
+
() =>
|
|
267
|
+
apiCall('/api/customers/pipeline-stages', {
|
|
268
|
+
method: 'PUT',
|
|
269
|
+
headers: { 'content-type': 'application/json' },
|
|
270
|
+
body: JSON.stringify({ id: stageDialog.entry.id, label: stageForm.label.trim(), ...appearance }),
|
|
271
|
+
}),
|
|
272
|
+
)
|
|
256
273
|
if (!res.ok) {
|
|
257
274
|
await raiseCrudError(res.response, t('customers.pipelines.errors.stageUpdateFailed', 'Failed to update stage'))
|
|
258
275
|
return
|
|
@@ -274,11 +291,15 @@ export default function PipelineSettings(): React.ReactElement {
|
|
|
274
291
|
variant: 'destructive',
|
|
275
292
|
})
|
|
276
293
|
if (!confirmed) return
|
|
277
|
-
const res = await
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
294
|
+
const res = await withScopedApiRequestHeaders(
|
|
295
|
+
buildOptimisticLockHeader(stage.updatedAt),
|
|
296
|
+
() =>
|
|
297
|
+
apiCall('/api/customers/pipeline-stages', {
|
|
298
|
+
method: 'DELETE',
|
|
299
|
+
headers: { 'content-type': 'application/json' },
|
|
300
|
+
body: JSON.stringify({ id: stage.id }),
|
|
301
|
+
}),
|
|
302
|
+
)
|
|
282
303
|
if (!res.ok) {
|
|
283
304
|
const body = (res.result ?? {}) as Record<string, unknown>
|
|
284
305
|
const msg = typeof body.error === 'string' ? body.error : t('customers.pipelines.errors.stageDeleteFailed', 'Failed to delete stage')
|