@open-mercato/core 0.6.6-develop.6551.1.1511bfa890 → 0.6.6
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/dist/generated/entities.ids.generated.js +0 -1
- package/dist/generated/entities.ids.generated.js.map +2 -2
- package/dist/generated/entity-fields-registry.js +0 -12
- package/dist/generated/entity-fields-registry.js.map +2 -2
- package/dist/modules/api_keys/api/keys/route.js +13 -30
- package/dist/modules/api_keys/api/keys/route.js.map +2 -2
- package/dist/modules/api_keys/cli.js +1 -2
- package/dist/modules/api_keys/cli.js.map +2 -2
- package/dist/modules/attachments/api/file/[id]/route.js +7 -9
- package/dist/modules/attachments/api/file/[id]/route.js.map +2 -2
- package/dist/modules/attachments/api/image/[id]/[[...slug]]/route.js +7 -9
- package/dist/modules/attachments/api/image/[id]/[[...slug]]/route.js.map +2 -2
- package/dist/modules/attachments/api/route.js +17 -21
- package/dist/modules/attachments/api/route.js.map +2 -2
- package/dist/modules/attachments/components/AttachmentContentPreview.js +35 -6
- package/dist/modules/attachments/components/AttachmentContentPreview.js.map +2 -2
- package/dist/modules/audit_logs/backend/audit-logs/page.js +24 -14
- package/dist/modules/audit_logs/backend/audit-logs/page.js.map +2 -2
- package/dist/modules/auth/api/users/route.js +2 -6
- package/dist/modules/auth/api/users/route.js.map +2 -2
- package/dist/modules/auth/cli.js +2 -3
- package/dist/modules/auth/cli.js.map +2 -2
- package/dist/modules/configs/lib/upgrade-actions.js +0 -22
- package/dist/modules/configs/lib/upgrade-actions.js.map +2 -2
- package/dist/modules/customer_accounts/api/admin/roles/[id]/acl.js +0 -1
- package/dist/modules/customer_accounts/api/admin/roles/[id]/acl.js.map +2 -2
- package/dist/modules/customer_accounts/api/admin/roles/[id].js +3 -17
- package/dist/modules/customer_accounts/api/admin/roles/[id].js.map +2 -2
- package/dist/modules/customer_accounts/api/portal/users/[id]/roles.js +1 -6
- package/dist/modules/customer_accounts/api/portal/users/[id]/roles.js.map +2 -2
- package/dist/modules/customer_accounts/api/portal/users-invite.js +1 -6
- package/dist/modules/customer_accounts/api/portal/users-invite.js.map +2 -2
- package/dist/modules/customer_accounts/services/customerInvitationService.js +0 -1
- package/dist/modules/customer_accounts/services/customerInvitationService.js.map +2 -2
- package/dist/modules/customer_accounts/services/customerRbacService.js +1 -6
- package/dist/modules/customer_accounts/services/customerRbacService.js.map +2 -2
- package/dist/modules/customer_accounts/widgets/injection-table.js +2 -0
- package/dist/modules/customer_accounts/widgets/injection-table.js.map +2 -2
- package/dist/modules/customers/backend/customers/companies-v2/[id]/page.js +1 -7
- package/dist/modules/customers/backend/customers/companies-v2/[id]/page.js.map +2 -2
- package/dist/modules/customers/backend/customers/deals/pipeline/components/ViewTabsRow.js +2 -2
- package/dist/modules/customers/backend/customers/deals/pipeline/components/ViewTabsRow.js.map +2 -2
- package/dist/modules/customers/components/detail/CompanyDetailTabs.js +43 -37
- package/dist/modules/customers/components/detail/CompanyDetailTabs.js.map +2 -2
- package/dist/modules/customers/components/detail/DealDetailTabs.js +35 -23
- package/dist/modules/customers/components/detail/DealDetailTabs.js.map +2 -2
- package/dist/modules/customers/components/detail/DetailTabsLayout.js +21 -6
- package/dist/modules/customers/components/detail/DetailTabsLayout.js.map +2 -2
- package/dist/modules/customers/components/detail/MobilePersonDetail.js +32 -26
- package/dist/modules/customers/components/detail/MobilePersonDetail.js.map +2 -2
- package/dist/modules/customers/components/detail/PersonDetailTabs.js +39 -29
- package/dist/modules/customers/components/detail/PersonDetailTabs.js.map +2 -2
- package/dist/modules/dashboards/api/roles/widgets/route.js +3 -22
- package/dist/modules/dashboards/api/roles/widgets/route.js.map +2 -2
- package/dist/modules/dashboards/api/users/widgets/route.js +3 -22
- package/dist/modules/dashboards/api/users/widgets/route.js.map +2 -2
- package/dist/modules/dashboards/cli.js +3 -4
- package/dist/modules/dashboards/cli.js.map +2 -2
- package/dist/modules/dashboards/lib/widgetAssignmentScope.js +1 -9
- package/dist/modules/dashboards/lib/widgetAssignmentScope.js.map +2 -2
- package/dist/modules/dictionaries/commands/entries.js +14 -7
- package/dist/modules/dictionaries/commands/entries.js.map +2 -2
- package/dist/modules/dictionaries/commands/entry-operations.js +16 -7
- package/dist/modules/dictionaries/commands/entry-operations.js.map +2 -2
- package/dist/modules/dictionaries/commands/factory.js +3 -9
- package/dist/modules/dictionaries/commands/factory.js.map +2 -2
- package/dist/modules/dictionaries/fields/dictionary.js +41 -56
- package/dist/modules/dictionaries/fields/dictionary.js.map +2 -2
- package/dist/modules/directory/utils/organizationScope.js +3 -10
- package/dist/modules/directory/utils/organizationScope.js.map +2 -2
- package/dist/modules/entities/api/records.js +4 -5
- package/dist/modules/entities/api/records.js.map +2 -2
- package/dist/modules/entities/backend/entities/system/[entityId]/page.meta.js +0 -1
- package/dist/modules/entities/backend/entities/system/[entityId]/page.meta.js.map +2 -2
- package/dist/modules/entities/backend/entities/user/[entityId]/page.js +49 -49
- package/dist/modules/entities/backend/entities/user/[entityId]/page.js.map +2 -2
- package/dist/modules/entities/backend/entities/user/[entityId]/page.meta.js +0 -1
- package/dist/modules/entities/backend/entities/user/[entityId]/page.meta.js.map +2 -2
- package/dist/modules/entities/cli.js +1 -2
- package/dist/modules/entities/cli.js.map +2 -2
- package/dist/modules/feature_toggles/api/check/boolean/route.js +14 -0
- package/dist/modules/feature_toggles/api/check/boolean/route.js.map +2 -2
- package/dist/modules/feature_toggles/defaults.json +0 -8
- package/dist/modules/integrations/backend/integrations/[id]/page.js +80 -9
- package/dist/modules/integrations/backend/integrations/[id]/page.js.map +2 -2
- package/dist/modules/payment_gateways/data/entities.js +0 -45
- package/dist/modules/payment_gateways/data/entities.js.map +2 -2
- package/dist/modules/payment_gateways/lib/gateway-service.js +38 -173
- package/dist/modules/payment_gateways/lib/gateway-service.js.map +3 -3
- package/dist/modules/planner/backend/planner/availability-rulesets/[id]/page.js +14 -16
- package/dist/modules/planner/backend/planner/availability-rulesets/[id]/page.js.map +2 -2
- package/dist/modules/planner/components/AvailabilityRulesEditor.js +30 -18
- package/dist/modules/planner/components/AvailabilityRulesEditor.js.map +2 -2
- package/dist/modules/query_index/api/status.js +8 -2
- package/dist/modules/query_index/api/status.js.map +2 -2
- package/dist/modules/resources/backend/resources/resources/[id]/page.js +24 -24
- package/dist/modules/resources/backend/resources/resources/[id]/page.js.map +2 -2
- package/dist/modules/sales/backend/sales/channels/create/page.js +0 -6
- package/dist/modules/sales/backend/sales/channels/create/page.js.map +2 -2
- package/dist/modules/sales/backend/sales/channels/create/page.meta.js +0 -2
- package/dist/modules/sales/backend/sales/channels/create/page.meta.js.map +2 -2
- package/dist/modules/sales/backend/sales/channels/offers/page.js +0 -6
- package/dist/modules/sales/backend/sales/channels/offers/page.js.map +2 -2
- package/dist/modules/sales/backend/sales/channels/offers/page.meta.js +0 -2
- package/dist/modules/sales/backend/sales/channels/offers/page.meta.js.map +2 -2
- package/dist/modules/sales/backend/sales/channels/page.js +0 -6
- package/dist/modules/sales/backend/sales/channels/page.js.map +2 -2
- package/dist/modules/sales/backend/sales/channels/page.meta.js +0 -2
- package/dist/modules/sales/backend/sales/channels/page.meta.js.map +2 -2
- package/dist/modules/sales/backend/sales/documents/[id]/page.js +4 -6
- package/dist/modules/sales/backend/sales/documents/[id]/page.js.map +2 -2
- package/dist/modules/sales/commands/documents.js +0 -44
- package/dist/modules/sales/commands/documents.js.map +2 -2
- package/dist/modules/sales/commands/returns.js +27 -2
- package/dist/modules/sales/commands/returns.js.map +2 -2
- package/dist/modules/sales/components/documents/AddressesSection.js +2 -6
- package/dist/modules/sales/components/documents/AddressesSection.js.map +2 -2
- package/dist/modules/sales/components/documents/ItemsSection.js +0 -1
- package/dist/modules/sales/components/documents/ItemsSection.js.map +2 -2
- package/dist/modules/sales/components/documents/LineItemDialog.js +0 -9
- package/dist/modules/sales/components/documents/LineItemDialog.js.map +2 -2
- package/dist/modules/sales/components/documents/SalesDocumentForm.js +3 -51
- package/dist/modules/sales/components/documents/SalesDocumentForm.js.map +2 -2
- package/dist/modules/sales/components/documents/SalesDocumentsTable.js +8 -10
- package/dist/modules/sales/components/documents/SalesDocumentsTable.js.map +2 -2
- package/dist/modules/sales/components/documents/ShipmentDialog.js +38 -59
- package/dist/modules/sales/components/documents/ShipmentDialog.js.map +2 -2
- package/dist/modules/sales/lib/shipments/snapshots.js +1 -27
- package/dist/modules/sales/lib/shipments/snapshots.js.map +2 -2
- package/dist/modules/staff/backend/staff/team-members/[id]/page.js +25 -22
- package/dist/modules/staff/backend/staff/team-members/[id]/page.js.map +2 -2
- package/dist/modules/staff/backend/staff/teams/[id]/edit/page.js +14 -12
- package/dist/modules/staff/backend/staff/teams/[id]/edit/page.js.map +2 -2
- package/dist/modules/staff/lib/timesheets-projects-ui/SavedViewTabs.js +29 -10
- package/dist/modules/staff/lib/timesheets-projects-ui/SavedViewTabs.js.map +2 -2
- package/dist/modules/sync_excel/lib/adapters/customers.js +20 -19
- package/dist/modules/sync_excel/lib/adapters/customers.js.map +2 -2
- package/dist/modules/sync_excel/lib/parser.js +0 -185
- package/dist/modules/sync_excel/lib/parser.js.map +2 -2
- package/dist/modules/sync_excel/lib/upload-storage.js +1 -20
- package/dist/modules/sync_excel/lib/upload-storage.js.map +2 -2
- package/dist/modules/workflows/frontend/checkout-demo/page.js +8 -1
- package/dist/modules/workflows/frontend/checkout-demo/page.js.map +2 -2
- package/dist/modules/workflows/lib/activity-executor.js +1 -1
- package/dist/modules/workflows/lib/activity-executor.js.map +2 -2
- package/dist/modules/workflows/lib/find-definition.js +18 -2
- package/dist/modules/workflows/lib/find-definition.js.map +2 -2
- package/dist/modules/workflows/lib/signal-handler.js +3 -2
- package/dist/modules/workflows/lib/signal-handler.js.map +2 -2
- package/dist/modules/workflows/lib/step-handler.js +4 -8
- package/dist/modules/workflows/lib/step-handler.js.map +2 -2
- package/dist/modules/workflows/lib/task-handler.js +3 -5
- package/dist/modules/workflows/lib/task-handler.js.map +2 -2
- package/dist/modules/workflows/lib/timer-handler.js +2 -1
- package/dist/modules/workflows/lib/timer-handler.js.map +2 -2
- package/dist/modules/workflows/lib/transition-handler.js +5 -13
- package/dist/modules/workflows/lib/transition-handler.js.map +2 -2
- package/dist/modules/workflows/lib/workflow-executor.js +11 -9
- package/dist/modules/workflows/lib/workflow-executor.js.map +2 -2
- package/dist/modules/workflows/migrations/Migration20260715120000.js +68 -0
- package/dist/modules/workflows/migrations/Migration20260715120000.js.map +7 -0
- package/dist/modules/workflows/migrations/Migration20260716120000.js +24 -0
- package/dist/modules/workflows/migrations/Migration20260716120000.js.map +7 -0
- package/dist/modules/workflows/workflows.js +2 -0
- package/dist/modules/workflows/workflows.js.map +2 -2
- package/generated/entities.ids.generated.ts +0 -1
- package/generated/entity-fields-registry.ts +0 -12
- package/package.json +8 -9
- package/src/modules/api_keys/api/keys/route.ts +13 -36
- package/src/modules/api_keys/cli.ts +3 -2
- package/src/modules/attachments/api/file/[id]/route.ts +7 -11
- package/src/modules/attachments/api/image/[id]/[[...slug]]/route.ts +7 -11
- package/src/modules/attachments/api/route.ts +21 -26
- package/src/modules/attachments/components/AttachmentContentPreview.tsx +44 -9
- package/src/modules/audit_logs/backend/audit-logs/page.tsx +22 -12
- package/src/modules/auth/api/users/route.ts +2 -11
- package/src/modules/auth/cli.ts +2 -3
- package/src/modules/configs/i18n/de.json +1 -5
- package/src/modules/configs/i18n/en.json +1 -5
- package/src/modules/configs/i18n/es.json +1 -5
- package/src/modules/configs/i18n/pl.json +1 -5
- package/src/modules/configs/lib/upgrade-actions.ts +0 -24
- package/src/modules/customer_accounts/AGENTS.md +6 -8
- package/src/modules/customer_accounts/api/admin/roles/[id]/acl.ts +0 -1
- package/src/modules/customer_accounts/api/admin/roles/[id].ts +3 -17
- package/src/modules/customer_accounts/api/portal/users/[id]/roles.ts +1 -6
- package/src/modules/customer_accounts/api/portal/users-invite.ts +1 -6
- package/src/modules/customer_accounts/services/customerInvitationService.ts +0 -1
- package/src/modules/customer_accounts/services/customerRbacService.ts +2 -9
- package/src/modules/customer_accounts/widgets/injection-table.ts +2 -0
- package/src/modules/customers/backend/customers/companies-v2/[id]/page.tsx +1 -11
- package/src/modules/customers/backend/customers/deals/pipeline/components/ViewTabsRow.tsx +2 -6
- package/src/modules/customers/components/detail/CompanyDetailTabs.tsx +55 -39
- package/src/modules/customers/components/detail/DealDetailTabs.tsx +49 -24
- package/src/modules/customers/components/detail/DetailTabsLayout.tsx +24 -13
- package/src/modules/customers/components/detail/MobilePersonDetail.tsx +31 -25
- package/src/modules/customers/components/detail/PersonDetailTabs.tsx +50 -29
- package/src/modules/dashboards/api/roles/widgets/route.ts +3 -22
- package/src/modules/dashboards/api/users/widgets/route.ts +3 -22
- package/src/modules/dashboards/cli.ts +9 -4
- package/src/modules/dashboards/lib/widgetAssignmentScope.ts +0 -18
- package/src/modules/dictionaries/commands/entries.ts +16 -7
- package/src/modules/dictionaries/commands/entry-operations.ts +18 -8
- package/src/modules/dictionaries/commands/factory.ts +2 -8
- package/src/modules/dictionaries/fields/dictionary.tsx +32 -55
- package/src/modules/dictionaries/i18n/de.json +0 -2
- package/src/modules/dictionaries/i18n/en.json +0 -2
- package/src/modules/dictionaries/i18n/es.json +0 -2
- package/src/modules/dictionaries/i18n/pl.json +0 -2
- package/src/modules/directory/utils/organizationScope.ts +2 -36
- package/src/modules/entities/api/records.ts +7 -5
- package/src/modules/entities/backend/entities/system/[entityId]/page.meta.ts +0 -1
- package/src/modules/entities/backend/entities/user/[entityId]/page.meta.ts +0 -1
- package/src/modules/entities/backend/entities/user/[entityId]/page.tsx +49 -51
- package/src/modules/entities/cli.ts +1 -2
- package/src/modules/entities/i18n/de.json +0 -34
- package/src/modules/entities/i18n/en.json +0 -34
- package/src/modules/entities/i18n/es.json +0 -34
- package/src/modules/entities/i18n/pl.json +0 -34
- package/src/modules/feature_toggles/api/check/boolean/route.ts +15 -0
- package/src/modules/feature_toggles/defaults.json +0 -8
- package/src/modules/integrations/backend/integrations/[id]/page.tsx +59 -16
- package/src/modules/payment_gateways/data/entities.ts +0 -39
- package/src/modules/payment_gateways/lib/gateway-service.ts +40 -211
- package/src/modules/payment_gateways/migrations/.snapshot-open-mercato.json +0 -236
- package/src/modules/planner/backend/planner/availability-rulesets/[id]/page.tsx +20 -14
- package/src/modules/planner/components/AvailabilityRulesEditor.tsx +34 -16
- package/src/modules/query_index/api/status.ts +8 -2
- package/src/modules/resources/backend/resources/resources/[id]/page.tsx +37 -27
- package/src/modules/sales/backend/sales/channels/create/page.meta.ts +0 -3
- package/src/modules/sales/backend/sales/channels/create/page.tsx +0 -7
- package/src/modules/sales/backend/sales/channels/offers/page.meta.ts +0 -3
- package/src/modules/sales/backend/sales/channels/offers/page.tsx +0 -7
- package/src/modules/sales/backend/sales/channels/page.meta.ts +0 -4
- package/src/modules/sales/backend/sales/channels/page.tsx +0 -7
- package/src/modules/sales/backend/sales/documents/[id]/page.tsx +5 -7
- package/src/modules/sales/commands/documents.ts +0 -65
- package/src/modules/sales/commands/returns.ts +32 -2
- package/src/modules/sales/components/documents/AddressesSection.tsx +2 -6
- package/src/modules/sales/components/documents/ItemsSection.tsx +0 -5
- package/src/modules/sales/components/documents/LineItemDialog.tsx +0 -10
- package/src/modules/sales/components/documents/SalesDocumentForm.tsx +3 -53
- package/src/modules/sales/components/documents/SalesDocumentsTable.tsx +8 -10
- package/src/modules/sales/components/documents/ShipmentDialog.tsx +40 -65
- package/src/modules/sales/i18n/de.json +0 -5
- package/src/modules/sales/i18n/en.json +0 -5
- package/src/modules/sales/i18n/es.json +0 -5
- package/src/modules/sales/i18n/pl.json +0 -5
- package/src/modules/sales/lib/shipments/snapshots.ts +0 -30
- package/src/modules/staff/backend/staff/team-members/[id]/page.tsx +34 -25
- package/src/modules/staff/backend/staff/teams/[id]/edit/page.tsx +17 -11
- package/src/modules/staff/lib/timesheets-projects-ui/SavedViewTabs.tsx +28 -11
- package/src/modules/sync_excel/lib/adapters/customers.ts +22 -20
- package/src/modules/sync_excel/lib/parser.ts +0 -245
- package/src/modules/sync_excel/lib/upload-storage.ts +1 -23
- package/src/modules/workflows/frontend/checkout-demo/page.tsx +12 -1
- package/src/modules/workflows/lib/activity-executor.ts +22 -2
- package/src/modules/workflows/lib/find-definition.ts +53 -1
- package/src/modules/workflows/lib/signal-handler.ts +5 -4
- package/src/modules/workflows/lib/step-handler.ts +4 -8
- package/src/modules/workflows/lib/task-handler.ts +2 -4
- package/src/modules/workflows/lib/timer-handler.ts +3 -2
- package/src/modules/workflows/lib/transition-handler.ts +5 -13
- package/src/modules/workflows/lib/workflow-executor.ts +11 -8
- package/src/modules/workflows/migrations/Migration20260715120000.ts +114 -0
- package/src/modules/workflows/migrations/Migration20260716120000.ts +57 -0
- package/src/modules/workflows/workflows.ts +2 -0
- package/dist/generated/entities/gateway_session_initialization/index.js +0 -23
- package/dist/generated/entities/gateway_session_initialization/index.js.map +0 -7
- package/dist/modules/attachments/lib/reconcileOrganization.js +0 -110
- package/dist/modules/attachments/lib/reconcileOrganization.js.map +0 -7
- package/dist/modules/attachments/lib/requestScope.js +0 -10
- package/dist/modules/attachments/lib/requestScope.js.map +0 -7
- package/dist/modules/auth/api/autologin.js +0 -85
- package/dist/modules/auth/api/autologin.js.map +0 -7
- package/dist/modules/auth/lib/autologin.js +0 -19
- package/dist/modules/auth/lib/autologin.js.map +0 -7
- package/dist/modules/customers/components/detail/useDealsAccess.js +0 -16
- package/dist/modules/customers/components/detail/useDealsAccess.js.map +0 -7
- package/dist/modules/payment_gateways/lib/session-idempotency.js +0 -104
- package/dist/modules/payment_gateways/lib/session-idempotency.js.map +0 -7
- package/dist/modules/payment_gateways/migrations/Migration20260709220938_payment_gateways.js +0 -11
- package/dist/modules/payment_gateways/migrations/Migration20260709220938_payment_gateways.js.map +0 -7
- package/dist/modules/sales/components/SalesChannelsDisabledNotice.js +0 -15
- package/dist/modules/sales/components/SalesChannelsDisabledNotice.js.map +0 -7
- package/dist/modules/sales/components/useSalesChannelsEnabled.js +0 -44
- package/dist/modules/sales/components/useSalesChannelsEnabled.js.map +0 -7
- package/dist/modules/sales/lib/salesChannelsToggle.js +0 -18
- package/dist/modules/sales/lib/salesChannelsToggle.js.map +0 -7
- package/dist/modules/sales/lib/salesChannelsToggleId.js +0 -5
- package/dist/modules/sales/lib/salesChannelsToggleId.js.map +0 -7
- package/generated/entities/gateway_session_initialization/index.ts +0 -10
- package/src/modules/attachments/lib/reconcileOrganization.ts +0 -188
- package/src/modules/attachments/lib/requestScope.ts +0 -27
- package/src/modules/auth/api/autologin.ts +0 -100
- package/src/modules/auth/lib/autologin.ts +0 -36
- package/src/modules/customers/components/detail/useDealsAccess.ts +0 -19
- package/src/modules/payment_gateways/lib/session-idempotency.ts +0 -142
- package/src/modules/payment_gateways/migrations/Migration20260709220938_payment_gateways.ts +0 -10
- package/src/modules/sales/components/SalesChannelsDisabledNotice.tsx +0 -21
- package/src/modules/sales/components/useSalesChannelsEnabled.ts +0 -59
- package/src/modules/sales/lib/salesChannelsToggle.ts +0 -26
- package/src/modules/sales/lib/salesChannelsToggleId.ts +0 -1
|
@@ -22,7 +22,6 @@ import {
|
|
|
22
22
|
import { findOneWithDecryption, findWithDecryption } from '@open-mercato/shared/lib/encryption/find'
|
|
23
23
|
import { buildPasswordSchema } from '@open-mercato/shared/lib/auth/passwordPolicy'
|
|
24
24
|
import { escapeLikePattern } from '@open-mercato/shared/lib/db/escapeLikePattern'
|
|
25
|
-
import { parseBooleanFlag } from '@open-mercato/shared/lib/boolean'
|
|
26
25
|
import { resolveSearchConfig } from '@open-mercato/shared/lib/search/config'
|
|
27
26
|
import { tokenizeText } from '@open-mercato/shared/lib/search/tokenize'
|
|
28
27
|
import { sql } from 'kysely'
|
|
@@ -42,7 +41,6 @@ const querySchema = z.object({
|
|
|
42
41
|
search: z.string().optional(),
|
|
43
42
|
name: z.string().optional(),
|
|
44
43
|
organizationId: z.string().uuid().optional(),
|
|
45
|
-
scopeToActiveOrganization: z.boolean().optional(),
|
|
46
44
|
roleIds: z.array(z.string().uuid()).optional(),
|
|
47
45
|
}).passthrough()
|
|
48
46
|
|
|
@@ -182,7 +180,6 @@ export async function GET(req: Request) {
|
|
|
182
180
|
search: url.searchParams.get('search') || undefined,
|
|
183
181
|
name: url.searchParams.get('name') || undefined,
|
|
184
182
|
organizationId: url.searchParams.get('organizationId') || undefined,
|
|
185
|
-
scopeToActiveOrganization: parseBooleanFlag(url.searchParams.get('scopeToActiveOrganization') || undefined),
|
|
186
183
|
roleIds: rawRoleIds.length ? rawRoleIds : undefined,
|
|
187
184
|
})
|
|
188
185
|
if (!parsed.success) return NextResponse.json({ items: [], total: 0, totalPages: 1 })
|
|
@@ -198,7 +195,7 @@ export async function GET(req: Request) {
|
|
|
198
195
|
} catch (err) {
|
|
199
196
|
logger.error('Failed to resolve rbac', { err })
|
|
200
197
|
}
|
|
201
|
-
const { id, page, pageSize, search, name, organizationId,
|
|
198
|
+
const { id, page, pageSize, search, name, organizationId, roleIds } = parsed.data
|
|
202
199
|
const filters: any[] = [{ deletedAt: null }]
|
|
203
200
|
const actorTenantId = auth.tenantId ? String(auth.tenantId) : null
|
|
204
201
|
let effectiveTenantId: string | null = null
|
|
@@ -247,12 +244,6 @@ export async function GET(req: Request) {
|
|
|
247
244
|
? effectiveSelectedOrganizationId
|
|
248
245
|
: auth.orgId ?? null
|
|
249
246
|
if (organizationId) filters.push({ organizationId })
|
|
250
|
-
// Recipient/assignee pickers scope to the caller's active organization so they never
|
|
251
|
-
// suggest users outside it. A message composed here is stamped with the caller's
|
|
252
|
-
// active org (auth.orgId), and the message detail endpoint enforces
|
|
253
|
-
// hasOrganizationAccess(scope.organizationId, message.organizationId); scoping the
|
|
254
|
-
// suggestions to the same org keeps a picked recipient able to open what they were sent.
|
|
255
|
-
if (scopeToActiveOrganization) filters.push({ organizationId: auth.orgId ?? null })
|
|
256
247
|
const trimmedName = typeof name === 'string' ? name.trim() : ''
|
|
257
248
|
if (trimmedName) {
|
|
258
249
|
const searchPattern = `%${escapeLikePattern(trimmedName)}%`
|
|
@@ -629,7 +620,7 @@ export const openApi: OpenApiRouteDoc = {
|
|
|
629
620
|
GET: {
|
|
630
621
|
summary: 'List users',
|
|
631
622
|
description:
|
|
632
|
-
'Returns users for the effective selected tenant and organization scope. Search matches email, organization name, and role name. Super administrators may scope the response via the topbar context, organization filters, or role filters.
|
|
623
|
+
'Returns users for the effective selected tenant and organization scope. Search matches email, organization name, and role name. Super administrators may scope the response via the topbar context, organization filters, or role filters.',
|
|
633
624
|
query: querySchema,
|
|
634
625
|
responses: [
|
|
635
626
|
{ status: 200, description: 'User collection', schema: userListResponseSchema },
|
package/src/modules/auth/cli.ts
CHANGED
|
@@ -9,7 +9,6 @@ import { Tenant, Organization } from '@open-mercato/core/modules/directory/data/
|
|
|
9
9
|
import { rebuildHierarchyForTenant } from '@open-mercato/core/modules/directory/lib/hierarchy'
|
|
10
10
|
import { ensureRoles, setupInitialTenant, ensureDefaultRoleAcls, ensureCustomRoleAcls, OrgSlugExistsError, DerivedUserPasswordRequiredError } from './lib/setup-app'
|
|
11
11
|
import { normalizeTenantId } from './lib/tenantAccess'
|
|
12
|
-
import { parseCommaSeparatedList } from '@open-mercato/shared/lib/string'
|
|
13
12
|
import { computeEmailHash, emailHashLookupValues } from './lib/emailHash'
|
|
14
13
|
import { findWithDecryption, findOneWithDecryption } from '@open-mercato/shared/lib/encryption/find'
|
|
15
14
|
import { isTenantDataEncryptionEnabled } from '@open-mercato/shared/lib/encryption/toggles'
|
|
@@ -72,7 +71,7 @@ const addUser: ModuleCli = {
|
|
|
72
71
|
})
|
|
73
72
|
await em.persist(u).flush()
|
|
74
73
|
if (rolesCsv) {
|
|
75
|
-
const names =
|
|
74
|
+
const names = rolesCsv.split(',').map(s => s.trim()).filter(Boolean)
|
|
76
75
|
for (const name of names) {
|
|
77
76
|
const role = await resolveTenantScopedRole(em, name, normalizedTenantId)
|
|
78
77
|
const link = em.create(UserRole, { user: u, role })
|
|
@@ -494,7 +493,7 @@ const setupApp: ModuleCli = {
|
|
|
494
493
|
const container = await createRequestContainer()
|
|
495
494
|
const em = container.resolve<EntityManager>('em')
|
|
496
495
|
const roleNames = rolesCsv
|
|
497
|
-
?
|
|
496
|
+
? rolesCsv.split(',').map((s) => s.trim()).filter(Boolean)
|
|
498
497
|
: undefined
|
|
499
498
|
|
|
500
499
|
try {
|
|
@@ -189,9 +189,5 @@
|
|
|
189
189
|
"configs.systemStatus.variables.queryIndexWarmupThrottleMs.label": "Warmup-Drosselfenster",
|
|
190
190
|
"configs.systemStatus.variables.scheduleAutoReindex.description": "Automatisch Query-Index-Neuindizierungsaufträge bei Lücken planen.",
|
|
191
191
|
"configs.systemStatus.variables.scheduleAutoReindex.label": "Automatische Neuindizierung",
|
|
192
|
-
"configs.systemStatus.viewDocs": "Dokumentation anzeigen"
|
|
193
|
-
"configs.upgrades.attachmentsOrgReconcile.cta": "Anhang-Organisationen abgleichen",
|
|
194
|
-
"configs.upgrades.attachmentsOrgReconcile.loading": "Anhang-Organisationen werden abgeglichen…",
|
|
195
|
-
"configs.upgrades.attachmentsOrgReconcile.message": "Version {{version}} behebt Anhänge, die unter der falschen Organisation gespeichert wurden. Führen Sie den Abgleich aus, um vorhandene Anhänge in die Organisation des zugehörigen Datensatzes zu verschieben.",
|
|
196
|
-
"configs.upgrades.attachmentsOrgReconcile.success": "Anhang-Organisationen abgeglichen."
|
|
192
|
+
"configs.systemStatus.viewDocs": "Dokumentation anzeigen"
|
|
197
193
|
}
|
|
@@ -189,9 +189,5 @@
|
|
|
189
189
|
"configs.systemStatus.variables.queryIndexWarmupThrottleMs.label": "Warmup throttle window",
|
|
190
190
|
"configs.systemStatus.variables.scheduleAutoReindex.description": "Automatically schedule query index reindex jobs when gaps appear.",
|
|
191
191
|
"configs.systemStatus.variables.scheduleAutoReindex.label": "Auto reindex",
|
|
192
|
-
"configs.systemStatus.viewDocs": "View documentation"
|
|
193
|
-
"configs.upgrades.attachmentsOrgReconcile.cta": "Reconcile attachment organizations",
|
|
194
|
-
"configs.upgrades.attachmentsOrgReconcile.loading": "Reconciling attachment organizations…",
|
|
195
|
-
"configs.upgrades.attachmentsOrgReconcile.message": "Version {{version}} fixes attachments that were saved under the wrong organization. Run the reconciliation to move existing attachments to the organization of the record they belong to.",
|
|
196
|
-
"configs.upgrades.attachmentsOrgReconcile.success": "Attachment organizations reconciled."
|
|
192
|
+
"configs.systemStatus.viewDocs": "View documentation"
|
|
197
193
|
}
|
|
@@ -189,9 +189,5 @@
|
|
|
189
189
|
"configs.systemStatus.variables.queryIndexWarmupThrottleMs.label": "Ventana de limitación del calentamiento",
|
|
190
190
|
"configs.systemStatus.variables.scheduleAutoReindex.description": "Programar automáticamente trabajos de reindexación cuando se detecten brechas.",
|
|
191
191
|
"configs.systemStatus.variables.scheduleAutoReindex.label": "Reindexación automática",
|
|
192
|
-
"configs.systemStatus.viewDocs": "Ver documentación"
|
|
193
|
-
"configs.upgrades.attachmentsOrgReconcile.cta": "Reconciliar organizaciones de adjuntos",
|
|
194
|
-
"configs.upgrades.attachmentsOrgReconcile.loading": "Reconciliando organizaciones de adjuntos…",
|
|
195
|
-
"configs.upgrades.attachmentsOrgReconcile.message": "La versión {{version}} corrige los adjuntos guardados en la organización incorrecta. Ejecuta la reconciliación para mover los adjuntos existentes a la organización del registro al que pertenecen.",
|
|
196
|
-
"configs.upgrades.attachmentsOrgReconcile.success": "Organizaciones de adjuntos reconciliadas."
|
|
192
|
+
"configs.systemStatus.viewDocs": "Ver documentación"
|
|
197
193
|
}
|
|
@@ -189,9 +189,5 @@
|
|
|
189
189
|
"configs.systemStatus.variables.queryIndexWarmupThrottleMs.label": "Okno throttlingu rozgrzewki",
|
|
190
190
|
"configs.systemStatus.variables.scheduleAutoReindex.description": "Automatycznie uruchamia przebudowę indeksu zapytań, gdy wykryte zostaną luki.",
|
|
191
191
|
"configs.systemStatus.variables.scheduleAutoReindex.label": "Automatyczna przebudowa indeksu",
|
|
192
|
-
"configs.systemStatus.viewDocs": "Zobacz dokumentację"
|
|
193
|
-
"configs.upgrades.attachmentsOrgReconcile.cta": "Uzgodnij organizacje załączników",
|
|
194
|
-
"configs.upgrades.attachmentsOrgReconcile.loading": "Uzgadnianie organizacji załączników…",
|
|
195
|
-
"configs.upgrades.attachmentsOrgReconcile.message": "Wersja {{version}} naprawia załączniki zapisane pod niewłaściwą organizacją. Uruchom uzgadnianie, aby przenieść istniejące załączniki do organizacji rekordu, do którego należą.",
|
|
196
|
-
"configs.upgrades.attachmentsOrgReconcile.success": "Organizacje załączników zostały uzgodnione."
|
|
192
|
+
"configs.systemStatus.viewDocs": "Zobacz dokumentację"
|
|
197
193
|
}
|
|
@@ -1,11 +1,6 @@
|
|
|
1
1
|
import type { EntityManager } from '@mikro-orm/postgresql'
|
|
2
2
|
import * as semver from 'semver'
|
|
3
3
|
import type { AppContainer } from '@open-mercato/shared/lib/di/container'
|
|
4
|
-
import { createLogger } from '@open-mercato/shared/lib/logger'
|
|
5
|
-
import type { QueryEngine } from '@open-mercato/shared/lib/query/types'
|
|
6
|
-
import { reconcileAttachmentOrganizations } from '@open-mercato/core/modules/attachments/lib/reconcileOrganization'
|
|
7
|
-
|
|
8
|
-
const logger = createLogger('configs').child({ component: 'upgrade-actions' })
|
|
9
4
|
|
|
10
5
|
export type UpgradeActionContext = {
|
|
11
6
|
tenantId: string
|
|
@@ -43,25 +38,6 @@ export function compareVersions(a: string, b: string): number {
|
|
|
43
38
|
}
|
|
44
39
|
|
|
45
40
|
export const upgradeActions: UpgradeActionDefinition[] = [
|
|
46
|
-
{
|
|
47
|
-
id: 'attachments.reconcile-organization',
|
|
48
|
-
version: '0.6.6',
|
|
49
|
-
messageKey: 'configs.upgrades.attachmentsOrgReconcile.message',
|
|
50
|
-
ctaKey: 'configs.upgrades.attachmentsOrgReconcile.cta',
|
|
51
|
-
successKey: 'configs.upgrades.attachmentsOrgReconcile.success',
|
|
52
|
-
loadingKey: 'configs.upgrades.attachmentsOrgReconcile.loading',
|
|
53
|
-
async run({ container, em, tenantId }) {
|
|
54
|
-
const queryEngine = container.resolve('queryEngine') as QueryEngine
|
|
55
|
-
const report = await reconcileAttachmentOrganizations({ em, queryEngine, tenantId })
|
|
56
|
-
logger.info('attachments organization reconcile completed', {
|
|
57
|
-
tenantId,
|
|
58
|
-
scanned: report.scanned,
|
|
59
|
-
updated: report.updated,
|
|
60
|
-
unresolved: report.unresolved,
|
|
61
|
-
skippedVirtual: report.skippedVirtual,
|
|
62
|
-
})
|
|
63
|
-
},
|
|
64
|
-
},
|
|
65
41
|
{
|
|
66
42
|
id: 'customers.seed-interaction-statuses',
|
|
67
43
|
version: '0.6.5',
|
|
@@ -306,17 +306,15 @@ Both link to `/backend/customer_accounts/{sourceEntityId}` for staff review.
|
|
|
306
306
|
|
|
307
307
|
| Spot ID | Widget | Purpose |
|
|
308
308
|
|---------|--------|---------|
|
|
309
|
-
| `customers.person` | `account-status` |
|
|
310
|
-
| `crud-form:customers.person` | `account-status` |
|
|
311
|
-
| `customers
|
|
312
|
-
| `
|
|
309
|
+
| `customers.person` | `account-status` | Shows portal account status on Customers v2 person detail forms |
|
|
310
|
+
| `crud-form:customers.person` | `account-status` | Alias for CrudForm hosts deriving the spot from `customers.person` |
|
|
311
|
+
| `crud-form:customers:customer_person_profile:fields` | `account-status` | Shows portal account status on CRM person detail page |
|
|
312
|
+
| `customers.company` | `company-users` | Shows portal users on Customers v2 company detail forms |
|
|
313
|
+
| `crud-form:customers.company` | `company-users` | Alias for CrudForm hosts deriving the spot from `customers.company` |
|
|
314
|
+
| `crud-form:customers:customer_company_profile:fields` | `company-users` | Shows portal users linked to a CRM company |
|
|
313
315
|
|
|
314
316
|
Both inject as column 2 groups with priority 200, gated by `customer_accounts.view` feature.
|
|
315
317
|
|
|
316
|
-
CrudForm derives its spot id as `crud-form:${entityId}` with every `:` normalized to `.`, so a
|
|
317
|
-
registered `crud-form:` key whose entity segment still contains `:` can never be requested by any
|
|
318
|
-
host. Register against the normalized (dot) form only — `injection-table.test.ts` enforces this.
|
|
319
|
-
|
|
320
318
|
## Backend Pages
|
|
321
319
|
|
|
322
320
|
| Path | Purpose |
|
|
@@ -36,7 +36,6 @@ export async function GET(req: Request, { params }: { params: { id: string } })
|
|
|
36
36
|
const role = await em.findOne(CustomerRole, {
|
|
37
37
|
id: params.id,
|
|
38
38
|
tenantId: auth.tenantId,
|
|
39
|
-
organizationId: auth.orgId,
|
|
40
39
|
deletedAt: null,
|
|
41
40
|
})
|
|
42
41
|
if (!role) {
|
|
@@ -95,7 +94,6 @@ export async function PUT(req: Request, { params }: { params: { id: string } })
|
|
|
95
94
|
const role = await em.findOne(CustomerRole, {
|
|
96
95
|
id: params.id,
|
|
97
96
|
tenantId: auth.tenantId,
|
|
98
|
-
organizationId: auth.orgId,
|
|
99
97
|
deletedAt: null,
|
|
100
98
|
})
|
|
101
99
|
if (!role) {
|
|
@@ -129,11 +127,7 @@ export async function PUT(req: Request, { params }: { params: { id: string } })
|
|
|
129
127
|
if (parsed.data.isDefault !== undefined) updates.isDefault = parsed.data.isDefault
|
|
130
128
|
if (parsed.data.customerAssignable !== undefined) updates.customerAssignable = parsed.data.customerAssignable
|
|
131
129
|
|
|
132
|
-
await em.nativeUpdate(CustomerRole, {
|
|
133
|
-
id: role.id,
|
|
134
|
-
tenantId: auth.tenantId,
|
|
135
|
-
organizationId: auth.orgId,
|
|
136
|
-
}, updates)
|
|
130
|
+
await em.nativeUpdate(CustomerRole, { id: role.id }, updates)
|
|
137
131
|
|
|
138
132
|
void emitCustomerAccountsEvent('customer_accounts.role.updated', {
|
|
139
133
|
id: role.id,
|
|
@@ -163,7 +157,6 @@ export async function DELETE(req: Request, { params }: { params: { id: string }
|
|
|
163
157
|
const role = await em.findOne(CustomerRole, {
|
|
164
158
|
id: params.id,
|
|
165
159
|
tenantId: auth.tenantId,
|
|
166
|
-
organizationId: auth.orgId,
|
|
167
160
|
deletedAt: null,
|
|
168
161
|
})
|
|
169
162
|
if (!role) {
|
|
@@ -198,15 +191,8 @@ export async function DELETE(req: Request, { params }: { params: { id: string }
|
|
|
198
191
|
return NextResponse.json({ ok: false, error: `Cannot delete role with ${assignedUsersCount} assigned user(s). Reassign users first.` }, { status: 400 })
|
|
199
192
|
}
|
|
200
193
|
|
|
201
|
-
await em.nativeUpdate(CustomerRole, {
|
|
202
|
-
|
|
203
|
-
tenantId: auth.tenantId,
|
|
204
|
-
organizationId: auth.orgId,
|
|
205
|
-
}, { deletedAt: new Date() })
|
|
206
|
-
await em.nativeUpdate(CustomerRoleAcl, {
|
|
207
|
-
role: role.id as any,
|
|
208
|
-
tenantId: auth.tenantId,
|
|
209
|
-
}, { deletedAt: new Date() })
|
|
194
|
+
await em.nativeUpdate(CustomerRole, { id: role.id }, { deletedAt: new Date() })
|
|
195
|
+
await em.nativeUpdate(CustomerRoleAcl, { role: role.id as any }, { deletedAt: new Date() })
|
|
210
196
|
|
|
211
197
|
void emitCustomerAccountsEvent('customer_accounts.role.deleted', {
|
|
212
198
|
id: role.id,
|
|
@@ -60,12 +60,7 @@ export async function PUT(req: Request, { params }: { params: { id: string } })
|
|
|
60
60
|
? await findWithDecryption(
|
|
61
61
|
em,
|
|
62
62
|
CustomerRole,
|
|
63
|
-
{
|
|
64
|
-
id: { $in: requestedRoleIds },
|
|
65
|
-
tenantId: auth.tenantId,
|
|
66
|
-
organizationId: auth.orgId,
|
|
67
|
-
deletedAt: null,
|
|
68
|
-
} as any,
|
|
63
|
+
{ id: { $in: requestedRoleIds }, tenantId: auth.tenantId, deletedAt: null } as any,
|
|
69
64
|
undefined,
|
|
70
65
|
{ tenantId: auth.tenantId, organizationId: auth.orgId },
|
|
71
66
|
)
|
|
@@ -67,12 +67,7 @@ export async function POST(req: Request) {
|
|
|
67
67
|
? await findWithDecryption(
|
|
68
68
|
em,
|
|
69
69
|
CustomerRole,
|
|
70
|
-
{
|
|
71
|
-
id: { $in: requestedRoleIds },
|
|
72
|
-
tenantId: auth.tenantId,
|
|
73
|
-
organizationId: auth.orgId,
|
|
74
|
-
deletedAt: null,
|
|
75
|
-
} as any,
|
|
70
|
+
{ id: { $in: requestedRoleIds }, tenantId: auth.tenantId, deletedAt: null } as any,
|
|
76
71
|
undefined,
|
|
77
72
|
{ tenantId: auth.tenantId, organizationId: auth.orgId },
|
|
78
73
|
)
|
|
@@ -29,9 +29,7 @@ export class CustomerRbacService {
|
|
|
29
29
|
}
|
|
30
30
|
|
|
31
31
|
private getCacheKey(userId: string, scope: { tenantId: string; organizationId: string }): string {
|
|
32
|
-
|
|
33
|
-
// before scope hardening cannot preserve grants that are no longer valid.
|
|
34
|
-
return `customer_rbac:v2:${userId}:${scope.tenantId}:${scope.organizationId}`
|
|
32
|
+
return `customer_rbac:${userId}:${scope.tenantId}:${scope.organizationId}`
|
|
35
33
|
}
|
|
36
34
|
|
|
37
35
|
private getUserTag(userId: string): string {
|
|
@@ -91,13 +89,8 @@ export class CustomerRbacService {
|
|
|
91
89
|
// Aggregate role ACLs
|
|
92
90
|
const links = await em.find(CustomerUserRole, {
|
|
93
91
|
user: userId as any,
|
|
94
|
-
role: {
|
|
95
|
-
tenantId: scope.tenantId,
|
|
96
|
-
organizationId: scope.organizationId,
|
|
97
|
-
deletedAt: null,
|
|
98
|
-
},
|
|
99
92
|
deletedAt: null,
|
|
100
|
-
}
|
|
93
|
+
}, { populate: ['role'] })
|
|
101
94
|
const roleIds = links.map((l) => (l.role as any)?.id).filter(Boolean)
|
|
102
95
|
|
|
103
96
|
let isPortalAdmin = false
|
|
@@ -19,8 +19,10 @@ const companyUsersWidget = {
|
|
|
19
19
|
export const injectionTable: ModuleInjectionTable = {
|
|
20
20
|
'customers.person': [accountStatusWidget],
|
|
21
21
|
'crud-form:customers.person': [accountStatusWidget],
|
|
22
|
+
'crud-form:customers:customer_person_profile:fields': [accountStatusWidget],
|
|
22
23
|
'customers.company': [companyUsersWidget],
|
|
23
24
|
'crud-form:customers.company': [companyUsersWidget],
|
|
25
|
+
'crud-form:customers:customer_company_profile:fields': [companyUsersWidget],
|
|
24
26
|
// Step 4.10 — Portal AiChat injection example.
|
|
25
27
|
// Mapped to the portal profile page's `pageAfter('profile')` spot;
|
|
26
28
|
// third-party modules targeting other portal pages can copy this entry.
|
|
@@ -31,7 +31,6 @@ import type { TagsSectionController } from '@open-mercato/ui/backend/detail'
|
|
|
31
31
|
import { coerceDisplayName } from '../../../../lib/displayName'
|
|
32
32
|
import { CompanyDetailHeader } from '../../../../components/detail/CompanyDetailHeader'
|
|
33
33
|
import { CompanyDetailTabs, resolveLegacyTab, type CompanyTabId } from '../../../../components/detail/CompanyDetailTabs'
|
|
34
|
-
import { useDealsAccess } from '../../../../components/detail/useDealsAccess'
|
|
35
34
|
import { CompanyKpiBar } from '../../../../components/detail/CompanyKpiBar'
|
|
36
35
|
import { ScheduleActivityDialog, type ScheduleActivityEditData } from '../../../../components/detail/ScheduleActivityDialog'
|
|
37
36
|
import { ChangelogTab } from '../../../../components/detail/ChangelogTab'
|
|
@@ -70,7 +69,6 @@ export default function CompanyDetailV2Page({ params }: { params?: { id?: string
|
|
|
70
69
|
}, [searchParams])
|
|
71
70
|
const [activeTab, setActiveTab] = React.useState<CompanyTabId>(initialTab)
|
|
72
71
|
const [sectionAction, setSectionAction] = React.useState<SectionAction | null>(null)
|
|
73
|
-
const { canViewDeals, isReady: isDealsAccessReady } = useDealsAccess()
|
|
74
72
|
|
|
75
73
|
// Form state
|
|
76
74
|
const [isDirty, setIsDirty] = React.useState(false)
|
|
@@ -330,14 +328,6 @@ export default function CompanyDetailV2Page({ params }: { params?: { id?: string
|
|
|
330
328
|
setSectionAction(null)
|
|
331
329
|
}, [activeTab])
|
|
332
330
|
|
|
333
|
-
// A `?tab=deals` deep link must not strand users without `customers.deals.view`
|
|
334
|
-
// on a tab that no longer exists for them. Wait for the granted features to load
|
|
335
|
-
// so a permitted user is never bounced off the tab mid-fetch.
|
|
336
|
-
React.useEffect(() => {
|
|
337
|
-
if (!isDealsAccessReady || canViewDeals) return
|
|
338
|
-
setActiveTab((current) => (current === 'deals' ? 'people' : current))
|
|
339
|
-
}, [isDealsAccessReady, canViewDeals])
|
|
340
|
-
|
|
341
331
|
// Deals scope
|
|
342
332
|
const dealsScope = React.useMemo(
|
|
343
333
|
() => (currentCompanyId ? ({ kind: 'company', entityId: currentCompanyId } as const) : null),
|
|
@@ -554,7 +544,7 @@ export default function CompanyDetailV2Page({ params }: { params?: { id?: string
|
|
|
554
544
|
/>
|
|
555
545
|
)}
|
|
556
546
|
|
|
557
|
-
{activeTab === 'deals' &&
|
|
547
|
+
{activeTab === 'deals' && (
|
|
558
548
|
<DealsSection
|
|
559
549
|
scope={dealsScope}
|
|
560
550
|
emptyLabel={t('customers.companies.detail.empty.deals', 'No deals linked to this company.')}
|
|
@@ -24,13 +24,9 @@ export function ViewTabsRow({ active, className }: ViewTabsRowProps): React.Reac
|
|
|
24
24
|
map: translateWithFallback(t, 'customers.deals.kanban.view.map', 'Map'),
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
-
// Link-based tab row (two routes), so the Tabs primitive (state-driven,
|
|
28
|
-
// onValueChange) does not fit — real <Link> semantics must stay. Classes
|
|
29
|
-
// mirror the Tabs underline variant: accent-indigo active border,
|
|
30
|
-
// shadow-focus halo.
|
|
31
27
|
const baseTab =
|
|
32
|
-
'inline-flex items-center px-3.5 py-2.5 text-sm leading-normal transition-colors focus-visible:outline-none focus-visible:
|
|
33
|
-
const activeTab = 'border-b-2 border-
|
|
28
|
+
'inline-flex items-center px-3.5 py-2.5 text-sm leading-normal transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2'
|
|
29
|
+
const activeTab = 'border-b-2 border-foreground font-semibold text-foreground'
|
|
34
30
|
const inactiveTab = 'border-b-2 border-transparent font-normal text-muted-foreground hover:text-foreground'
|
|
35
31
|
|
|
36
32
|
// Renders the active tab as a non-navigating `<span>` and the inactive tab as a `<Link>`,
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
"use client"
|
|
2
2
|
|
|
3
3
|
import * as React from 'react'
|
|
4
|
+
import { cn } from '@open-mercato/shared/lib/utils'
|
|
4
5
|
import { useT } from '@open-mercato/shared/lib/i18n/context'
|
|
5
6
|
import { Button } from '@open-mercato/ui/primitives/button'
|
|
6
|
-
import {
|
|
7
|
+
import { Badge } from '@open-mercato/ui/primitives/badge'
|
|
7
8
|
import {
|
|
8
9
|
Users,
|
|
9
10
|
Handshake,
|
|
@@ -13,7 +14,6 @@ import {
|
|
|
13
14
|
Plus,
|
|
14
15
|
} from 'lucide-react'
|
|
15
16
|
import type { SectionAction } from '@open-mercato/ui/backend/detail'
|
|
16
|
-
import { useDealsAccess } from './useDealsAccess'
|
|
17
17
|
|
|
18
18
|
export type CompanyTabId =
|
|
19
19
|
| 'people'
|
|
@@ -27,7 +27,7 @@ type TabDef = {
|
|
|
27
27
|
id: CompanyTabId
|
|
28
28
|
label: string
|
|
29
29
|
icon?: React.ReactNode
|
|
30
|
-
|
|
30
|
+
badge?: React.ReactNode
|
|
31
31
|
}
|
|
32
32
|
|
|
33
33
|
type CompanyDetailTabsProps = {
|
|
@@ -58,9 +58,21 @@ export function resolveLegacyTab(tab: string | null | undefined): CompanyTabId {
|
|
|
58
58
|
return tab as CompanyTabId
|
|
59
59
|
}
|
|
60
60
|
|
|
61
|
-
function
|
|
62
|
-
|
|
63
|
-
|
|
61
|
+
function NewBadge() {
|
|
62
|
+
return (
|
|
63
|
+
<span className="ml-1.5 rounded bg-foreground px-1.5 py-0.5 text-overline font-semibold leading-none text-background">
|
|
64
|
+
NEW
|
|
65
|
+
</span>
|
|
66
|
+
)
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function CountBadge({ count }: { count: number }) {
|
|
70
|
+
if (count <= 0) return null
|
|
71
|
+
return (
|
|
72
|
+
<span className="ml-1.5 rounded-full bg-muted px-1.5 py-0.5 text-xs font-medium leading-none text-muted-foreground">
|
|
73
|
+
{count > 999 ? '999+' : count}
|
|
74
|
+
</span>
|
|
75
|
+
)
|
|
64
76
|
}
|
|
65
77
|
|
|
66
78
|
export function CompanyDetailTabs({
|
|
@@ -75,7 +87,6 @@ export function CompanyDetailTabs({
|
|
|
75
87
|
children,
|
|
76
88
|
}: CompanyDetailTabsProps) {
|
|
77
89
|
const t = useT()
|
|
78
|
-
const { canViewDeals } = useDealsAccess()
|
|
79
90
|
|
|
80
91
|
const builtInTabs: TabDef[] = React.useMemo(
|
|
81
92
|
() => [
|
|
@@ -83,38 +94,34 @@ export function CompanyDetailTabs({
|
|
|
83
94
|
id: 'people',
|
|
84
95
|
label: t('customers.companies.detail.tabs.people', 'People'),
|
|
85
96
|
icon: <Users className="size-4" />,
|
|
86
|
-
|
|
97
|
+
badge: <CountBadge count={peopleCount} />,
|
|
98
|
+
},
|
|
99
|
+
{
|
|
100
|
+
id: 'deals',
|
|
101
|
+
label: t('customers.companies.detail.tabs.deals', 'Deals'),
|
|
102
|
+
icon: <Handshake className="size-4" />,
|
|
103
|
+
badge: <CountBadge count={dealsCount} />,
|
|
87
104
|
},
|
|
88
|
-
...(canViewDeals
|
|
89
|
-
? [
|
|
90
|
-
{
|
|
91
|
-
id: 'deals' as CompanyTabId,
|
|
92
|
-
label: t('customers.companies.detail.tabs.deals', 'Deals'),
|
|
93
|
-
icon: <Handshake className="size-4" />,
|
|
94
|
-
count: formatTabCount(dealsCount),
|
|
95
|
-
},
|
|
96
|
-
]
|
|
97
|
-
: []),
|
|
98
105
|
{
|
|
99
106
|
id: 'activity-log',
|
|
100
107
|
label: t('customers.companies.detail.tabs.activityLog', 'Activity log'),
|
|
101
108
|
icon: <Clock className="size-4" />,
|
|
102
|
-
|
|
109
|
+
badge: <CountBadge count={activitiesCount} />,
|
|
103
110
|
},
|
|
104
111
|
{
|
|
105
112
|
id: 'changelog',
|
|
106
113
|
label: t('customers.companies.detail.tabs.changelog', 'Changelog'),
|
|
107
114
|
icon: <History className="size-4" />,
|
|
108
|
-
|
|
115
|
+
badge: <NewBadge />,
|
|
109
116
|
},
|
|
110
117
|
{
|
|
111
118
|
id: 'files',
|
|
112
119
|
label: t('customers.companies.detail.tabs.files', 'Files'),
|
|
113
120
|
icon: <Paperclip className="size-4" />,
|
|
114
|
-
|
|
121
|
+
badge: <CountBadge count={filesCount} />,
|
|
115
122
|
},
|
|
116
123
|
],
|
|
117
|
-
[t,
|
|
124
|
+
[t, peopleCount, dealsCount, activitiesCount, filesCount],
|
|
118
125
|
)
|
|
119
126
|
|
|
120
127
|
const allTabs: TabDef[] = React.useMemo(
|
|
@@ -131,24 +138,33 @@ export function CompanyDetailTabs({
|
|
|
131
138
|
return (
|
|
132
139
|
<div>
|
|
133
140
|
{/* Tab navigation */}
|
|
134
|
-
<div className="flex items-end justify-between gap-2 border-b">
|
|
135
|
-
<
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
141
|
+
<div className="flex items-end justify-between gap-2 border-b" role="tablist" aria-label={t('customers.companies.detail.tabs.label', 'Company detail sections')}>
|
|
142
|
+
<nav className="-mb-px flex flex-1 gap-1 overflow-x-auto px-1">
|
|
143
|
+
{allTabs.map((tab) => {
|
|
144
|
+
const isActive = activeTab === tab.id
|
|
145
|
+
return (
|
|
146
|
+
<Button
|
|
147
|
+
key={tab.id}
|
|
148
|
+
type="button"
|
|
149
|
+
variant="ghost"
|
|
150
|
+
size="sm"
|
|
151
|
+
role="tab"
|
|
152
|
+
aria-selected={isActive}
|
|
153
|
+
onClick={() => onTabChange(tab.id)}
|
|
154
|
+
className={cn(
|
|
155
|
+
'h-auto shrink-0 rounded-none border-b-2 px-3 py-2.5 hover:bg-transparent',
|
|
156
|
+
isActive
|
|
157
|
+
? 'border-foreground text-foreground font-semibold'
|
|
158
|
+
: 'border-transparent text-muted-foreground hover:text-foreground',
|
|
159
|
+
)}
|
|
160
|
+
>
|
|
161
|
+
{tab.icon && <span className="mr-1.5">{tab.icon}</span>}
|
|
147
162
|
{tab.label}
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
163
|
+
{tab.badge}
|
|
164
|
+
</Button>
|
|
165
|
+
)
|
|
166
|
+
})}
|
|
167
|
+
</nav>
|
|
152
168
|
{sectionAction ? (
|
|
153
169
|
<Button
|
|
154
170
|
type="button"
|