@open-mercato/core 0.6.6-develop.6317.1.b3be10ab84 → 0.6.6-develop.6331.1.a33b8e99b7
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 +1 -1
- package/dist/modules/attachments/components/AttachmentPartitionSettings.js +3 -0
- package/dist/modules/attachments/components/AttachmentPartitionSettings.js.map +2 -2
- package/dist/modules/auth/api/roles/acl/route.js +2 -2
- package/dist/modules/auth/api/roles/acl/route.js.map +2 -2
- package/dist/modules/auth/api/users/acl/route.js +2 -2
- package/dist/modules/auth/api/users/acl/route.js.map +2 -2
- package/dist/modules/auth/backend/roles/[id]/edit/page.js +12 -0
- package/dist/modules/auth/backend/roles/[id]/edit/page.js.map +2 -2
- package/dist/modules/auth/backend/users/[id]/edit/page.js +12 -0
- package/dist/modules/auth/backend/users/[id]/edit/page.js.map +2 -2
- package/dist/modules/auth/data/entities.js +2 -2
- package/dist/modules/auth/data/entities.js.map +2 -2
- package/dist/modules/business_rules/api/rules/route.js +3 -3
- package/dist/modules/business_rules/api/rules/route.js.map +2 -2
- package/dist/modules/business_rules/api/sets/route.js +3 -3
- package/dist/modules/business_rules/api/sets/route.js.map +2 -2
- package/dist/modules/business_rules/backend/rules/[id]/page.js +12 -1
- package/dist/modules/business_rules/backend/rules/[id]/page.js.map +2 -2
- package/dist/modules/business_rules/backend/sets/[id]/page.js +12 -1
- package/dist/modules/business_rules/backend/sets/[id]/page.js.map +2 -2
- package/dist/modules/catalog/api/product-media/route.js.map +2 -2
- package/dist/modules/catalog/backend/catalog/categories/[id]/edit/page.js +12 -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 +15 -0
- 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 +12 -1
- package/dist/modules/catalog/backend/catalog/products/[productId]/variants/[variantId]/page.js.map +2 -2
- package/dist/modules/catalog/components/PriceKindSettings.js +13 -3
- package/dist/modules/catalog/components/PriceKindSettings.js.map +2 -2
- package/dist/modules/catalog/lib/bulkDelete.js.map +2 -2
- package/dist/modules/currencies/backend/currencies/[id]/page.js +15 -3
- package/dist/modules/currencies/backend/currencies/[id]/page.js.map +2 -2
- package/dist/modules/currencies/backend/currencies/page.js +2 -1
- package/dist/modules/currencies/backend/currencies/page.js.map +2 -2
- package/dist/modules/currencies/backend/exchange-rates/[id]/page.js +12 -1
- package/dist/modules/currencies/backend/exchange-rates/[id]/page.js.map +2 -2
- package/dist/modules/currencies/backend/exchange-rates/page.js +3 -2
- package/dist/modules/currencies/backend/exchange-rates/page.js.map +2 -2
- package/dist/modules/customer_accounts/api/admin/roles/[id].js +3 -3
- package/dist/modules/customer_accounts/api/admin/roles/[id].js.map +2 -2
- package/dist/modules/customer_accounts/api/admin/users/[id].js +3 -3
- package/dist/modules/customer_accounts/api/admin/users/[id].js.map +2 -2
- package/dist/modules/customer_accounts/backend/customer_accounts/roles/[id]/page.js +7 -12
- package/dist/modules/customer_accounts/backend/customer_accounts/roles/[id]/page.js.map +2 -2
- package/dist/modules/customer_accounts/backend/customer_accounts/users/page.js +5 -2
- package/dist/modules/customer_accounts/backend/customer_accounts/users/page.js.map +2 -2
- package/dist/modules/customer_accounts/widgets/injection/account-status/widget.client.js +2 -1
- package/dist/modules/customer_accounts/widgets/injection/account-status/widget.client.js.map +2 -2
- package/dist/modules/customer_accounts/widgets/injection/company-users/widget.client.js +2 -1
- package/dist/modules/customer_accounts/widgets/injection/company-users/widget.client.js.map +2 -2
- package/dist/modules/customers/api/addresses/route.js +4 -2
- package/dist/modules/customers/api/addresses/route.js.map +2 -2
- package/dist/modules/customers/api/tags/route.js +8 -3
- package/dist/modules/customers/api/tags/route.js.map +2 -2
- package/dist/modules/customers/backend/customers/companies-v2/[id]/page.js +13 -2
- package/dist/modules/customers/backend/customers/companies-v2/[id]/page.js.map +2 -2
- package/dist/modules/customers/backend/customers/deals/[id]/hooks/useDealAssociations.js +24 -9
- package/dist/modules/customers/backend/customers/deals/[id]/hooks/useDealAssociations.js.map +2 -2
- package/dist/modules/customers/backend/customers/deals/[id]/hooks/useDealClosure.js +53 -23
- package/dist/modules/customers/backend/customers/deals/[id]/hooks/useDealClosure.js.map +2 -2
- package/dist/modules/customers/backend/customers/deals/[id]/hooks/useDealPipeline.js +13 -3
- package/dist/modules/customers/backend/customers/deals/[id]/hooks/useDealPipeline.js.map +2 -2
- package/dist/modules/customers/backend/customers/deals/[id]/page.js +19 -2
- package/dist/modules/customers/backend/customers/deals/[id]/page.js.map +2 -2
- package/dist/modules/customers/backend/customers/people-v2/[id]/page.js +13 -2
- package/dist/modules/customers/backend/customers/people-v2/[id]/page.js.map +2 -2
- package/dist/modules/customers/commands/interactions.js +5 -5
- package/dist/modules/customers/commands/interactions.js.map +2 -2
- package/dist/modules/customers/commands/pipeline-stages.js +24 -2
- package/dist/modules/customers/commands/pipeline-stages.js.map +2 -2
- package/dist/modules/customers/commands/pipelines.js +24 -2
- package/dist/modules/customers/commands/pipelines.js.map +2 -2
- package/dist/modules/customers/components/detail/AddressesSection.js +46 -29
- package/dist/modules/customers/components/detail/AddressesSection.js.map +2 -2
- package/dist/modules/customers/components/detail/DealForm.js +5 -1
- package/dist/modules/customers/components/detail/DealForm.js.map +2 -2
- package/dist/modules/customers/components/detail/EntityTagsDialog.js +76 -67
- package/dist/modules/customers/components/detail/EntityTagsDialog.js.map +3 -3
- package/dist/modules/customers/components/detail/notesAdapter.js +25 -18
- package/dist/modules/customers/components/detail/notesAdapter.js.map +2 -2
- package/dist/modules/dashboards/components/WidgetVisibilityEditor.js +4 -3
- package/dist/modules/dashboards/components/WidgetVisibilityEditor.js.map +2 -2
- package/dist/modules/data_sync/api/runs.js +1 -0
- package/dist/modules/data_sync/api/runs.js.map +2 -2
- package/dist/modules/data_sync/api/schedules/[id]/route.js +38 -19
- package/dist/modules/data_sync/api/schedules/[id]/route.js.map +2 -2
- package/dist/modules/data_sync/api/schedules/route.js +1 -1
- package/dist/modules/data_sync/api/schedules/route.js.map +2 -2
- package/dist/modules/data_sync/backend/data-sync/page.js +35 -16
- package/dist/modules/data_sync/backend/data-sync/page.js.map +2 -2
- package/dist/modules/data_sync/data/validators.js +1 -0
- package/dist/modules/data_sync/data/validators.js.map +2 -2
- package/dist/modules/data_sync/lib/sync-run-service.js +20 -0
- package/dist/modules/data_sync/lib/sync-run-service.js.map +2 -2
- package/dist/modules/data_sync/lib/sync-schedule-service.js +19 -5
- package/dist/modules/data_sync/lib/sync-schedule-service.js.map +2 -2
- package/dist/modules/dictionaries/api/[dictionaryId]/entries/[entryId]/route.js +3 -3
- package/dist/modules/dictionaries/api/[dictionaryId]/entries/[entryId]/route.js.map +2 -2
- package/dist/modules/dictionaries/api/[dictionaryId]/route.js +3 -3
- package/dist/modules/dictionaries/api/[dictionaryId]/route.js.map +2 -2
- package/dist/modules/dictionaries/components/DictionariesManager.js +12 -1
- package/dist/modules/dictionaries/components/DictionariesManager.js.map +2 -2
- package/dist/modules/dictionaries/components/DictionaryEntriesEditor.js.map +2 -2
- package/dist/modules/directory/backend/directory/organizations/[id]/edit/page.js +12 -0
- package/dist/modules/directory/backend/directory/organizations/[id]/edit/page.js.map +2 -2
- package/dist/modules/directory/backend/directory/tenants/[id]/edit/page.js +12 -0
- package/dist/modules/directory/backend/directory/tenants/[id]/edit/page.js.map +2 -2
- package/dist/modules/entities/api/entities.js +2 -2
- package/dist/modules/entities/api/entities.js.map +2 -2
- package/dist/modules/entities/api/records.js +18 -6
- package/dist/modules/entities/api/records.js.map +2 -2
- package/dist/modules/entities/backend/entities/user/[entityId]/records/page.js +17 -10
- package/dist/modules/entities/backend/entities/user/[entityId]/records/page.js.map +2 -2
- package/dist/modules/feature_toggles/api/overrides/route.js +2 -2
- 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.map +2 -2
- package/dist/modules/feature_toggles/data/entities.js +1 -1
- package/dist/modules/feature_toggles/data/entities.js.map +2 -2
- package/dist/modules/feature_toggles/data/validators.js +2 -1
- package/dist/modules/feature_toggles/data/validators.js.map +2 -2
- package/dist/modules/feature_toggles/lib/queries.js +2 -1
- package/dist/modules/feature_toggles/lib/queries.js.map +2 -2
- package/dist/modules/inbox_ops/api/settings/route.js +2 -2
- package/dist/modules/inbox_ops/api/settings/route.js.map +2 -2
- package/dist/modules/messages/api/unread-count/route.js +32 -0
- package/dist/modules/messages/api/unread-count/route.js.map +2 -2
- package/dist/modules/query_index/components/QueryIndexesTable.js +13 -5
- package/dist/modules/query_index/components/QueryIndexesTable.js.map +2 -2
- package/dist/modules/resources/backend/resources/resource-types/[id]/edit/page.js +12 -1
- package/dist/modules/resources/backend/resources/resource-types/[id]/edit/page.js.map +2 -2
- package/dist/modules/resources/backend/resources/resources/[id]/page.js +12 -1
- package/dist/modules/resources/backend/resources/resources/[id]/page.js.map +2 -2
- package/dist/modules/resources/components/detail/notesAdapter.js +25 -18
- package/dist/modules/resources/components/detail/notesAdapter.js.map +2 -2
- package/dist/modules/sales/backend/sales/documents/[id]/page.js +14 -1
- package/dist/modules/sales/backend/sales/documents/[id]/page.js.map +2 -2
- package/dist/modules/sales/commands/documents.js +11 -10
- package/dist/modules/sales/commands/documents.js.map +2 -2
- package/dist/modules/sales/commands/payments.js +6 -1
- package/dist/modules/sales/commands/payments.js.map +2 -2
- package/dist/modules/sales/commands/returns.js +3 -3
- package/dist/modules/sales/commands/returns.js.map +2 -2
- package/dist/modules/sales/commands/shared.js +3 -3
- package/dist/modules/sales/commands/shared.js.map +2 -2
- package/dist/modules/sales/commands/shipments.js +6 -1
- package/dist/modules/sales/commands/shipments.js.map +2 -2
- package/dist/modules/sales/components/documents/PaymentDialog.js +6 -3
- package/dist/modules/sales/components/documents/PaymentDialog.js.map +2 -2
- package/dist/modules/sales/components/documents/PaymentsSection.js +7 -3
- package/dist/modules/sales/components/documents/PaymentsSection.js.map +2 -2
- package/dist/modules/sales/components/documents/ShipmentDialog.js +6 -3
- package/dist/modules/sales/components/documents/ShipmentDialog.js.map +2 -2
- package/dist/modules/sales/components/documents/ShipmentsSection.js +7 -3
- package/dist/modules/sales/components/documents/ShipmentsSection.js.map +2 -2
- package/dist/modules/sales/di.js +39 -3
- package/dist/modules/sales/di.js.map +2 -2
- package/dist/modules/sales/setup.js +2 -0
- package/dist/modules/sales/setup.js.map +2 -2
- package/dist/modules/shipping_carriers/i18n/en.js +11 -1
- package/dist/modules/shipping_carriers/i18n/en.js.map +2 -2
- package/dist/modules/shipping_carriers/i18n/pl.js +11 -1
- package/dist/modules/shipping_carriers/i18n/pl.js.map +2 -2
- package/dist/modules/shipping_carriers/widgets/injection/tracking-status-badge/widget.client.js +25 -0
- package/dist/modules/shipping_carriers/widgets/injection/tracking-status-badge/widget.client.js.map +7 -0
- package/dist/modules/shipping_carriers/widgets/injection/tracking-status-badge/widget.js +3 -17
- package/dist/modules/shipping_carriers/widgets/injection/tracking-status-badge/widget.js.map +2 -2
- package/dist/modules/staff/backend/staff/leave-requests/[id]/page.js +12 -1
- package/dist/modules/staff/backend/staff/leave-requests/[id]/page.js.map +2 -2
- package/dist/modules/staff/backend/staff/team-members/[id]/page.js +12 -1
- package/dist/modules/staff/backend/staff/team-members/[id]/page.js.map +2 -2
- package/dist/modules/staff/backend/staff/team-roles/[id]/edit/page.js +12 -1
- package/dist/modules/staff/backend/staff/team-roles/[id]/edit/page.js.map +2 -2
- package/dist/modules/staff/backend/staff/teams/[id]/edit/page.js +12 -1
- package/dist/modules/staff/backend/staff/teams/[id]/edit/page.js.map +2 -2
- package/dist/modules/staff/commands/job-histories.js +3 -3
- package/dist/modules/staff/commands/job-histories.js.map +2 -2
- package/dist/modules/staff/components/detail/addressesAdapter.js +33 -24
- package/dist/modules/staff/components/detail/addressesAdapter.js.map +2 -2
- package/dist/modules/staff/components/detail/notesAdapter.js +25 -18
- package/dist/modules/staff/components/detail/notesAdapter.js.map +2 -2
- package/dist/modules/translations/api/[entityType]/[entityId]/route.js +37 -0
- package/dist/modules/translations/api/[entityType]/[entityId]/route.js.map +2 -2
- package/dist/modules/translations/components/TranslationManager.js +7 -1
- package/dist/modules/translations/components/TranslationManager.js.map +2 -2
- package/dist/modules/translations/widgets/injection/translation-manager/widget.client.js +19 -14
- package/dist/modules/translations/widgets/injection/translation-manager/widget.client.js.map +2 -2
- package/dist/modules/workflows/api/definitions/[id]/route.js +3 -3
- package/dist/modules/workflows/api/definitions/[id]/route.js.map +2 -2
- package/dist/modules/workflows/backend/definitions/[id]/page.js +12 -1
- package/dist/modules/workflows/backend/definitions/[id]/page.js.map +2 -2
- package/dist/modules/workflows/backend/definitions/visual-editor/page.js +11 -1
- package/dist/modules/workflows/backend/definitions/visual-editor/page.js.map +2 -2
- package/package.json +7 -7
- package/src/modules/attachments/components/AttachmentPartitionSettings.tsx +3 -0
- package/src/modules/auth/api/roles/acl/route.ts +2 -2
- package/src/modules/auth/api/users/acl/route.ts +2 -2
- package/src/modules/auth/backend/roles/[id]/edit/page.tsx +17 -0
- package/src/modules/auth/backend/users/[id]/edit/page.tsx +17 -0
- package/src/modules/auth/data/entities.ts +2 -2
- package/src/modules/business_rules/api/rules/route.ts +3 -3
- package/src/modules/business_rules/api/sets/route.ts +3 -3
- package/src/modules/business_rules/backend/rules/[id]/page.tsx +17 -1
- package/src/modules/business_rules/backend/sets/[id]/page.tsx +18 -1
- package/src/modules/catalog/api/product-media/route.ts +4 -0
- package/src/modules/catalog/backend/catalog/categories/[id]/edit/page.tsx +17 -0
- package/src/modules/catalog/backend/catalog/products/[id]/page.tsx +21 -0
- package/src/modules/catalog/backend/catalog/products/[productId]/variants/[variantId]/page.tsx +16 -1
- package/src/modules/catalog/components/PriceKindSettings.tsx +15 -7
- package/src/modules/catalog/lib/bulkDelete.ts +6 -0
- package/src/modules/currencies/backend/currencies/[id]/page.tsx +20 -3
- package/src/modules/currencies/backend/currencies/page.tsx +2 -1
- package/src/modules/currencies/backend/exchange-rates/[id]/page.tsx +17 -1
- package/src/modules/currencies/backend/exchange-rates/page.tsx +3 -2
- package/src/modules/customer_accounts/api/admin/roles/[id].ts +3 -3
- package/src/modules/customer_accounts/api/admin/users/[id].ts +3 -3
- package/src/modules/customer_accounts/backend/customer_accounts/roles/[id]/page.tsx +7 -10
- package/src/modules/customer_accounts/backend/customer_accounts/users/page.tsx +6 -7
- package/src/modules/customer_accounts/widgets/injection/account-status/widget.client.tsx +3 -2
- package/src/modules/customer_accounts/widgets/injection/company-users/widget.client.tsx +3 -2
- package/src/modules/customers/api/addresses/route.ts +2 -0
- package/src/modules/customers/api/tags/route.ts +6 -1
- package/src/modules/customers/backend/customers/companies-v2/[id]/page.tsx +19 -2
- package/src/modules/customers/backend/customers/deals/[id]/hooks/useDealAssociations.ts +29 -8
- package/src/modules/customers/backend/customers/deals/[id]/hooks/useDealClosure.ts +47 -20
- package/src/modules/customers/backend/customers/deals/[id]/hooks/useDealPipeline.ts +13 -3
- package/src/modules/customers/backend/customers/deals/[id]/page.tsx +21 -1
- package/src/modules/customers/backend/customers/people-v2/[id]/page.tsx +18 -2
- package/src/modules/customers/commands/interactions.ts +5 -5
- package/src/modules/customers/commands/pipeline-stages.ts +26 -2
- package/src/modules/customers/commands/pipelines.ts +26 -2
- package/src/modules/customers/components/detail/AddressesSection.tsx +50 -28
- package/src/modules/customers/components/detail/DealForm.tsx +12 -0
- package/src/modules/customers/components/detail/EntityTagsDialog.tsx +89 -71
- package/src/modules/customers/components/detail/notesAdapter.ts +29 -18
- 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/dashboards/components/WidgetVisibilityEditor.tsx +6 -3
- package/src/modules/data_sync/api/runs.ts +1 -0
- package/src/modules/data_sync/api/schedules/[id]/route.ts +38 -20
- package/src/modules/data_sync/api/schedules/route.ts +1 -1
- package/src/modules/data_sync/backend/data-sync/page.tsx +35 -16
- package/src/modules/data_sync/data/validators.ts +1 -0
- package/src/modules/data_sync/i18n/de.json +1 -0
- package/src/modules/data_sync/i18n/en.json +1 -0
- package/src/modules/data_sync/i18n/es.json +1 -0
- package/src/modules/data_sync/i18n/pl.json +1 -0
- package/src/modules/data_sync/lib/sync-run-service.ts +23 -0
- package/src/modules/data_sync/lib/sync-schedule-service.ts +30 -5
- package/src/modules/dictionaries/api/[dictionaryId]/entries/[entryId]/route.ts +3 -3
- package/src/modules/dictionaries/api/[dictionaryId]/route.ts +3 -3
- package/src/modules/dictionaries/components/DictionariesManager.tsx +21 -1
- package/src/modules/dictionaries/components/DictionaryEntriesEditor.tsx +2 -0
- package/src/modules/directory/backend/directory/organizations/[id]/edit/page.tsx +17 -0
- package/src/modules/directory/backend/directory/tenants/[id]/edit/page.tsx +17 -0
- package/src/modules/entities/api/entities.ts +2 -2
- package/src/modules/entities/api/records.ts +24 -6
- package/src/modules/entities/backend/entities/user/[entityId]/records/page.tsx +25 -12
- package/src/modules/feature_toggles/api/overrides/route.ts +2 -2
- package/src/modules/feature_toggles/backend/feature-toggles/global/[id]/edit/page.tsx +12 -0
- package/src/modules/feature_toggles/data/entities.ts +1 -1
- package/src/modules/feature_toggles/data/validators.ts +1 -0
- package/src/modules/feature_toggles/lib/queries.ts +1 -0
- package/src/modules/inbox_ops/api/settings/route.ts +2 -2
- package/src/modules/messages/api/unread-count/route.ts +40 -0
- package/src/modules/query_index/components/QueryIndexesTable.tsx +17 -15
- package/src/modules/resources/backend/resources/resource-types/[id]/edit/page.tsx +17 -1
- package/src/modules/resources/backend/resources/resources/[id]/page.tsx +17 -1
- package/src/modules/resources/components/detail/notesAdapter.ts +29 -18
- package/src/modules/sales/backend/sales/documents/[id]/page.tsx +17 -1
- package/src/modules/sales/commands/documents.ts +11 -10
- package/src/modules/sales/commands/payments.ts +11 -0
- package/src/modules/sales/commands/returns.ts +3 -3
- package/src/modules/sales/commands/shared.ts +10 -4
- package/src/modules/sales/commands/shipments.ts +14 -0
- package/src/modules/sales/components/documents/PaymentDialog.tsx +7 -3
- package/src/modules/sales/components/documents/PaymentsSection.tsx +8 -3
- package/src/modules/sales/components/documents/ShipmentDialog.tsx +7 -3
- package/src/modules/sales/components/documents/ShipmentsSection.tsx +8 -3
- package/src/modules/sales/di.ts +68 -9
- package/src/modules/sales/setup.ts +2 -0
- package/src/modules/shipping_carriers/i18n/de.json +11 -1
- package/src/modules/shipping_carriers/i18n/en.json +11 -1
- package/src/modules/shipping_carriers/i18n/en.ts +10 -0
- package/src/modules/shipping_carriers/i18n/es.json +11 -1
- package/src/modules/shipping_carriers/i18n/pl.json +11 -1
- package/src/modules/shipping_carriers/i18n/pl.ts +10 -0
- package/src/modules/shipping_carriers/widgets/injection/tracking-status-badge/widget.client.tsx +35 -0
- package/src/modules/shipping_carriers/widgets/injection/tracking-status-badge/widget.tsx +3 -22
- package/src/modules/staff/backend/staff/leave-requests/[id]/page.tsx +17 -1
- package/src/modules/staff/backend/staff/team-members/[id]/page.tsx +17 -1
- package/src/modules/staff/backend/staff/team-roles/[id]/edit/page.tsx +17 -1
- package/src/modules/staff/backend/staff/teams/[id]/edit/page.tsx +17 -1
- package/src/modules/staff/commands/job-histories.ts +3 -3
- package/src/modules/staff/components/detail/addressesAdapter.ts +40 -23
- package/src/modules/staff/components/detail/notesAdapter.ts +28 -18
- package/src/modules/translations/api/[entityType]/[entityId]/route.ts +74 -0
- package/src/modules/translations/components/TranslationManager.tsx +14 -1
- package/src/modules/translations/widgets/injection/translation-manager/widget.client.tsx +30 -13
- package/src/modules/workflows/api/definitions/[id]/route.ts +3 -3
- package/src/modules/workflows/backend/definitions/[id]/page.tsx +18 -1
- package/src/modules/workflows/backend/definitions/visual-editor/page.tsx +19 -1
|
@@ -5,7 +5,7 @@ import { getAuthFromRequest } from '@open-mercato/shared/lib/auth/server'
|
|
|
5
5
|
import { createRequestContainer } from '@open-mercato/shared/lib/di/container'
|
|
6
6
|
import { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'
|
|
7
7
|
import { isCrudHttpError } from '@open-mercato/shared/lib/crud/errors'
|
|
8
|
-
import {
|
|
8
|
+
import { enforceCommandOptimisticLockWithGuards } from '@open-mercato/shared/lib/crud/optimistic-lock-command'
|
|
9
9
|
import { BusinessRule } from '../../data/entities'
|
|
10
10
|
import type { EntityManager } from '@mikro-orm/postgresql'
|
|
11
11
|
import { escapeLikePattern } from '@open-mercato/shared/lib/db/escapeLikePattern'
|
|
@@ -280,7 +280,7 @@ export async function PUT(req: Request) {
|
|
|
280
280
|
}
|
|
281
281
|
|
|
282
282
|
try {
|
|
283
|
-
|
|
283
|
+
await enforceCommandOptimisticLockWithGuards(container, {
|
|
284
284
|
resourceKind: 'business_rules.rule',
|
|
285
285
|
resourceId: rule.id,
|
|
286
286
|
current: rule.updatedAt ?? null,
|
|
@@ -338,7 +338,7 @@ export async function DELETE(req: Request) {
|
|
|
338
338
|
}
|
|
339
339
|
|
|
340
340
|
try {
|
|
341
|
-
|
|
341
|
+
await enforceCommandOptimisticLockWithGuards(container, {
|
|
342
342
|
resourceKind: 'business_rules.rule',
|
|
343
343
|
resourceId: rule.id,
|
|
344
344
|
current: rule.updatedAt ?? null,
|
|
@@ -4,7 +4,7 @@ import type { OpenApiRouteDoc } from '@open-mercato/shared/lib/openapi'
|
|
|
4
4
|
import { getAuthFromRequest } from '@open-mercato/shared/lib/auth/server'
|
|
5
5
|
import { createRequestContainer } from '@open-mercato/shared/lib/di/container'
|
|
6
6
|
import { isCrudHttpError } from '@open-mercato/shared/lib/crud/errors'
|
|
7
|
-
import {
|
|
7
|
+
import { enforceCommandOptimisticLockWithGuards } from '@open-mercato/shared/lib/crud/optimistic-lock-command'
|
|
8
8
|
import { RuleSet } from '../../data/entities'
|
|
9
9
|
import type { EntityManager } from '@mikro-orm/postgresql'
|
|
10
10
|
import { escapeLikePattern } from '@open-mercato/shared/lib/db/escapeLikePattern'
|
|
@@ -224,7 +224,7 @@ export async function PUT(req: Request) {
|
|
|
224
224
|
}
|
|
225
225
|
|
|
226
226
|
try {
|
|
227
|
-
|
|
227
|
+
await enforceCommandOptimisticLockWithGuards(container, {
|
|
228
228
|
resourceKind: 'business_rules.ruleSet',
|
|
229
229
|
resourceId: ruleSet.id,
|
|
230
230
|
current: ruleSet.updatedAt ?? null,
|
|
@@ -271,7 +271,7 @@ export async function DELETE(req: Request) {
|
|
|
271
271
|
}
|
|
272
272
|
|
|
273
273
|
try {
|
|
274
|
-
|
|
274
|
+
await enforceCommandOptimisticLockWithGuards(container, {
|
|
275
275
|
resourceKind: 'business_rules.ruleSet',
|
|
276
276
|
resourceId: ruleSet.id,
|
|
277
277
|
current: ruleSet.updatedAt ?? null,
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import * as React from 'react'
|
|
4
4
|
import Link from 'next/link'
|
|
5
|
-
import { useRouter, useParams } from 'next/navigation'
|
|
5
|
+
import { useRouter, useParams, usePathname } from 'next/navigation'
|
|
6
6
|
import { useQuery } from '@tanstack/react-query'
|
|
7
7
|
import { Page, PageBody } from '@open-mercato/ui/backend/Page'
|
|
8
8
|
import { CrudForm } from '@open-mercato/ui/backend/CrudForm'
|
|
@@ -10,6 +10,7 @@ import { Spinner } from '@open-mercato/ui/primitives/spinner'
|
|
|
10
10
|
import { Button } from '@open-mercato/ui/primitives/button'
|
|
11
11
|
import { apiFetch, withScopedApiHeaders } from '@open-mercato/ui/backend/utils/api'
|
|
12
12
|
import { buildOptimisticLockHeader } from '@open-mercato/ui/backend/utils/optimisticLock'
|
|
13
|
+
import { buildRecordInjectionContext, useSetCurrentRecordInjectionContext } from '@open-mercato/ui/backend/injection/recordContext'
|
|
13
14
|
import { readJsonSafe } from '@open-mercato/ui/backend/utils/serverErrors'
|
|
14
15
|
import { CrudHttpError } from '@open-mercato/shared/lib/crud/errors'
|
|
15
16
|
import { useT } from '@open-mercato/shared/lib/i18n/context'
|
|
@@ -27,6 +28,7 @@ import { buildRulePayload, parseRuleToFormValues } from '../../../components/uti
|
|
|
27
28
|
export default function EditBusinessRulePage() {
|
|
28
29
|
const router = useRouter()
|
|
29
30
|
const params = useParams()
|
|
31
|
+
const pathname = usePathname()
|
|
30
32
|
|
|
31
33
|
// Handle catch-all route: params.slug = ['rules', 'uuid']
|
|
32
34
|
let ruleId: string | undefined
|
|
@@ -103,6 +105,20 @@ export default function EditBusinessRulePage() {
|
|
|
103
105
|
[t]
|
|
104
106
|
)
|
|
105
107
|
|
|
108
|
+
// Publish page-load record context to the AppShell-owned `backend:record:current`
|
|
109
|
+
// mount so the enterprise record_locks widget resolves `business_rules.rule` + id
|
|
110
|
+
// explicitly. The resourceKind mirrors the route's `enforceCommandOptimisticLock`
|
|
111
|
+
// call so the held lock matches the save-time conflict surface for the same rule.
|
|
112
|
+
useSetCurrentRecordInjectionContext(
|
|
113
|
+
buildRecordInjectionContext({
|
|
114
|
+
resourceKind: 'business_rules.rule',
|
|
115
|
+
resourceId: ruleId ?? null,
|
|
116
|
+
updatedAt: rule?.updatedAt ?? rule?.updated_at ?? null,
|
|
117
|
+
data: (rule ?? null) as Record<string, unknown> | null,
|
|
118
|
+
path: pathname,
|
|
119
|
+
}),
|
|
120
|
+
)
|
|
121
|
+
|
|
106
122
|
if (isLoading) {
|
|
107
123
|
return (
|
|
108
124
|
<Page>
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import * as React from 'react'
|
|
4
4
|
import Link from 'next/link'
|
|
5
|
-
import { useRouter, useParams } from 'next/navigation'
|
|
5
|
+
import { useRouter, useParams, usePathname } from 'next/navigation'
|
|
6
6
|
import { useQuery, useQueryClient } from '@tanstack/react-query'
|
|
7
7
|
import { Page, PageBody } from '@open-mercato/ui/backend/Page'
|
|
8
8
|
import { CrudForm } from '@open-mercato/ui/backend/CrudForm'
|
|
@@ -12,6 +12,7 @@ import { Button } from '@open-mercato/ui/primitives/button'
|
|
|
12
12
|
import { apiFetch, withScopedApiHeaders } from '@open-mercato/ui/backend/utils/api'
|
|
13
13
|
import { apiCall } from '@open-mercato/ui/backend/utils/apiCall'
|
|
14
14
|
import { buildOptimisticLockHeader } from '@open-mercato/ui/backend/utils/optimisticLock'
|
|
15
|
+
import { buildRecordInjectionContext, useSetCurrentRecordInjectionContext } from '@open-mercato/ui/backend/injection/recordContext'
|
|
15
16
|
import { readJsonSafe } from '@open-mercato/ui/backend/utils/serverErrors'
|
|
16
17
|
import { CrudHttpError } from '@open-mercato/shared/lib/crud/errors'
|
|
17
18
|
import { flash } from '@open-mercato/ui/backend/FlashMessages'
|
|
@@ -55,6 +56,7 @@ type RuleSetDetail = {
|
|
|
55
56
|
export default function EditRuleSetPage() {
|
|
56
57
|
const router = useRouter()
|
|
57
58
|
const params = useParams()
|
|
59
|
+
const pathname = usePathname()
|
|
58
60
|
|
|
59
61
|
// Handle catch-all route: params.slug = ['sets', 'uuid']
|
|
60
62
|
let setId: string | undefined
|
|
@@ -237,6 +239,21 @@ export default function EditRuleSetPage() {
|
|
|
237
239
|
]
|
|
238
240
|
}, [t, ruleSet, handleAddMember, handleUpdateMember, handleRemoveMember])
|
|
239
241
|
|
|
242
|
+
// Publish page-load record context to the AppShell-owned `backend:record:current`
|
|
243
|
+
// mount so the enterprise record_locks widget resolves the rule set + id
|
|
244
|
+
// explicitly. The resourceKind mirrors the route's `enforceCommandOptimisticLock`
|
|
245
|
+
// call (`business_rules.ruleSet`) so the held lock matches the save-time conflict
|
|
246
|
+
// surface for the same rule set.
|
|
247
|
+
useSetCurrentRecordInjectionContext(
|
|
248
|
+
buildRecordInjectionContext({
|
|
249
|
+
resourceKind: 'business_rules.ruleSet',
|
|
250
|
+
resourceId: setId ?? null,
|
|
251
|
+
updatedAt: ruleSet?.updatedAt ?? null,
|
|
252
|
+
data: (ruleSet ?? null) as Record<string, unknown> | null,
|
|
253
|
+
path: pathname,
|
|
254
|
+
}),
|
|
255
|
+
)
|
|
256
|
+
|
|
240
257
|
if (isLoading) {
|
|
241
258
|
return (
|
|
242
259
|
<Page>
|
|
@@ -10,6 +10,10 @@ import { CatalogProduct } from '../../data/entities'
|
|
|
10
10
|
import { E } from '#generated/entities.ids.generated'
|
|
11
11
|
import type { OpenApiRouteDoc } from '@open-mercato/shared/lib/openapi'
|
|
12
12
|
|
|
13
|
+
// record_locks decision: this route is read-only (GET only) and projects the
|
|
14
|
+
// attachment side-table for a product. It is EXEMPT from the optimistic-lock /
|
|
15
|
+
// record-lock guard (Phase 4) — there is no mutating method here, and media
|
|
16
|
+
// uploads/deletes are owned by the attachments module's own write paths.
|
|
13
17
|
export const metadata = {
|
|
14
18
|
GET: { requireAuth: true, requireFeatures: ['catalog.products.view'] },
|
|
15
19
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use client"
|
|
2
2
|
|
|
3
3
|
import * as React from 'react'
|
|
4
|
+
import { usePathname } from 'next/navigation'
|
|
4
5
|
import { Page, PageBody } from '@open-mercato/ui/backend/Page'
|
|
5
6
|
import { CrudForm, type CrudField, type CrudFormGroup } from '@open-mercato/ui/backend/CrudForm'
|
|
6
7
|
import { apiCall } from '@open-mercato/ui/backend/utils/apiCall'
|
|
@@ -8,6 +9,7 @@ import { updateCrud, deleteCrud } from '@open-mercato/ui/backend/utils/crud'
|
|
|
8
9
|
import { createCrudFormError } from '@open-mercato/ui/backend/utils/serverErrors'
|
|
9
10
|
import { collectCustomFieldValues } from '@open-mercato/ui/backend/utils/customFieldValues'
|
|
10
11
|
import { ErrorMessage, RecordNotFoundState } from '@open-mercato/ui/backend/detail'
|
|
12
|
+
import { buildRecordInjectionContext, useSetCurrentRecordInjectionContext } from '@open-mercato/ui/backend/injection/recordContext'
|
|
11
13
|
import { useT } from '@open-mercato/shared/lib/i18n/context'
|
|
12
14
|
import { extractCustomFieldEntries } from '@open-mercato/shared/lib/crud/custom-fields-client'
|
|
13
15
|
import { E } from '#generated/entities.ids.generated'
|
|
@@ -81,6 +83,7 @@ async function submitCategoryUpdate(
|
|
|
81
83
|
export default function EditCatalogCategoryPage({ params }: { params?: { id?: string } }) {
|
|
82
84
|
const categoryId = params?.id ?? ''
|
|
83
85
|
const t = useT()
|
|
86
|
+
const pathname = usePathname()
|
|
84
87
|
const [initialValues, setInitialValues] = React.useState<CategoryFormValues | null>(null)
|
|
85
88
|
const [pathLabel, setPathLabel] = React.useState<string>('')
|
|
86
89
|
const [loading, setLoading] = React.useState<boolean>(true)
|
|
@@ -195,6 +198,20 @@ export default function EditCatalogCategoryPage({ params }: { params?: { id?: st
|
|
|
195
198
|
},
|
|
196
199
|
], [t])
|
|
197
200
|
|
|
201
|
+
// Publish page-load record context to the AppShell-owned `backend:record:current`
|
|
202
|
+
// mount so the enterprise record_locks widget resolves `catalog.category` + id
|
|
203
|
+
// explicitly. The resourceKind mirrors the CrudForm `versionHistory` so the held
|
|
204
|
+
// lock matches the save-time conflict surface for the same category.
|
|
205
|
+
useSetCurrentRecordInjectionContext(
|
|
206
|
+
buildRecordInjectionContext({
|
|
207
|
+
resourceKind: 'catalog.category',
|
|
208
|
+
resourceId: categoryId || null,
|
|
209
|
+
updatedAt: initialValues?.updatedAt ?? null,
|
|
210
|
+
data: initialValues as Record<string, unknown> | null,
|
|
211
|
+
path: pathname,
|
|
212
|
+
}),
|
|
213
|
+
)
|
|
214
|
+
|
|
198
215
|
if (!categoryId) {
|
|
199
216
|
return (
|
|
200
217
|
<Page>
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import * as React from "react";
|
|
4
4
|
import Link from "next/link";
|
|
5
|
+
import { usePathname } from "next/navigation";
|
|
5
6
|
import { Page, PageBody } from "@open-mercato/ui/backend/Page";
|
|
6
7
|
import { ErrorMessage, RecordNotFoundState } from "@open-mercato/ui/backend/detail";
|
|
7
8
|
import {
|
|
@@ -41,6 +42,10 @@ import {
|
|
|
41
42
|
} from "@open-mercato/ui/backend/utils/apiCall";
|
|
42
43
|
import { buildOptimisticLockHeader } from "@open-mercato/ui/backend/utils/optimisticLock";
|
|
43
44
|
import { surfaceRecordConflict } from "@open-mercato/ui/backend/conflicts";
|
|
45
|
+
import {
|
|
46
|
+
buildRecordInjectionContext,
|
|
47
|
+
useSetCurrentRecordInjectionContext,
|
|
48
|
+
} from "@open-mercato/ui/backend/injection/recordContext";
|
|
44
49
|
import { useT } from "@open-mercato/shared/lib/i18n/context";
|
|
45
50
|
import { useConfirmDialog } from "@open-mercato/ui/backend/confirm-dialog";
|
|
46
51
|
import { E } from "#generated/entities.ids.generated";
|
|
@@ -314,6 +319,7 @@ export default function EditCatalogProductPage({
|
|
|
314
319
|
}) {
|
|
315
320
|
const productId = params?.id ? String(params.id) : null;
|
|
316
321
|
const t = useT();
|
|
322
|
+
const pathname = usePathname();
|
|
317
323
|
const productSubpathPrefix = productId
|
|
318
324
|
? `/backend/catalog/products/${productId}/`
|
|
319
325
|
: null;
|
|
@@ -835,6 +841,21 @@ export default function EditCatalogProductPage({
|
|
|
835
841
|
el.scrollIntoView({ behavior: 'smooth', block: 'start' })
|
|
836
842
|
})
|
|
837
843
|
|
|
844
|
+
// Publish page-load record context to the AppShell-owned `backend:record:current`
|
|
845
|
+
// mount so the enterprise record_locks widget resolves `catalog.product` + id
|
|
846
|
+
// explicitly (presence/acquire/heartbeat on load; cleared on unmount). The
|
|
847
|
+
// resourceKind mirrors the CrudForm `versionHistory` so the held lock matches
|
|
848
|
+
// the save-time conflict surface for the same product.
|
|
849
|
+
useSetCurrentRecordInjectionContext(
|
|
850
|
+
buildRecordInjectionContext({
|
|
851
|
+
resourceKind: "catalog.product",
|
|
852
|
+
resourceId: productId,
|
|
853
|
+
updatedAt: initialValues?.updatedAt ?? null,
|
|
854
|
+
data: initialValues as Record<string, unknown> | null,
|
|
855
|
+
path: pathname,
|
|
856
|
+
}),
|
|
857
|
+
);
|
|
858
|
+
|
|
838
859
|
const handleVariantDeleted = React.useCallback((variantId: string) => {
|
|
839
860
|
setVariants((prev) => prev.filter((variant) => variant.id !== variantId));
|
|
840
861
|
}, []);
|
package/src/modules/catalog/backend/catalog/products/[productId]/variants/[variantId]/page.tsx
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use client"
|
|
2
2
|
|
|
3
3
|
import * as React from 'react'
|
|
4
|
-
import { useRouter } from 'next/navigation'
|
|
4
|
+
import { useRouter, usePathname } from 'next/navigation'
|
|
5
5
|
import { Page, PageBody } from '@open-mercato/ui/backend/Page'
|
|
6
6
|
import { CrudForm, type CrudFormGroup } from '@open-mercato/ui/backend/CrudForm'
|
|
7
7
|
import { createCrud, updateCrud, deleteCrud } from '@open-mercato/ui/backend/utils/crud'
|
|
@@ -10,6 +10,7 @@ import { collectCustomFieldValues } from '@open-mercato/ui/backend/utils/customF
|
|
|
10
10
|
import { apiCall, readApiResultOrThrow, withScopedApiRequestHeaders } from '@open-mercato/ui/backend/utils/apiCall'
|
|
11
11
|
import { buildOptimisticLockHeader } from '@open-mercato/ui/backend/utils/optimisticLock'
|
|
12
12
|
import { surfaceRecordConflict } from '@open-mercato/ui/backend/conflicts'
|
|
13
|
+
import { buildRecordInjectionContext, useSetCurrentRecordInjectionContext } from '@open-mercato/ui/backend/injection/recordContext'
|
|
13
14
|
import { flash } from '@open-mercato/ui/backend/FlashMessages'
|
|
14
15
|
import { ErrorMessage, RecordNotFoundState } from '@open-mercato/ui/backend/detail'
|
|
15
16
|
import { useT } from '@open-mercato/shared/lib/i18n/context'
|
|
@@ -100,6 +101,7 @@ function resolveVariantPriceLabel(prices: Record<string, VariantPriceDraft> | un
|
|
|
100
101
|
export default function EditVariantPage({ params }: { params?: { productId?: string; variantId?: string } }) {
|
|
101
102
|
const router = useRouter()
|
|
102
103
|
const t = useT()
|
|
104
|
+
const pathname = usePathname()
|
|
103
105
|
const productId = params?.productId ? String(params.productId) : null
|
|
104
106
|
const variantId = params?.variantId ? String(params.variantId) : null
|
|
105
107
|
const isCreateSentinel = variantId === 'create'
|
|
@@ -476,6 +478,19 @@ export default function EditVariantPage({ params }: { params?: { productId?: str
|
|
|
476
478
|
return list
|
|
477
479
|
}, [optionDefinitions, priceKinds, t, taxRates])
|
|
478
480
|
|
|
481
|
+
// Publish page-load record context to the AppShell-owned `backend:record:current`
|
|
482
|
+
// mount so the enterprise record_locks widget resolves `catalog.variant` + id
|
|
483
|
+
// explicitly. Skipped on the create-delegation path (no record to lock).
|
|
484
|
+
useSetCurrentRecordInjectionContext(
|
|
485
|
+
buildRecordInjectionContext({
|
|
486
|
+
resourceKind: 'catalog.variant',
|
|
487
|
+
resourceId: isCreateSentinel ? null : variantId,
|
|
488
|
+
updatedAt: initialValues?.updatedAt ?? null,
|
|
489
|
+
data: initialValues as Record<string, unknown> | null,
|
|
490
|
+
path: pathname,
|
|
491
|
+
}),
|
|
492
|
+
)
|
|
493
|
+
|
|
479
494
|
if (isCreateSentinel) {
|
|
480
495
|
if (!productId) {
|
|
481
496
|
return (
|
|
@@ -18,7 +18,8 @@ import {
|
|
|
18
18
|
} from '@open-mercato/ui/primitives/dialog'
|
|
19
19
|
import { flash } from '@open-mercato/ui/backend/FlashMessages'
|
|
20
20
|
import { apiCall, readApiResultOrThrow, withScopedApiRequestHeaders } from '@open-mercato/ui/backend/utils/apiCall'
|
|
21
|
-
import { buildOptimisticLockHeader
|
|
21
|
+
import { buildOptimisticLockHeader } from '@open-mercato/ui/backend/utils/optimisticLock'
|
|
22
|
+
import { surfaceRecordConflict } from '@open-mercato/ui/backend/conflicts'
|
|
22
23
|
import { raiseCrudError } from '@open-mercato/ui/backend/utils/serverErrors'
|
|
23
24
|
import { useOrganizationScopeVersion } from '@open-mercato/shared/lib/frontend/useOrganizationScope'
|
|
24
25
|
import { useT } from '@open-mercato/shared/lib/i18n/context'
|
|
@@ -236,9 +237,15 @@ export function PriceKindSettings() {
|
|
|
236
237
|
await loadItems()
|
|
237
238
|
} catch (err) {
|
|
238
239
|
console.error('catalog.price-kinds.save failed', err)
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
240
|
+
// Route a concurrent-edit 409 through the single conflict surface (unified
|
|
241
|
+
// conflict bar, or the enterprise merge dialog when its handler is mounted)
|
|
242
|
+
// and close the editor so that surface owns the resolution. Other errors
|
|
243
|
+
// stay inline in the dialog so the user can correct and resubmit.
|
|
244
|
+
if (surfaceRecordConflict(err, t, { onRefresh: () => { void loadItems() } })) {
|
|
245
|
+
closeDialog()
|
|
246
|
+
return
|
|
247
|
+
}
|
|
248
|
+
const message = err instanceof Error ? err.message : t('catalog.priceKinds.errors.save', 'Failed to save price kind.')
|
|
242
249
|
setError(message)
|
|
243
250
|
} finally {
|
|
244
251
|
setSubmitting(false)
|
|
@@ -270,9 +277,10 @@ export function PriceKindSettings() {
|
|
|
270
277
|
await loadItems()
|
|
271
278
|
} catch (err) {
|
|
272
279
|
console.error('catalog.price-kinds.delete failed', err)
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
280
|
+
// Route a concurrent-edit 409 through the single conflict surface; fall
|
|
281
|
+
// back to a flash for any other delete failure.
|
|
282
|
+
if (surfaceRecordConflict(err, t, { onRefresh: () => { void loadItems() } })) return
|
|
283
|
+
const message = err instanceof Error ? err.message : t('catalog.priceKinds.errors.delete', 'Failed to delete price kind.')
|
|
276
284
|
flash(message, 'error')
|
|
277
285
|
}
|
|
278
286
|
},
|
|
@@ -82,6 +82,12 @@ export async function deleteCatalogProductsWithProgress(params: {
|
|
|
82
82
|
let affectedCount = 0
|
|
83
83
|
const deletedIds = new Set<string>()
|
|
84
84
|
|
|
85
|
+
// record_locks decision: bulk product delete is EXEMPT from the optimistic-lock
|
|
86
|
+
// / record-lock guard (Phase 4). It is an explicit destructive operation over a
|
|
87
|
+
// multi-selection, not a collaborative field edit, and the queued job has no
|
|
88
|
+
// per-row expected `updated_at` to compare against — mirroring the customers
|
|
89
|
+
// bulk pattern from Phase 2. Single-product delete on the detail screen still
|
|
90
|
+
// rides the CRUD mutation-guard decorator with the version header.
|
|
85
91
|
for (const [index, id] of ids.entries()) {
|
|
86
92
|
await commandBus.execute<{ body?: Record<string, unknown> }, { productId: string }>('catalog.products.delete', {
|
|
87
93
|
input: { body: { id } },
|
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
'use client'
|
|
2
2
|
|
|
3
3
|
import * as React from 'react'
|
|
4
|
-
import { useRouter, useParams } from 'next/navigation'
|
|
4
|
+
import { useRouter, useParams, usePathname } from 'next/navigation'
|
|
5
5
|
import { Page, PageBody } from '@open-mercato/ui/backend/Page'
|
|
6
6
|
import { CrudForm, type CrudFormGroup } from '@open-mercato/ui/backend/CrudForm'
|
|
7
7
|
import { updateCrud, deleteCrud } from '@open-mercato/ui/backend/utils/crud'
|
|
8
8
|
import { createCrudFormError } from '@open-mercato/ui/backend/utils/serverErrors'
|
|
9
9
|
import { flash } from '@open-mercato/ui/backend/FlashMessages'
|
|
10
10
|
import { apiCall, withScopedApiRequestHeaders } from '@open-mercato/ui/backend/utils/apiCall'
|
|
11
|
-
import { buildOptimisticLockHeader
|
|
11
|
+
import { buildOptimisticLockHeader } from '@open-mercato/ui/backend/utils/optimisticLock'
|
|
12
|
+
import { surfaceRecordConflict } from '@open-mercato/ui/backend/conflicts'
|
|
13
|
+
import { buildRecordInjectionContext, useSetCurrentRecordInjectionContext } from '@open-mercato/ui/backend/injection/recordContext'
|
|
12
14
|
import { useGuardedMutation } from '@open-mercato/ui/backend/injection/useGuardedMutation'
|
|
13
15
|
import { useT } from '@open-mercato/shared/lib/i18n/context'
|
|
14
16
|
import { SendObjectMessageDialog } from '@open-mercato/ui/backend/messages'
|
|
@@ -35,6 +37,7 @@ type CurrencyData = {
|
|
|
35
37
|
export default function EditCurrencyPage({ params }: { params?: { id?: string } }) {
|
|
36
38
|
const t = useT()
|
|
37
39
|
const router = useRouter()
|
|
40
|
+
const pathname = usePathname()
|
|
38
41
|
const { confirm: confirmDialog, ConfirmDialogElement } = useConfirmDialog()
|
|
39
42
|
const mutationContextId = 'currencies-edit:delete'
|
|
40
43
|
const { runMutation, retryLastMutation } = useGuardedMutation<{
|
|
@@ -185,11 +188,25 @@ export default function EditCurrencyPage({ params }: { params?: { id?: string }
|
|
|
185
188
|
flash(t('currencies.flash.deleted'), 'success')
|
|
186
189
|
router.push('/backend/currencies')
|
|
187
190
|
} catch (error) {
|
|
188
|
-
if (
|
|
191
|
+
if (surfaceRecordConflict(error, t)) return
|
|
189
192
|
flash(t('currencies.flash.deleteError'), 'error')
|
|
190
193
|
}
|
|
191
194
|
}, [currency, t, router, confirmDialog, mutationContextId, retryLastMutation, runMutation])
|
|
192
195
|
|
|
196
|
+
// Publish page-load record context to the AppShell-owned `backend:record:current`
|
|
197
|
+
// mount so the enterprise record_locks widget resolves `currencies.currency` + id
|
|
198
|
+
// explicitly. The resourceKind mirrors the CrudForm `versionHistory` so the held
|
|
199
|
+
// lock matches the save-time conflict surface for the same currency.
|
|
200
|
+
useSetCurrentRecordInjectionContext(
|
|
201
|
+
buildRecordInjectionContext({
|
|
202
|
+
resourceKind: 'currencies.currency',
|
|
203
|
+
resourceId: currency?.id ?? null,
|
|
204
|
+
updatedAt: currency?.updatedAt ?? currency?.updated_at ?? null,
|
|
205
|
+
data: currency as Record<string, unknown> | null,
|
|
206
|
+
path: pathname,
|
|
207
|
+
}),
|
|
208
|
+
)
|
|
209
|
+
|
|
193
210
|
if (loading) {
|
|
194
211
|
return (
|
|
195
212
|
<Page>
|
|
@@ -14,6 +14,7 @@ import { Plus, Star } from 'lucide-react'
|
|
|
14
14
|
import { useT } from '@open-mercato/shared/lib/i18n/context'
|
|
15
15
|
import { apiCall, withScopedApiRequestHeaders } from '@open-mercato/ui/backend/utils/apiCall'
|
|
16
16
|
import { buildOptimisticLockHeader, extractOptimisticLockConflict } from '@open-mercato/ui/backend/utils/optimisticLock'
|
|
17
|
+
import { surfaceRecordConflict } from '@open-mercato/ui/backend/conflicts'
|
|
17
18
|
import { useGuardedMutation } from '@open-mercato/ui/backend/injection/useGuardedMutation'
|
|
18
19
|
import { flash } from '@open-mercato/ui/backend/FlashMessages'
|
|
19
20
|
import { useOrganizationScopeVersion } from '@open-mercato/shared/lib/frontend/useOrganizationScope'
|
|
@@ -188,7 +189,7 @@ export default function CurrenciesPage() {
|
|
|
188
189
|
flash(t('currencies.flash.deleted'), 'success')
|
|
189
190
|
setReloadToken((token) => token + 1)
|
|
190
191
|
} catch (error) {
|
|
191
|
-
if (
|
|
192
|
+
if (surfaceRecordConflict(error, t, { onRefresh: () => setReloadToken((token) => token + 1) })) return
|
|
192
193
|
flash(t('currencies.flash.deleteError'), 'error')
|
|
193
194
|
}
|
|
194
195
|
},
|
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
'use client'
|
|
2
2
|
|
|
3
3
|
import * as React from 'react'
|
|
4
|
-
import { useRouter } from 'next/navigation'
|
|
4
|
+
import { useRouter, usePathname } from 'next/navigation'
|
|
5
5
|
import { Page, PageBody } from '@open-mercato/ui/backend/Page'
|
|
6
6
|
import { LoadingMessage, ErrorMessage, RecordNotFoundState } from '@open-mercato/ui/backend/detail'
|
|
7
7
|
import { CrudForm } from '@open-mercato/ui/backend/CrudForm'
|
|
8
8
|
import { updateCrud } from '@open-mercato/ui/backend/utils/crud'
|
|
9
9
|
import { flash } from '@open-mercato/ui/backend/FlashMessages'
|
|
10
10
|
import { apiCall } from '@open-mercato/ui/backend/utils/apiCall'
|
|
11
|
+
import { buildRecordInjectionContext, useSetCurrentRecordInjectionContext } from '@open-mercato/ui/backend/injection/recordContext'
|
|
11
12
|
import { useT } from '@open-mercato/shared/lib/i18n/context'
|
|
12
13
|
import {
|
|
13
14
|
loadCurrencyOptions,
|
|
@@ -47,6 +48,7 @@ type ExchangeRateData = {
|
|
|
47
48
|
export default function EditExchangeRatePage({ params }: { params?: { id?: string } }) {
|
|
48
49
|
const t = useT()
|
|
49
50
|
const router = useRouter()
|
|
51
|
+
const pathname = usePathname()
|
|
50
52
|
|
|
51
53
|
const [exchangeRate, setExchangeRate] = React.useState<ExchangeRateData | null>(null)
|
|
52
54
|
const [loading, setLoading] = React.useState(true)
|
|
@@ -84,6 +86,20 @@ export default function EditExchangeRatePage({ params }: { params?: { id?: strin
|
|
|
84
86
|
[t, loadOptions]
|
|
85
87
|
)
|
|
86
88
|
|
|
89
|
+
// Publish page-load record context to the AppShell-owned `backend:record:current`
|
|
90
|
+
// mount so the enterprise record_locks widget resolves `currencies.exchange_rate`
|
|
91
|
+
// + id explicitly. The resourceKind mirrors the CrudForm `versionHistory` so the
|
|
92
|
+
// held lock matches the save-time conflict surface for the same exchange rate.
|
|
93
|
+
useSetCurrentRecordInjectionContext(
|
|
94
|
+
buildRecordInjectionContext({
|
|
95
|
+
resourceKind: 'currencies.exchange_rate',
|
|
96
|
+
resourceId: exchangeRate?.id ?? null,
|
|
97
|
+
updatedAt: exchangeRate?.updatedAt ?? exchangeRate?.updated_at ?? null,
|
|
98
|
+
data: exchangeRate as Record<string, unknown> | null,
|
|
99
|
+
path: pathname,
|
|
100
|
+
}),
|
|
101
|
+
)
|
|
102
|
+
|
|
87
103
|
if (loading) {
|
|
88
104
|
return (
|
|
89
105
|
<Page>
|
|
@@ -13,7 +13,8 @@ import { BooleanIcon } from '@open-mercato/ui/backend/ValueIcons'
|
|
|
13
13
|
import { Plus } from 'lucide-react'
|
|
14
14
|
import { useT } from '@open-mercato/shared/lib/i18n/context'
|
|
15
15
|
import { apiCall, withScopedApiRequestHeaders } from '@open-mercato/ui/backend/utils/apiCall'
|
|
16
|
-
import { buildOptimisticLockHeader
|
|
16
|
+
import { buildOptimisticLockHeader } from '@open-mercato/ui/backend/utils/optimisticLock'
|
|
17
|
+
import { surfaceRecordConflict } from '@open-mercato/ui/backend/conflicts'
|
|
17
18
|
import { useGuardedMutation } from '@open-mercato/ui/backend/injection/useGuardedMutation'
|
|
18
19
|
import { flash } from '@open-mercato/ui/backend/FlashMessages'
|
|
19
20
|
import { useOrganizationScopeVersion } from '@open-mercato/shared/lib/frontend/useOrganizationScope'
|
|
@@ -152,7 +153,7 @@ export default function ExchangeRatesPage() {
|
|
|
152
153
|
flash(t('exchangeRates.flash.deleted'), 'success')
|
|
153
154
|
setReloadToken((token) => token + 1)
|
|
154
155
|
} catch (error) {
|
|
155
|
-
if (
|
|
156
|
+
if (surfaceRecordConflict(error, t, { onRefresh: () => setReloadToken((token) => token + 1) })) return
|
|
156
157
|
flash(t('exchangeRates.flash.deleteError'), 'error')
|
|
157
158
|
}
|
|
158
159
|
},
|
|
@@ -7,7 +7,7 @@ import { RbacService } from '@open-mercato/core/modules/auth/services/rbacServic
|
|
|
7
7
|
import { CustomerRole, CustomerRoleAcl, CustomerUserRole } from '@open-mercato/core/modules/customer_accounts/data/entities'
|
|
8
8
|
import { updateRoleSchema } from '@open-mercato/core/modules/customer_accounts/data/validators'
|
|
9
9
|
import { emitCustomerAccountsEvent } from '@open-mercato/core/modules/customer_accounts/events'
|
|
10
|
-
import {
|
|
10
|
+
import { enforceCommandOptimisticLockWithGuards } from '@open-mercato/shared/lib/crud/optimistic-lock-command'
|
|
11
11
|
import { isCrudHttpError } from '@open-mercato/shared/lib/crud/errors'
|
|
12
12
|
|
|
13
13
|
export const metadata = {}
|
|
@@ -107,7 +107,7 @@ export async function PUT(req: Request, { params }: { params: { id: string } })
|
|
|
107
107
|
// Optimistic lock: refuse a stale overwrite so two admins editing the same role
|
|
108
108
|
// in parallel cannot silently clobber each other (#2055). Strictly additive.
|
|
109
109
|
try {
|
|
110
|
-
|
|
110
|
+
await enforceCommandOptimisticLockWithGuards(container, {
|
|
111
111
|
resourceKind: 'customer_accounts.role',
|
|
112
112
|
resourceId: role.id,
|
|
113
113
|
current: role.updatedAt ?? null,
|
|
@@ -169,7 +169,7 @@ export async function DELETE(req: Request, { params }: { params: { id: string }
|
|
|
169
169
|
|
|
170
170
|
// Optimistic lock: refuse a stale delete. Strictly additive.
|
|
171
171
|
try {
|
|
172
|
-
|
|
172
|
+
await enforceCommandOptimisticLockWithGuards(container, {
|
|
173
173
|
resourceKind: 'customer_accounts.role',
|
|
174
174
|
resourceId: role.id,
|
|
175
175
|
current: role.updatedAt ?? null,
|
|
@@ -12,7 +12,7 @@ import { adminUpdateUserSchema } from '@open-mercato/core/modules/customer_accou
|
|
|
12
12
|
import { emitCustomerAccountsEvent } from '@open-mercato/core/modules/customer_accounts/events'
|
|
13
13
|
import { findOneWithDecryption, findWithDecryption } from '@open-mercato/shared/lib/encryption/find'
|
|
14
14
|
import { isOwnedCompanyEntity } from '@open-mercato/core/modules/customer_accounts/lib/customerEntityOwnership'
|
|
15
|
-
import {
|
|
15
|
+
import { enforceCommandOptimisticLockWithGuards } from '@open-mercato/shared/lib/crud/optimistic-lock-command'
|
|
16
16
|
import { isCrudHttpError } from '@open-mercato/shared/lib/crud/errors'
|
|
17
17
|
|
|
18
18
|
export const metadata = {}
|
|
@@ -143,7 +143,7 @@ export async function PUT(req: Request, { params }: { params: { id: string } })
|
|
|
143
143
|
// customer user in parallel cannot silently clobber each other (#2055). The
|
|
144
144
|
// check is strictly additive — a no-op when the client sends no expected-version header.
|
|
145
145
|
try {
|
|
146
|
-
|
|
146
|
+
await enforceCommandOptimisticLockWithGuards(container, {
|
|
147
147
|
resourceKind: 'customer_accounts.user',
|
|
148
148
|
resourceId: user.id,
|
|
149
149
|
current: user.updatedAt ?? null,
|
|
@@ -267,7 +267,7 @@ export async function DELETE(req: Request, { params }: { params: { id: string }
|
|
|
267
267
|
// Optimistic lock: refuse a stale delete (e.g. deleting a record another admin
|
|
268
268
|
// already modified). Strictly additive — a no-op without the expected-version header.
|
|
269
269
|
try {
|
|
270
|
-
|
|
270
|
+
await enforceCommandOptimisticLockWithGuards(container, {
|
|
271
271
|
resourceKind: 'customer_accounts.user',
|
|
272
272
|
resourceId: user.id,
|
|
273
273
|
current: user.updatedAt ?? null,
|
|
@@ -7,6 +7,7 @@ import { Page, PageBody } from '@open-mercato/ui/backend/Page'
|
|
|
7
7
|
import { CrudForm } from '@open-mercato/ui/backend/CrudForm'
|
|
8
8
|
import type { CrudField, CrudFormGroup, CrudFormGroupComponentProps } from '@open-mercato/ui/backend/CrudForm'
|
|
9
9
|
import { Button } from '@open-mercato/ui/primitives/button'
|
|
10
|
+
import { Checkbox } from '@open-mercato/ui/primitives/checkbox'
|
|
10
11
|
import { Spinner } from '@open-mercato/ui/primitives/spinner'
|
|
11
12
|
import { apiCall, readApiResultOrThrow, withScopedApiRequestHeaders } from '@open-mercato/ui/backend/utils/apiCall'
|
|
12
13
|
import { buildOptimisticLockHeader } from '@open-mercato/ui/backend/utils/optimisticLock'
|
|
@@ -106,12 +107,9 @@ function PortalPermissionsEditor({ values, setValue }: CrudFormGroupComponentPro
|
|
|
106
107
|
<div className="flex items-center justify-between border-b px-4 py-3">
|
|
107
108
|
<span className="text-sm font-semibold">{t(group.labelKey, group.fallback)}</span>
|
|
108
109
|
<label className="flex items-center gap-2 text-xs text-muted-foreground">
|
|
109
|
-
<
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
ref={(el) => { if (el) el.indeterminate = someSelected && !allSelected }}
|
|
113
|
-
onChange={() => handleGroupToggle(groupFeatures)}
|
|
114
|
-
className="rounded border-border"
|
|
110
|
+
<Checkbox
|
|
111
|
+
checked={allSelected ? true : (someSelected ? 'indeterminate' : false)}
|
|
112
|
+
onCheckedChange={() => handleGroupToggle(groupFeatures)}
|
|
115
113
|
/>
|
|
116
114
|
{t('customer_accounts.admin.roleDetail.selectAll', 'Select all')}
|
|
117
115
|
</label>
|
|
@@ -121,11 +119,10 @@ function PortalPermissionsEditor({ values, setValue }: CrudFormGroupComponentPro
|
|
|
121
119
|
const feature = PORTAL_FEATURES.find((portalFeature) => portalFeature.id === featureId)
|
|
122
120
|
return (
|
|
123
121
|
<label key={featureId} className="flex items-start gap-3 px-4 py-3 cursor-pointer hover:bg-muted/50 transition-colors">
|
|
124
|
-
<
|
|
125
|
-
type="checkbox"
|
|
122
|
+
<Checkbox
|
|
126
123
|
checked={features.includes(featureId)}
|
|
127
|
-
|
|
128
|
-
className="mt-0.5
|
|
124
|
+
onCheckedChange={() => handleFeatureToggle(featureId)}
|
|
125
|
+
className="mt-0.5"
|
|
129
126
|
/>
|
|
130
127
|
<div className="space-y-0.5">
|
|
131
128
|
<div className="text-sm font-medium">{feature ? t(feature.labelKey, feature.fallback) : featureId}</div>
|
|
@@ -191,20 +191,19 @@ function CreateUserDialog({
|
|
|
191
191
|
{roleOptions.map((role) => {
|
|
192
192
|
const isSelected = selectedRoleIds.includes(role.id)
|
|
193
193
|
return (
|
|
194
|
-
<
|
|
194
|
+
<Button
|
|
195
195
|
key={role.id}
|
|
196
196
|
type="button"
|
|
197
|
+
size="2xs"
|
|
198
|
+
variant={isSelected ? 'secondary' : 'outline'}
|
|
199
|
+
aria-pressed={isSelected}
|
|
197
200
|
onClick={() => setSelectedRoleIds((prev) =>
|
|
198
201
|
prev.includes(role.id) ? prev.filter((rid) => rid !== role.id) : [...prev, role.id],
|
|
199
202
|
)}
|
|
200
|
-
className=
|
|
201
|
-
isSelected
|
|
202
|
-
? 'border-primary bg-primary/10 text-primary'
|
|
203
|
-
: 'border-border bg-background text-muted-foreground hover:bg-muted'
|
|
204
|
-
}`}
|
|
203
|
+
className="rounded-full"
|
|
205
204
|
>
|
|
206
205
|
{role.label}
|
|
207
|
-
</
|
|
206
|
+
</Button>
|
|
208
207
|
)
|
|
209
208
|
})}
|
|
210
209
|
</div>
|
|
@@ -8,6 +8,7 @@ import { useT } from '@open-mercato/shared/lib/i18n/context'
|
|
|
8
8
|
import { Button } from '@open-mercato/ui/primitives/button'
|
|
9
9
|
import { Input } from '@open-mercato/ui/primitives/input'
|
|
10
10
|
import { EmailInput } from '@open-mercato/ui/primitives/email-input'
|
|
11
|
+
import { StatusBadge } from '@open-mercato/ui/primitives/status-badge'
|
|
11
12
|
import { flash } from '@open-mercato/ui/backend/FlashMessages'
|
|
12
13
|
|
|
13
14
|
interface AccountStatusData {
|
|
@@ -305,9 +306,9 @@ export default function AccountStatusWidget({ context }: AccountStatusProps) {
|
|
|
305
306
|
<div className="space-y-1 text-sm">
|
|
306
307
|
<div className="flex justify-between">
|
|
307
308
|
<span className="text-muted-foreground">{t('common.status', 'Status')}</span>
|
|
308
|
-
<
|
|
309
|
+
<StatusBadge variant={data.isActive ? 'success' : 'error'} dot>
|
|
309
310
|
{data.isActive ? t('common.active', 'Active') : t('common.inactive', 'Inactive')}
|
|
310
|
-
</
|
|
311
|
+
</StatusBadge>
|
|
311
312
|
</div>
|
|
312
313
|
<div className="flex justify-between">
|
|
313
314
|
<span className="text-muted-foreground">{t('common.email', 'Email')}</span>
|