@open-mercato/core 0.8.1-develop.7275.1.f772b944d4 → 0.8.1-develop.7294.1.0ef99fc518
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/auth/api/users/acl/route.js.map +2 -2
- package/dist/modules/auth/components/AclEditor.js +21 -3
- package/dist/modules/auth/components/AclEditor.js.map +2 -2
- package/dist/modules/customers/backend/customers/companies/page.js +6 -4
- package/dist/modules/customers/backend/customers/companies/page.js.map +2 -2
- package/dist/modules/customers/backend/customers/deals/map/components/DealsMapView.js +6 -4
- package/dist/modules/customers/backend/customers/deals/map/components/DealsMapView.js.map +2 -2
- package/dist/modules/customers/backend/customers/deals/page.js +6 -4
- package/dist/modules/customers/backend/customers/deals/page.js.map +2 -2
- package/dist/modules/customers/backend/customers/deals/pipeline/components/ChangeOwnerDialog.js +5 -3
- package/dist/modules/customers/backend/customers/deals/pipeline/components/ChangeOwnerDialog.js.map +2 -2
- package/dist/modules/customers/backend/customers/deals/pipeline/page.js +6 -4
- package/dist/modules/customers/backend/customers/deals/pipeline/page.js.map +2 -2
- package/dist/modules/customers/backend/customers/people/page.js +6 -4
- package/dist/modules/customers/backend/customers/people/page.js.map +2 -2
- package/dist/modules/customers/components/calendar/editor/PeopleField.js +9 -2
- package/dist/modules/customers/components/calendar/editor/PeopleField.js.map +2 -2
- package/dist/modules/customers/components/calendar/editor/hooks.js +4 -2
- package/dist/modules/customers/components/calendar/editor/hooks.js.map +2 -2
- package/dist/modules/customers/components/calendar/editor/lookups.js +7 -3
- package/dist/modules/customers/components/calendar/editor/lookups.js.map +2 -2
- package/dist/modules/customers/components/detail/AssignRoleDialog.js +5 -2
- package/dist/modules/customers/components/detail/AssignRoleDialog.js.map +2 -2
- package/dist/modules/customers/components/detail/RoleAssignmentRow.js +4 -2
- package/dist/modules/customers/components/detail/RoleAssignmentRow.js.map +2 -2
- package/dist/modules/customers/components/detail/ScheduleActivityDialog.js +8 -5
- package/dist/modules/customers/components/detail/ScheduleActivityDialog.js.map +2 -2
- package/dist/modules/customers/components/detail/schedule/DateTimeFields.js +10 -7
- package/dist/modules/customers/components/detail/schedule/DateTimeFields.js.map +2 -2
- package/dist/modules/customers/components/detail/schedule/ParticipantsField.js +4 -2
- package/dist/modules/customers/components/detail/schedule/ParticipantsField.js.map +2 -2
- package/dist/modules/customers/components/detail/schedule/fieldConfig.js +9 -0
- package/dist/modules/customers/components/detail/schedule/fieldConfig.js.map +2 -2
- package/dist/modules/customers/components/detail/schedule/index.js +3 -1
- package/dist/modules/customers/components/detail/schedule/index.js.map +2 -2
- package/dist/modules/customers/components/detail/schedule/useScheduleFormState.js +11 -4
- package/dist/modules/customers/components/detail/schedule/useScheduleFormState.js.map +2 -2
- package/dist/modules/customers/components/formConfig.js +17 -9
- package/dist/modules/customers/components/formConfig.js.map +2 -2
- package/dist/modules/customers/data/validators.js +12 -7
- package/dist/modules/customers/data/validators.js.map +2 -2
- package/dist/modules/customers/lib/assignableStaff.js +103 -22
- package/dist/modules/customers/lib/assignableStaff.js.map +2 -2
- package/dist/modules/customers/setup.js +10 -2
- package/dist/modules/customers/setup.js.map +2 -2
- package/dist/modules/data_sync/api/schedules/[id]/route.js +5 -0
- package/dist/modules/data_sync/api/schedules/[id]/route.js.map +2 -2
- package/dist/modules/data_sync/api/schedules/route.js +5 -0
- package/dist/modules/data_sync/api/schedules/route.js.map +2 -2
- package/dist/modules/data_sync/backend/data-sync/page.js +29 -5
- package/dist/modules/data_sync/backend/data-sync/page.js.map +2 -2
- package/dist/modules/data_sync/components/IntegrationScheduleTab.js +48 -11
- package/dist/modules/data_sync/components/IntegrationScheduleTab.js.map +2 -2
- package/dist/modules/data_sync/data/validators.js +13 -2
- package/dist/modules/data_sync/data/validators.js.map +2 -2
- package/dist/modules/data_sync/lib/schedule-value.js +30 -0
- package/dist/modules/data_sync/lib/schedule-value.js.map +7 -0
- package/dist/modules/eudr/data/validators.js.map +2 -2
- package/dist/modules/portal/frontend/[orgSlug]/portal/dashboard/page.js +3 -4
- package/dist/modules/portal/frontend/[orgSlug]/portal/dashboard/page.js.map +2 -2
- package/dist/modules/portal/frontend/[orgSlug]/portal/invite/page.js +3 -1
- package/dist/modules/portal/frontend/[orgSlug]/portal/invite/page.js.map +2 -2
- package/dist/modules/portal/frontend/[orgSlug]/portal/login/page.js +2 -1
- package/dist/modules/portal/frontend/[orgSlug]/portal/login/page.js.map +2 -2
- package/dist/modules/portal/frontend/[orgSlug]/portal/page.js +3 -4
- package/dist/modules/portal/frontend/[orgSlug]/portal/page.js.map +2 -2
- package/dist/modules/portal/frontend/[orgSlug]/portal/profile/page.js +3 -4
- package/dist/modules/portal/frontend/[orgSlug]/portal/profile/page.js.map +2 -2
- package/dist/modules/portal/lib/navigation.js +3 -4
- package/dist/modules/portal/lib/navigation.js.map +2 -2
- package/dist/modules/query_index/lib/engine.js +79 -14
- package/dist/modules/query_index/lib/engine.js.map +2 -2
- package/dist/modules/staff/backend/staff/time-tracking/page.js +122 -86
- package/dist/modules/staff/backend/staff/time-tracking/page.js.map +2 -2
- package/dist/modules/staff/backend/staff/time-tracking/projects/[id]/page.js +38 -17
- package/dist/modules/staff/backend/staff/time-tracking/projects/[id]/page.js.map +2 -2
- package/dist/modules/staff/backend/staff/time-tracking/reports/[id]/page.js +45 -18
- package/dist/modules/staff/backend/staff/time-tracking/reports/[id]/page.js.map +2 -2
- package/dist/modules/staff/extension-points.js +16 -0
- package/dist/modules/staff/extension-points.js.map +2 -2
- package/dist/modules/staff/frontend/[orgSlug]/portal/time-reports/[id]/page.js +3 -4
- package/dist/modules/staff/frontend/[orgSlug]/portal/time-reports/[id]/page.js.map +2 -2
- package/dist/modules/staff/frontend/[orgSlug]/portal/time-reports/page.js +3 -4
- package/dist/modules/staff/frontend/[orgSlug]/portal/time-reports/page.js.map +2 -2
- package/dist/modules/staff/lib/time-tracking-ui/ReportSheet.js +14 -13
- package/dist/modules/staff/lib/time-tracking-ui/ReportSheet.js.map +2 -2
- package/dist/modules/staff/lib/time-tracking-ui/TaskListView.js +60 -41
- package/dist/modules/staff/lib/time-tracking-ui/TaskListView.js.map +2 -2
- package/dist/modules/warranty_claims/api/ai/assess/route.js +2 -2
- package/dist/modules/warranty_claims/api/ai/assess/route.js.map +2 -2
- package/dist/modules/warranty_claims/api/ai/draft-reply/route.js +3 -4
- package/dist/modules/warranty_claims/api/ai/draft-reply/route.js.map +3 -3
- package/dist/modules/warranty_claims/api/ai/suggest/route.js +3 -3
- package/dist/modules/warranty_claims/api/ai/suggest/route.js.map +2 -2
- package/dist/modules/warranty_claims/api/assign/route.js +3 -3
- package/dist/modules/warranty_claims/api/assign/route.js.map +2 -2
- package/dist/modules/warranty_claims/api/credit-memo/route.js +2 -2
- package/dist/modules/warranty_claims/api/credit-memo/route.js.map +2 -2
- package/dist/modules/warranty_claims/api/entitlement/route.js +2 -2
- package/dist/modules/warranty_claims/api/entitlement/route.js.map +2 -2
- package/dist/modules/warranty_claims/api/events/route.js +4 -4
- package/dist/modules/warranty_claims/api/events/route.js.map +2 -2
- package/dist/modules/warranty_claims/api/external/claims/route.js +3 -3
- package/dist/modules/warranty_claims/api/external/claims/route.js.map +2 -2
- package/dist/modules/warranty_claims/api/portal/claims/[id]/submit/route.js +2 -2
- package/dist/modules/warranty_claims/api/portal/claims/[id]/submit/route.js.map +2 -2
- package/dist/modules/warranty_claims/api/portal/claims/[id]/withdraw/route.js +2 -2
- package/dist/modules/warranty_claims/api/portal/claims/[id]/withdraw/route.js.map +2 -2
- package/dist/modules/warranty_claims/api/portal/claims/route.js +2 -2
- package/dist/modules/warranty_claims/api/portal/claims/route.js.map +2 -2
- package/dist/modules/warranty_claims/api/portal/events/route.js +2 -2
- package/dist/modules/warranty_claims/api/portal/events/route.js.map +2 -2
- package/dist/modules/warranty_claims/api/receiving/route.js +2 -2
- package/dist/modules/warranty_claims/api/receiving/route.js.map +2 -2
- package/dist/modules/warranty_claims/api/replacement-order/route.js +2 -2
- package/dist/modules/warranty_claims/api/replacement-order/route.js.map +2 -2
- package/dist/modules/warranty_claims/api/return-label/route.js +2 -2
- package/dist/modules/warranty_claims/api/return-label/route.js.map +2 -2
- package/dist/modules/warranty_claims/api/risk/route.js +2 -2
- package/dist/modules/warranty_claims/api/risk/route.js.map +2 -2
- package/dist/modules/warranty_claims/api/sales-return/route.js +2 -2
- package/dist/modules/warranty_claims/api/sales-return/route.js.map +2 -2
- package/dist/modules/warranty_claims/api/settings-general/route.js +4 -4
- package/dist/modules/warranty_claims/api/settings-general/route.js.map +2 -2
- package/dist/modules/warranty_claims/api/stats/route.js +2 -2
- package/dist/modules/warranty_claims/api/stats/route.js.map +2 -2
- package/dist/modules/warranty_claims/api/submit/route.js +3 -3
- package/dist/modules/warranty_claims/api/submit/route.js.map +2 -2
- package/dist/modules/warranty_claims/api/transition/route.js +3 -3
- package/dist/modules/warranty_claims/api/transition/route.js.map +2 -2
- package/dist/modules/warranty_claims/api/vendor-recovery/route.js +3 -3
- package/dist/modules/warranty_claims/api/vendor-recovery/route.js.map +2 -2
- package/dist/modules/warranty_claims/api/vendor-recovery-suggestions/route.js +2 -2
- package/dist/modules/warranty_claims/api/vendor-recovery-suggestions/route.js.map +2 -2
- package/dist/modules/warranty_claims/backend/page.js +4 -2
- package/dist/modules/warranty_claims/backend/page.js.map +2 -2
- package/dist/modules/warranty_claims/backend/warranty_claims/[id]/page.js +9 -2
- package/dist/modules/warranty_claims/backend/warranty_claims/[id]/page.js.map +2 -2
- package/dist/modules/warranty_claims/backend/warranty_claims/settings/page.js +4 -2
- package/dist/modules/warranty_claims/backend/warranty_claims/settings/page.js.map +2 -2
- package/dist/modules/warranty_claims/frontend/[orgSlug]/portal/claims/[id]/page.js +3 -4
- package/dist/modules/warranty_claims/frontend/[orgSlug]/portal/claims/[id]/page.js.map +2 -2
- package/dist/modules/warranty_claims/frontend/[orgSlug]/portal/claims/new/page.js +3 -2
- package/dist/modules/warranty_claims/frontend/[orgSlug]/portal/claims/new/page.js.map +2 -2
- package/dist/modules/warranty_claims/frontend/[orgSlug]/portal/claims/page.js +3 -2
- package/dist/modules/warranty_claims/frontend/[orgSlug]/portal/claims/page.js.map +2 -2
- package/dist/modules/workflows/components/DefinitionTriggersEditor.js +1 -1
- package/dist/modules/workflows/components/DefinitionTriggersEditor.js.map +2 -2
- package/dist/modules/workflows/frontend/[orgSlug]/portal/tasks/[id]/page.js +2 -2
- package/dist/modules/workflows/frontend/[orgSlug]/portal/tasks/[id]/page.js.map +2 -2
- package/dist/modules/workflows/lib/event-trigger-service.js +56 -1
- package/dist/modules/workflows/lib/event-trigger-service.js.map +2 -2
- package/package.json +7 -7
- package/src/modules/auth/api/users/acl/route.ts +4 -3
- package/src/modules/auth/components/AclEditor.tsx +38 -2
- package/src/modules/auth/i18n/de.json +5 -1
- package/src/modules/auth/i18n/en.json +5 -1
- package/src/modules/auth/i18n/es.json +5 -1
- package/src/modules/auth/i18n/ko.json +5 -1
- package/src/modules/auth/i18n/pl.json +5 -1
- package/src/modules/customers/backend/customers/companies/page.tsx +6 -4
- package/src/modules/customers/backend/customers/deals/map/components/DealsMapView.tsx +6 -4
- package/src/modules/customers/backend/customers/deals/page.tsx +6 -4
- package/src/modules/customers/backend/customers/deals/pipeline/components/ChangeOwnerDialog.tsx +5 -3
- package/src/modules/customers/backend/customers/deals/pipeline/page.tsx +6 -4
- package/src/modules/customers/backend/customers/people/page.tsx +6 -4
- package/src/modules/customers/components/calendar/editor/PeopleField.tsx +9 -2
- package/src/modules/customers/components/calendar/editor/hooks.ts +4 -2
- package/src/modules/customers/components/calendar/editor/lookups.ts +12 -4
- package/src/modules/customers/components/detail/AssignRoleDialog.tsx +4 -1
- package/src/modules/customers/components/detail/RoleAssignmentRow.tsx +4 -2
- package/src/modules/customers/components/detail/ScheduleActivityDialog.tsx +15 -7
- package/src/modules/customers/components/detail/schedule/DateTimeFields.tsx +16 -7
- package/src/modules/customers/components/detail/schedule/ParticipantsField.tsx +4 -2
- package/src/modules/customers/components/detail/schedule/fieldConfig.ts +15 -0
- package/src/modules/customers/components/detail/schedule/index.ts +1 -1
- package/src/modules/customers/components/detail/schedule/useScheduleFormState.ts +16 -9
- package/src/modules/customers/components/formConfig.tsx +35 -12
- package/src/modules/customers/data/validators.ts +14 -8
- package/src/modules/customers/i18n/de.json +1 -0
- package/src/modules/customers/i18n/en.json +1 -0
- package/src/modules/customers/i18n/es.json +1 -0
- package/src/modules/customers/i18n/ko.json +1 -0
- package/src/modules/customers/i18n/pl.json +1 -0
- package/src/modules/customers/lib/assignableStaff.ts +172 -34
- package/src/modules/customers/setup.ts +8 -0
- package/src/modules/data_sync/api/schedules/[id]/route.ts +5 -0
- package/src/modules/data_sync/api/schedules/route.ts +5 -0
- package/src/modules/data_sync/backend/data-sync/page.tsx +48 -4
- package/src/modules/data_sync/components/IntegrationScheduleTab.tsx +61 -2
- package/src/modules/data_sync/data/validators.ts +26 -2
- package/src/modules/data_sync/i18n/de.json +2 -0
- package/src/modules/data_sync/i18n/en.json +2 -0
- package/src/modules/data_sync/i18n/es.json +2 -0
- package/src/modules/data_sync/i18n/ko.json +2 -0
- package/src/modules/data_sync/i18n/pl.json +2 -0
- package/src/modules/data_sync/lib/schedule-value.ts +45 -0
- package/src/modules/eudr/data/validators.ts +3 -4
- package/src/modules/portal/frontend/[orgSlug]/portal/dashboard/page.tsx +5 -4
- package/src/modules/portal/frontend/[orgSlug]/portal/invite/page.tsx +3 -1
- package/src/modules/portal/frontend/[orgSlug]/portal/login/page.tsx +2 -1
- package/src/modules/portal/frontend/[orgSlug]/portal/page.tsx +5 -5
- package/src/modules/portal/frontend/[orgSlug]/portal/profile/page.tsx +5 -4
- package/src/modules/portal/i18n/de.json +1 -0
- package/src/modules/portal/i18n/en.json +1 -0
- package/src/modules/portal/i18n/es.json +1 -0
- package/src/modules/portal/i18n/ko.json +1 -0
- package/src/modules/portal/i18n/pl.json +1 -0
- package/src/modules/portal/lib/navigation.ts +8 -3
- package/src/modules/query_index/lib/engine.ts +111 -16
- package/src/modules/staff/backend/staff/time-tracking/page.tsx +161 -130
- package/src/modules/staff/backend/staff/time-tracking/projects/[id]/page.tsx +55 -43
- package/src/modules/staff/backend/staff/time-tracking/reports/[id]/page.tsx +61 -38
- package/src/modules/staff/extension-points.ts +16 -0
- package/src/modules/staff/frontend/[orgSlug]/portal/time-reports/[id]/page.tsx +3 -4
- package/src/modules/staff/frontend/[orgSlug]/portal/time-reports/page.tsx +3 -4
- package/src/modules/staff/i18n/de.json +3 -0
- package/src/modules/staff/i18n/en.json +3 -0
- package/src/modules/staff/i18n/es.json +3 -0
- package/src/modules/staff/i18n/ko.json +3 -0
- package/src/modules/staff/i18n/pl.json +3 -0
- package/src/modules/staff/lib/time-tracking-ui/ReportSheet.tsx +32 -29
- package/src/modules/staff/lib/time-tracking-ui/TaskListView.tsx +89 -79
- package/src/modules/warranty_claims/api/ai/assess/route.ts +2 -2
- package/src/modules/warranty_claims/api/ai/draft-reply/route.ts +2 -3
- package/src/modules/warranty_claims/api/ai/suggest/route.ts +3 -3
- package/src/modules/warranty_claims/api/assign/route.ts +3 -3
- package/src/modules/warranty_claims/api/credit-memo/route.ts +2 -2
- package/src/modules/warranty_claims/api/entitlement/route.ts +2 -2
- package/src/modules/warranty_claims/api/events/route.ts +4 -4
- package/src/modules/warranty_claims/api/external/claims/route.ts +3 -3
- package/src/modules/warranty_claims/api/portal/claims/[id]/submit/route.ts +2 -2
- package/src/modules/warranty_claims/api/portal/claims/[id]/withdraw/route.ts +2 -2
- package/src/modules/warranty_claims/api/portal/claims/route.ts +2 -2
- package/src/modules/warranty_claims/api/portal/events/route.ts +2 -2
- package/src/modules/warranty_claims/api/receiving/route.ts +2 -2
- package/src/modules/warranty_claims/api/replacement-order/route.ts +2 -2
- package/src/modules/warranty_claims/api/return-label/route.ts +2 -2
- package/src/modules/warranty_claims/api/risk/route.ts +2 -2
- package/src/modules/warranty_claims/api/sales-return/route.ts +2 -2
- package/src/modules/warranty_claims/api/settings-general/route.ts +4 -4
- package/src/modules/warranty_claims/api/stats/route.ts +2 -2
- package/src/modules/warranty_claims/api/submit/route.ts +3 -3
- package/src/modules/warranty_claims/api/transition/route.ts +3 -3
- package/src/modules/warranty_claims/api/vendor-recovery/route.ts +3 -3
- package/src/modules/warranty_claims/api/vendor-recovery-suggestions/route.ts +2 -2
- package/src/modules/warranty_claims/backend/page.tsx +4 -2
- package/src/modules/warranty_claims/backend/warranty_claims/[id]/page.tsx +9 -2
- package/src/modules/warranty_claims/backend/warranty_claims/settings/page.tsx +4 -2
- package/src/modules/warranty_claims/frontend/[orgSlug]/portal/claims/[id]/page.tsx +5 -4
- package/src/modules/warranty_claims/frontend/[orgSlug]/portal/claims/new/page.tsx +5 -2
- package/src/modules/warranty_claims/frontend/[orgSlug]/portal/claims/page.tsx +5 -2
- package/src/modules/workflows/components/DefinitionTriggersEditor.tsx +1 -1
- package/src/modules/workflows/frontend/[orgSlug]/portal/tasks/[id]/page.tsx +2 -2
- package/src/modules/workflows/i18n/de.json +1 -1
- package/src/modules/workflows/i18n/en.json +1 -1
- package/src/modules/workflows/i18n/es.json +1 -1
- package/src/modules/workflows/i18n/ko.json +1 -1
- package/src/modules/workflows/i18n/pl.json +1 -1
- package/src/modules/workflows/lib/event-trigger-service.ts +139 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@open-mercato/core",
|
|
3
|
-
"version": "0.8.1-develop.
|
|
3
|
+
"version": "0.8.1-develop.7294.1.0ef99fc518",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -253,16 +253,16 @@
|
|
|
253
253
|
"zod": "^4.4.3"
|
|
254
254
|
},
|
|
255
255
|
"peerDependencies": {
|
|
256
|
-
"@open-mercato/ai-assistant": "0.8.1-develop.
|
|
257
|
-
"@open-mercato/shared": "0.8.1-develop.
|
|
258
|
-
"@open-mercato/ui": "0.8.1-develop.
|
|
256
|
+
"@open-mercato/ai-assistant": "0.8.1-develop.7294.1.0ef99fc518",
|
|
257
|
+
"@open-mercato/shared": "0.8.1-develop.7294.1.0ef99fc518",
|
|
258
|
+
"@open-mercato/ui": "0.8.1-develop.7294.1.0ef99fc518",
|
|
259
259
|
"react": "^19.0.0",
|
|
260
260
|
"react-dom": "^19.0.0"
|
|
261
261
|
},
|
|
262
262
|
"devDependencies": {
|
|
263
|
-
"@open-mercato/ai-assistant": "0.8.1-develop.
|
|
264
|
-
"@open-mercato/shared": "0.8.1-develop.
|
|
265
|
-
"@open-mercato/ui": "0.8.1-develop.
|
|
263
|
+
"@open-mercato/ai-assistant": "0.8.1-develop.7294.1.0ef99fc518",
|
|
264
|
+
"@open-mercato/shared": "0.8.1-develop.7294.1.0ef99fc518",
|
|
265
|
+
"@open-mercato/ui": "0.8.1-develop.7294.1.0ef99fc518",
|
|
266
266
|
"@testing-library/dom": "^10.4.1",
|
|
267
267
|
"@testing-library/jest-dom": "^7.0.1",
|
|
268
268
|
"@testing-library/react": "^16.3.3",
|
|
@@ -422,9 +422,10 @@ function normalizeOrganizations(organizations: unknown): string[] | null {
|
|
|
422
422
|
|
|
423
423
|
// Whether the caller expressed an intentional narrowing. `null` and `__all__`
|
|
424
424
|
// are the two documented ways to say "every organization"; an empty list is the
|
|
425
|
-
// editor's "no organization picked" state
|
|
426
|
-
//
|
|
427
|
-
// only a concrete list has to justify itself against the feature
|
|
425
|
+
// editor's "no organization picked" state, which this route treats as
|
|
426
|
+
// unrestricted rather than a deliberate restriction. Only a concrete list
|
|
427
|
+
// narrows, so only a concrete list has to justify itself against the feature
|
|
428
|
+
// grant below.
|
|
428
429
|
function hasOrganizationRestriction(organizations: string[] | null): boolean {
|
|
429
430
|
if (!organizations || organizations.length === 0) return false
|
|
430
431
|
return !organizations.includes('__all__')
|
|
@@ -282,12 +282,36 @@ export function AclEditor({
|
|
|
282
282
|
|
|
283
283
|
const hasGlobalWildcard = granted.includes('*')
|
|
284
284
|
const hasOrganizationRestriction = Array.isArray(organizations) && organizations.length > 0
|
|
285
|
+
// `null` (unrestricted) and `[]` (deny-all, the #4033 semantic) both leave every
|
|
286
|
+
// checkbox unticked, so the scope has to be reported explicitly instead of being
|
|
287
|
+
// inferred from checkbox emptiness (#5642).
|
|
288
|
+
const isDenyAllOrganizations = Array.isArray(organizations) && organizations.length === 0
|
|
285
289
|
const showOrganizationWarning =
|
|
286
290
|
(kind === 'role' || overrideEnabled) &&
|
|
287
291
|
canEditOrganizations &&
|
|
288
292
|
!isSuperAdmin &&
|
|
289
293
|
hasOrganizationRestriction &&
|
|
290
294
|
granted.length === 0
|
|
295
|
+
// A role ACL is persisted verbatim, so its empty scope really is a deny-all. A
|
|
296
|
+
// per-user override without a single feature is not persisted at all — the API
|
|
297
|
+
// clears the row instead of writing an empty scope — so warning there would
|
|
298
|
+
// claim a permission loss that never happens.
|
|
299
|
+
const denyAllOrganizationsWouldPersist = kind === 'role' || granted.length > 0
|
|
300
|
+
const showDenyAllOrganizationsWarning =
|
|
301
|
+
(kind === 'role' || overrideEnabled) &&
|
|
302
|
+
canEditOrganizations &&
|
|
303
|
+
!isSuperAdmin &&
|
|
304
|
+
isDenyAllOrganizations &&
|
|
305
|
+
denyAllOrganizationsWouldPersist
|
|
306
|
+
const organizationScopeSummary = isDenyAllOrganizations
|
|
307
|
+
? t('auth.acl.organizationsScopeCurrent.none', 'Current scope: no organizations.')
|
|
308
|
+
: organizations && organizations.length > 0
|
|
309
|
+
? t(
|
|
310
|
+
'auth.acl.organizationsScopeCurrent.selected',
|
|
311
|
+
'Current scope: {count} selected organization(s).',
|
|
312
|
+
{ count: organizations.length },
|
|
313
|
+
)
|
|
314
|
+
: t('auth.acl.organizationsScopeCurrent.all', 'Current scope: all organizations.')
|
|
291
315
|
|
|
292
316
|
|
|
293
317
|
const toggleWildcard = React.useCallback((wildcard: string, enable: boolean) => {
|
|
@@ -399,6 +423,7 @@ export function AclEditor({
|
|
|
399
423
|
{t('auth.acl.globalWildcard.description', 'This grants access to all features in the system.')}
|
|
400
424
|
</div>
|
|
401
425
|
<Button
|
|
426
|
+
type="button"
|
|
402
427
|
variant="outline"
|
|
403
428
|
size="sm"
|
|
404
429
|
className="mt-2"
|
|
@@ -564,7 +589,10 @@ export function AclEditor({
|
|
|
564
589
|
{t('auth.acl.organizationsScope', 'Organizations scope')}
|
|
565
590
|
</div>
|
|
566
591
|
<div className="text-xs text-muted-foreground mb-2">
|
|
567
|
-
{t('auth.acl.organizationsScopeHint', '
|
|
592
|
+
{t('auth.acl.organizationsScopeHint', 'Select one or more organizations to restrict access to them. Use "Allow all organizations" to lift the restriction — clearing every selection instead denies access to all organizations.')}
|
|
593
|
+
</div>
|
|
594
|
+
<div className="text-xs font-medium mb-2" data-testid="acl-organization-scope-summary">
|
|
595
|
+
{organizationScopeSummary}
|
|
568
596
|
</div>
|
|
569
597
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-2">
|
|
570
598
|
{orgOptions.map((o) => {
|
|
@@ -584,13 +612,21 @@ export function AclEditor({
|
|
|
584
612
|
})}
|
|
585
613
|
</div>
|
|
586
614
|
<div className="mt-2">
|
|
587
|
-
<Button variant="outline" onClick={() => setOrganizations(null)}>{t('auth.acl.allowAllOrganizations', 'Allow all organizations')}</Button>
|
|
615
|
+
<Button type="button" variant="outline" onClick={() => setOrganizations(null)}>{t('auth.acl.allowAllOrganizations', 'Allow all organizations')}</Button>
|
|
588
616
|
</div>
|
|
589
617
|
{showOrganizationWarning && (
|
|
590
618
|
<div className="mt-3 rounded border border-status-warning-border bg-status-warning-bg px-3 py-2 text-sm text-status-warning-text">
|
|
591
619
|
{t('auth.acl.organizationWarning', 'Organization restrictions are saved only when at least one feature override is selected. Add a feature or enable a module wildcard before saving.')}
|
|
592
620
|
</div>
|
|
593
621
|
)}
|
|
622
|
+
{showDenyAllOrganizationsWarning && (
|
|
623
|
+
<div
|
|
624
|
+
className="mt-3 rounded border border-status-warning-border bg-status-warning-bg px-3 py-2 text-sm text-status-warning-text"
|
|
625
|
+
data-testid="acl-organization-deny-all-warning"
|
|
626
|
+
>
|
|
627
|
+
{t('auth.acl.organizationsDenyAllWarning', 'No organization is selected, so this override denies access in every organization — including the features granted above. Choose at least one organization, or use "Allow all organizations" to leave the scope unrestricted.')}
|
|
628
|
+
</div>
|
|
629
|
+
)}
|
|
594
630
|
</div>
|
|
595
631
|
)}
|
|
596
632
|
</>
|
|
@@ -436,8 +436,12 @@
|
|
|
436
436
|
"auth.acl.modules.wms": "Warehouse Management System",
|
|
437
437
|
"auth.acl.modules.workflows": "Workflow Engine",
|
|
438
438
|
"auth.acl.organizationWarning": "Organisationseinschränkungen erfordern mindestens eine Berechtigungsüberschreibung. Füge eine Berechtigung oder einen Modul-Platzhalter hinzu, oder lösche den Organisationsbereich vor dem Speichern.",
|
|
439
|
+
"auth.acl.organizationsDenyAllWarning": "Es ist keine Organisation ausgewählt, daher entzieht diese Überschreibung den Zugriff in allen Organisationen — einschließlich der oben erteilten Berechtigungen. Wähle mindestens eine Organisation aus oder verwende „Alle Organisationen zulassen“, um den Bereich nicht einzuschränken.",
|
|
439
440
|
"auth.acl.organizationsScope": "Organisationsbereich",
|
|
440
|
-
"auth.acl.
|
|
441
|
+
"auth.acl.organizationsScopeCurrent.all": "Aktueller Bereich: alle Organisationen.",
|
|
442
|
+
"auth.acl.organizationsScopeCurrent.none": "Aktueller Bereich: keine Organisationen.",
|
|
443
|
+
"auth.acl.organizationsScopeCurrent.selected": "Aktueller Bereich: {count} ausgewählte Organisation(en).",
|
|
444
|
+
"auth.acl.organizationsScopeHint": "Wähle eine oder mehrere Organisationen aus, um den Zugriff darauf zu beschränken. Verwende „Alle Organisationen zulassen“, um die Beschränkung aufzuheben — werden dagegen alle Auswahlen entfernt, wird der Zugriff auf alle Organisationen entzogen.",
|
|
441
445
|
"auth.acl.restricted": "Eingeschränkt",
|
|
442
446
|
"auth.acl.superAdmin.hint": "Only super administrators can change this option.",
|
|
443
447
|
"auth.acl.superAdmin.label": "Super Admin (all features)",
|
|
@@ -436,8 +436,12 @@
|
|
|
436
436
|
"auth.acl.modules.wms": "Warehouse Management System",
|
|
437
437
|
"auth.acl.modules.workflows": "Workflow Engine",
|
|
438
438
|
"auth.acl.organizationWarning": "Organization restrictions require at least one feature override. Add a feature or module wildcard, or clear the organization scope before saving.",
|
|
439
|
+
"auth.acl.organizationsDenyAllWarning": "No organization is selected, so this override denies access in every organization — including the features granted above. Choose at least one organization, or use \"Allow all organizations\" to leave the scope unrestricted.",
|
|
439
440
|
"auth.acl.organizationsScope": "Organizations scope",
|
|
440
|
-
"auth.acl.
|
|
441
|
+
"auth.acl.organizationsScopeCurrent.all": "Current scope: all organizations.",
|
|
442
|
+
"auth.acl.organizationsScopeCurrent.none": "Current scope: no organizations.",
|
|
443
|
+
"auth.acl.organizationsScopeCurrent.selected": "Current scope: {count} selected organization(s).",
|
|
444
|
+
"auth.acl.organizationsScopeHint": "Select one or more organizations to restrict access to them. Use \"Allow all organizations\" to lift the restriction — clearing every selection instead denies access to all organizations.",
|
|
441
445
|
"auth.acl.restricted": "Restricted",
|
|
442
446
|
"auth.acl.superAdmin.hint": "Only super administrators can change this option.",
|
|
443
447
|
"auth.acl.superAdmin.label": "Super Admin (all features)",
|
|
@@ -436,8 +436,12 @@
|
|
|
436
436
|
"auth.acl.modules.wms": "Warehouse Management System",
|
|
437
437
|
"auth.acl.modules.workflows": "Workflow Engine",
|
|
438
438
|
"auth.acl.organizationWarning": "Las restricciones de organización requieren al menos una anulación de función. Agrega una función o un comodín de módulo, o borra el ámbito de organización antes de guardar.",
|
|
439
|
+
"auth.acl.organizationsDenyAllWarning": "No hay ninguna organización seleccionada, por lo que esta anulación deniega el acceso en todas las organizaciones, incluidos los permisos concedidos arriba. Selecciona al menos una organización o usa «Permitir todas las organizaciones» para no restringir el alcance.",
|
|
439
440
|
"auth.acl.organizationsScope": "Alcance de organizaciones",
|
|
440
|
-
"auth.acl.
|
|
441
|
+
"auth.acl.organizationsScopeCurrent.all": "Alcance actual: todas las organizaciones.",
|
|
442
|
+
"auth.acl.organizationsScopeCurrent.none": "Alcance actual: ninguna organización.",
|
|
443
|
+
"auth.acl.organizationsScopeCurrent.selected": "Alcance actual: {count} organización(es) seleccionada(s).",
|
|
444
|
+
"auth.acl.organizationsScopeHint": "Selecciona una o más organizaciones para restringir el acceso a ellas. Usa «Permitir todas las organizaciones» para levantar la restricción; en cambio, borrar todas las selecciones deniega el acceso a todas las organizaciones.",
|
|
441
445
|
"auth.acl.restricted": "Restringido",
|
|
442
446
|
"auth.acl.superAdmin.hint": "Only super administrators can change this option.",
|
|
443
447
|
"auth.acl.superAdmin.label": "Super Admin (all features)",
|
|
@@ -436,8 +436,12 @@
|
|
|
436
436
|
"auth.acl.modules.wms": "Warehouse Management System",
|
|
437
437
|
"auth.acl.modules.workflows": "Workflow Engine",
|
|
438
438
|
"auth.acl.organizationWarning": "조직 제한에는 하나 이상의 기능 재정의가 필요합니다. 기능이나 모듈 와일드카드를 추가하거나 저장하기 전에 조직 범위를 지우세요.",
|
|
439
|
+
"auth.acl.organizationsDenyAllWarning": "선택된 조직이 없으므로 이 재정의는 위에서 부여한 권한을 포함해 모든 조직에서 접근을 거부합니다. 조직을 하나 이상 선택하거나, 범위를 제한하지 않으려면 ‘모든 조직 허용’을 사용하세요.",
|
|
439
440
|
"auth.acl.organizationsScope": "조직 범위",
|
|
440
|
-
"auth.acl.
|
|
441
|
+
"auth.acl.organizationsScopeCurrent.all": "현재 범위: 모든 조직.",
|
|
442
|
+
"auth.acl.organizationsScopeCurrent.none": "현재 범위: 조직 없음.",
|
|
443
|
+
"auth.acl.organizationsScopeCurrent.selected": "현재 범위: 선택된 조직 {count}개.",
|
|
444
|
+
"auth.acl.organizationsScopeHint": "하나 이상의 조직을 선택하면 해당 조직으로 접근이 제한됩니다. 제한을 해제하려면 ‘모든 조직 허용’을 사용하세요. 반대로 모든 선택을 해제하면 모든 조직에서 접근이 거부됩니다.",
|
|
441
445
|
"auth.acl.restricted": "제한됨",
|
|
442
446
|
"auth.acl.superAdmin.hint": "Only super administrators can change this option.",
|
|
443
447
|
"auth.acl.superAdmin.label": "Super Admin (all features)",
|
|
@@ -436,8 +436,12 @@
|
|
|
436
436
|
"auth.acl.modules.wms": "System zarządzania magazynem",
|
|
437
437
|
"auth.acl.modules.workflows": "Mechanizm przepływów pracy",
|
|
438
438
|
"auth.acl.organizationWarning": "Ograniczenia organizacyjne wymagają co najmniej jednego nadpisania uprawnień. Dodaj uprawnienie lub wildcard modułu albo wyczyść zakres organizacji przed zapisaniem.",
|
|
439
|
+
"auth.acl.organizationsDenyAllWarning": "Nie wybrano żadnej organizacji, więc to nadpisanie odbiera dostęp we wszystkich organizacjach — łącznie z uprawnieniami przyznanymi powyżej. Wybierz co najmniej jedną organizację lub użyj przycisku „Zezwól na wszystkie organizacje”, aby nie ograniczać zakresu.",
|
|
439
440
|
"auth.acl.organizationsScope": "Zakres organizacji",
|
|
440
|
-
"auth.acl.
|
|
441
|
+
"auth.acl.organizationsScopeCurrent.all": "Bieżący zakres: wszystkie organizacje.",
|
|
442
|
+
"auth.acl.organizationsScopeCurrent.none": "Bieżący zakres: brak organizacji.",
|
|
443
|
+
"auth.acl.organizationsScopeCurrent.selected": "Bieżący zakres: wybrane organizacje: {count}.",
|
|
444
|
+
"auth.acl.organizationsScopeHint": "Wybierz co najmniej jedną organizację, aby ograniczyć do niej dostęp. Użyj przycisku „Zezwól na wszystkie organizacje”, aby znieść ograniczenie — usunięcie wszystkich zaznaczeń odbiera natomiast dostęp do wszystkich organizacji.",
|
|
441
445
|
"auth.acl.restricted": "Ograniczone",
|
|
442
446
|
"auth.acl.superAdmin.hint": "Tylko superadministratorzy mogą zmienić tę opcję.",
|
|
443
447
|
"auth.acl.superAdmin.label": "Superadministrator (wszystkie funkcje)",
|
|
@@ -26,6 +26,7 @@ import type { AdvancedFilterTree } from '@open-mercato/shared/lib/query/advanced
|
|
|
26
26
|
import { createEmptyTree, makeRuleTree } from '@open-mercato/shared/lib/query/advanced-filter-tree'
|
|
27
27
|
import { deserializeAdvancedFilter, deserializeTree, flatToTree, mapDictionaryColorToTone, serializeTree } from '@open-mercato/shared/lib/query/advanced-filter'
|
|
28
28
|
import { useCurrentUserId } from '@open-mercato/ui/backend/utils/useCurrentUserId'
|
|
29
|
+
import { useCurrentOrganization } from '@open-mercato/ui/backend/BackendChromeProvider'
|
|
29
30
|
import {
|
|
30
31
|
DictionaryValue,
|
|
31
32
|
createEmptyCustomerDictionaryMaps,
|
|
@@ -327,11 +328,12 @@ export default function CustomersCompaniesPage() {
|
|
|
327
328
|
{ keyExtras: [scopeVersion, reloadToken] },
|
|
328
329
|
)
|
|
329
330
|
const currentUserId = useCurrentUserId()
|
|
331
|
+
const activeOrgId = useCurrentOrganization()?.id ?? null
|
|
330
332
|
const [ownerFilterOptions, setOwnerFilterOptions] = React.useState<AdvancedFilterOption[]>([])
|
|
331
333
|
React.useEffect(() => {
|
|
332
334
|
const controller = new AbortController()
|
|
333
335
|
let cancelled = false
|
|
334
|
-
void fetchAssignableStaffMembers('', { pageSize: 100, signal: controller.signal })
|
|
336
|
+
void fetchAssignableStaffMembers('', { pageSize: 100, activeOrgId, signal: controller.signal })
|
|
335
337
|
.then((items) => {
|
|
336
338
|
if (!cancelled) setOwnerFilterOptions(mapAssignableStaffToFilterOptions(items))
|
|
337
339
|
})
|
|
@@ -342,7 +344,7 @@ export default function CustomersCompaniesPage() {
|
|
|
342
344
|
cancelled = true
|
|
343
345
|
controller.abort()
|
|
344
346
|
}
|
|
345
|
-
}, [scopeVersion])
|
|
347
|
+
}, [activeOrgId, scopeVersion])
|
|
346
348
|
const resolvedOwnerFilterOptions = React.useMemo(
|
|
347
349
|
() => ensureCurrentUserFilterOption(
|
|
348
350
|
ownerFilterOptions,
|
|
@@ -352,9 +354,9 @@ export default function CustomersCompaniesPage() {
|
|
|
352
354
|
[currentUserId, ownerFilterOptions, t],
|
|
353
355
|
)
|
|
354
356
|
const loadOwnerFilterOptions = React.useCallback(async (query?: string): Promise<AdvancedFilterOption[]> => {
|
|
355
|
-
const items = await fetchAssignableStaffMembers(query ?? '', { pageSize: 100 })
|
|
357
|
+
const items = await fetchAssignableStaffMembers(query ?? '', { pageSize: 100, activeOrgId })
|
|
356
358
|
return mapAssignableStaffToFilterOptions(items)
|
|
357
|
-
}, [])
|
|
359
|
+
}, [activeOrgId])
|
|
358
360
|
|
|
359
361
|
const queryParams = React.useMemo(() => {
|
|
360
362
|
const params = new URLSearchParams()
|
|
@@ -12,6 +12,7 @@ import {
|
|
|
12
12
|
import { useT } from '@open-mercato/shared/lib/i18n/context'
|
|
13
13
|
import { translateWithFallback } from '@open-mercato/shared/lib/i18n/translate'
|
|
14
14
|
import { useOrganizationScopeVersion } from '@open-mercato/shared/lib/frontend/useOrganizationScope'
|
|
15
|
+
import { useCurrentOrganization } from '@open-mercato/ui/backend/BackendChromeProvider'
|
|
15
16
|
import type { FilterOptionTone } from '@open-mercato/shared/lib/query/advanced-filter'
|
|
16
17
|
import { FilterBarRow, type KanbanFilterChip } from '../../pipeline/components/FilterBarRow'
|
|
17
18
|
import { StatusFilterPopover } from '../../pipeline/components/StatusFilterPopover'
|
|
@@ -236,6 +237,7 @@ type DealsMapViewProps = {
|
|
|
236
237
|
export function DealsMapView({ search }: DealsMapViewProps): React.ReactElement {
|
|
237
238
|
const t = useT()
|
|
238
239
|
const scopeVersion = useOrganizationScopeVersion()
|
|
240
|
+
const activeOrgId = useCurrentOrganization()?.id ?? null
|
|
239
241
|
|
|
240
242
|
const [statusFilters, setStatusFilters] = React.useState<string[]>([])
|
|
241
243
|
const [selectedPipelineId, setSelectedPipelineId] = React.useState<string | null>(null)
|
|
@@ -293,13 +295,13 @@ export function DealsMapView({ search }: DealsMapViewProps): React.ReactElement
|
|
|
293
295
|
})
|
|
294
296
|
|
|
295
297
|
const staffQuery = useQuery<Map<string, string>>({
|
|
296
|
-
queryKey: ['customers', 'deals', 'map', 'staff', `scope:${scopeVersion}
|
|
298
|
+
queryKey: ['customers', 'deals', 'map', 'staff', `scope:${scopeVersion}`, activeOrgId],
|
|
297
299
|
staleTime: 300_000,
|
|
298
300
|
queryFn: async () => {
|
|
299
301
|
try {
|
|
300
302
|
const members = await withScopedApiRequestHeaders(
|
|
301
303
|
{ ...SUPPRESS_AUTH_REDIRECT_HEADERS },
|
|
302
|
-
() => fetchAssignableStaffMembers('', { pageSize: 100 }),
|
|
304
|
+
() => fetchAssignableStaffMembers('', { pageSize: 100, activeOrgId }),
|
|
303
305
|
)
|
|
304
306
|
const names = new Map<string, string>()
|
|
305
307
|
for (const member of members) {
|
|
@@ -482,7 +484,7 @@ export function DealsMapView({ search }: DealsMapViewProps): React.ReactElement
|
|
|
482
484
|
try {
|
|
483
485
|
const members = await withScopedApiRequestHeaders(
|
|
484
486
|
{ ...SUPPRESS_AUTH_REDIRECT_HEADERS },
|
|
485
|
-
() => fetchAssignableStaffMembers(query ?? '', { pageSize: 100 }),
|
|
487
|
+
() => fetchAssignableStaffMembers(query ?? '', { pageSize: 100, activeOrgId }),
|
|
486
488
|
)
|
|
487
489
|
const options: EntityFilterOption[] = members
|
|
488
490
|
.filter((member) => !!member.userId && !!member.displayName)
|
|
@@ -497,7 +499,7 @@ export function DealsMapView({ search }: DealsMapViewProps): React.ReactElement
|
|
|
497
499
|
return []
|
|
498
500
|
}
|
|
499
501
|
},
|
|
500
|
-
[],
|
|
502
|
+
[activeOrgId],
|
|
501
503
|
)
|
|
502
504
|
|
|
503
505
|
const loadPeopleOptions = React.useCallback(
|
|
@@ -12,6 +12,7 @@ import type { AdvancedFilterTree } from '@open-mercato/shared/lib/query/advanced
|
|
|
12
12
|
import { createEmptyTree, makeRuleTree, makeMultiRuleTree } from '@open-mercato/shared/lib/query/advanced-filter-tree'
|
|
13
13
|
import { deserializeTree, deserializeAdvancedFilter, flatToTree, mapDictionaryColorToTone, serializeTree, type FilterFieldDef, type FilterOption as AdvancedFilterOption } from '@open-mercato/shared/lib/query/advanced-filter'
|
|
14
14
|
import { useCurrentUserId } from '@open-mercato/ui/backend/utils/useCurrentUserId'
|
|
15
|
+
import { useCurrentOrganization } from '@open-mercato/ui/backend/BackendChromeProvider'
|
|
15
16
|
import { apiCall, withScopedApiRequestHeaders } from '@open-mercato/ui/backend/utils/apiCall'
|
|
16
17
|
import { buildOptimisticLockHeader } from '@open-mercato/ui/backend/utils/optimisticLock'
|
|
17
18
|
import { surfaceRecordConflict } from '@open-mercato/ui/backend/conflicts'
|
|
@@ -637,6 +638,7 @@ export default function CustomersDealsPage() {
|
|
|
637
638
|
keyExtras: [scopeVersion, reloadToken],
|
|
638
639
|
})
|
|
639
640
|
const currentUserId = useCurrentUserId()
|
|
641
|
+
const activeOrgId = useCurrentOrganization()?.id ?? null
|
|
640
642
|
const [ownerFilterOptions, setOwnerFilterOptions] = React.useState<AdvancedFilterOption[]>([])
|
|
641
643
|
// Single staff load drives both the owner FILTER options and the owner-name
|
|
642
644
|
// map shared with the OWNER cell + the KPI strip (userId → display name).
|
|
@@ -645,7 +647,7 @@ export default function CustomersDealsPage() {
|
|
|
645
647
|
React.useEffect(() => {
|
|
646
648
|
const controller = new AbortController()
|
|
647
649
|
let cancelled = false
|
|
648
|
-
void fetchAssignableStaffMembers('', { pageSize: 100, signal: controller.signal })
|
|
650
|
+
void fetchAssignableStaffMembers('', { pageSize: 100, activeOrgId, signal: controller.signal })
|
|
649
651
|
.then((items) => {
|
|
650
652
|
if (cancelled) return
|
|
651
653
|
setOwnerFilterOptions(mapAssignableStaffToFilterOptions(items))
|
|
@@ -664,7 +666,7 @@ export default function CustomersDealsPage() {
|
|
|
664
666
|
cancelled = true
|
|
665
667
|
controller.abort()
|
|
666
668
|
}
|
|
667
|
-
}, [scopeVersion])
|
|
669
|
+
}, [activeOrgId, scopeVersion])
|
|
668
670
|
const resolvedOwnerFilterOptions = React.useMemo(
|
|
669
671
|
() => ensureCurrentUserFilterOption(
|
|
670
672
|
ownerFilterOptions,
|
|
@@ -674,9 +676,9 @@ export default function CustomersDealsPage() {
|
|
|
674
676
|
[currentUserId, ownerFilterOptions, t],
|
|
675
677
|
)
|
|
676
678
|
const loadOwnerFilterOptions = React.useCallback(async (query?: string): Promise<AdvancedFilterOption[]> => {
|
|
677
|
-
const items = await fetchAssignableStaffMembers(query ?? '', { pageSize: 100 })
|
|
679
|
+
const items = await fetchAssignableStaffMembers(query ?? '', { pageSize: 100, activeOrgId })
|
|
678
680
|
return mapAssignableStaffToFilterOptions(items)
|
|
679
|
-
}, [])
|
|
681
|
+
}, [activeOrgId])
|
|
680
682
|
|
|
681
683
|
const startOfToday = React.useMemo(() => {
|
|
682
684
|
const today = new Date()
|
package/src/modules/customers/backend/customers/deals/pipeline/components/ChangeOwnerDialog.tsx
CHANGED
|
@@ -15,6 +15,7 @@ import { Input } from '@open-mercato/ui/primitives/input'
|
|
|
15
15
|
import { Avatar } from '@open-mercato/ui/primitives/avatar'
|
|
16
16
|
import { Spinner } from '@open-mercato/ui/primitives/spinner'
|
|
17
17
|
import { useT } from '@open-mercato/shared/lib/i18n/context'
|
|
18
|
+
import { useCurrentOrganization } from '@open-mercato/ui/backend/BackendChromeProvider'
|
|
18
19
|
import { translateWithFallback } from '@open-mercato/shared/lib/i18n/translate'
|
|
19
20
|
import {
|
|
20
21
|
fetchAssignableStaffMembers,
|
|
@@ -37,6 +38,7 @@ export function ChangeOwnerDialog({
|
|
|
37
38
|
onConfirm,
|
|
38
39
|
}: ChangeOwnerDialogProps): React.ReactElement {
|
|
39
40
|
const t = useT()
|
|
41
|
+
const activeOrgId = useCurrentOrganization()?.id ?? null
|
|
40
42
|
const [query, setQuery] = React.useState('')
|
|
41
43
|
const [items, setItems] = React.useState<AssignableStaffMember[]>([])
|
|
42
44
|
const [isLoading, setIsLoading] = React.useState(false)
|
|
@@ -53,7 +55,7 @@ export function ChangeOwnerDialog({
|
|
|
53
55
|
let cancelled = false
|
|
54
56
|
const controller = new AbortController()
|
|
55
57
|
setIsLoading(true)
|
|
56
|
-
fetchAssignableStaffMembers(query, { pageSize: 50, signal: controller.signal })
|
|
58
|
+
fetchAssignableStaffMembers(query, { pageSize: 50, activeOrgId, signal: controller.signal })
|
|
57
59
|
.then((next) => {
|
|
58
60
|
if (cancelled) return
|
|
59
61
|
setItems(next)
|
|
@@ -70,7 +72,7 @@ export function ChangeOwnerDialog({
|
|
|
70
72
|
controller.abort()
|
|
71
73
|
}
|
|
72
74
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
73
|
-
}, [open, query])
|
|
75
|
+
}, [activeOrgId, open, query])
|
|
74
76
|
|
|
75
77
|
const handleConfirm = () => {
|
|
76
78
|
onConfirm(selectedUserId)
|
|
@@ -141,7 +143,7 @@ export function ChangeOwnerDialog({
|
|
|
141
143
|
<Button
|
|
142
144
|
variant="ghost"
|
|
143
145
|
size="default"
|
|
144
|
-
key={member.teamMemberId}
|
|
146
|
+
key={member.teamMemberId ?? member.userId}
|
|
145
147
|
type="button"
|
|
146
148
|
onClick={() => setSelectedUserId(member.userId)}
|
|
147
149
|
// Overrides on the Button base class:
|
|
@@ -53,6 +53,7 @@ import type { RowActionItem } from '@open-mercato/ui/backend/RowActions'
|
|
|
53
53
|
import { useT } from '@open-mercato/shared/lib/i18n/context'
|
|
54
54
|
import { translateWithFallback } from '@open-mercato/shared/lib/i18n/translate'
|
|
55
55
|
import { useOrganizationScopeVersion } from '@open-mercato/shared/lib/frontend/useOrganizationScope'
|
|
56
|
+
import { useCurrentOrganization } from '@open-mercato/ui/backend/BackendChromeProvider'
|
|
56
57
|
import type { FilterOptionTone } from '@open-mercato/shared/lib/query/advanced-filter'
|
|
57
58
|
import { ViewTabsRow, VIEW_TABS_ROW_COMPONENT_ID, type ViewTabsRowProps } from './components/ViewTabsRow'
|
|
58
59
|
import { LANE_WIDTH_CLASS } from './components/constants'
|
|
@@ -427,6 +428,7 @@ export default function DealsKanbanPage(): React.ReactElement {
|
|
|
427
428
|
)
|
|
428
429
|
const router = useRouter()
|
|
429
430
|
const scopeVersion = useOrganizationScopeVersion()
|
|
431
|
+
const activeOrgId = useCurrentOrganization()?.id ?? null
|
|
430
432
|
const queryClient = useQueryClient()
|
|
431
433
|
|
|
432
434
|
const [selectedPipelineId, setSelectedPipelineId] = React.useState<string | null>(null)
|
|
@@ -499,9 +501,9 @@ export default function DealsKanbanPage(): React.ReactElement {
|
|
|
499
501
|
}, [pipelinesQuery.data, selectedPipelineId])
|
|
500
502
|
|
|
501
503
|
const staffQuery = useQuery<AssignableStaffMember[]>({
|
|
502
|
-
queryKey: ['customers', 'deals', 'kanban', 'staff', `scope:${scopeVersion}
|
|
504
|
+
queryKey: ['customers', 'deals', 'kanban', 'staff', `scope:${scopeVersion}`, activeOrgId],
|
|
503
505
|
staleTime: 300_000,
|
|
504
|
-
queryFn: async () => fetchAssignableStaffMembers('', { pageSize: 100 }),
|
|
506
|
+
queryFn: async () => fetchAssignableStaffMembers('', { pageSize: 100, activeOrgId }),
|
|
505
507
|
})
|
|
506
508
|
|
|
507
509
|
const ownerNamesById = React.useMemo(() => {
|
|
@@ -2414,7 +2416,7 @@ export default function DealsKanbanPage(): React.ReactElement {
|
|
|
2414
2416
|
// Async loaders for entity-filter popovers (Owner / People / Companies)
|
|
2415
2417
|
const loadOwnerOptions = React.useCallback(
|
|
2416
2418
|
async (query: string, _signal: AbortSignal): Promise<EntityFilterOption[]> => {
|
|
2417
|
-
const items = await fetchAssignableStaffMembers(query ?? '', { pageSize: 100 })
|
|
2419
|
+
const items = await fetchAssignableStaffMembers(query ?? '', { pageSize: 100, activeOrgId })
|
|
2418
2420
|
const opts: EntityFilterOption[] = items
|
|
2419
2421
|
.filter((user) => !!user.userId && !!user.displayName)
|
|
2420
2422
|
.map((user) => ({ value: user.userId!, label: user.displayName! }))
|
|
@@ -2426,7 +2428,7 @@ export default function DealsKanbanPage(): React.ReactElement {
|
|
|
2426
2428
|
})
|
|
2427
2429
|
return opts
|
|
2428
2430
|
},
|
|
2429
|
-
[],
|
|
2431
|
+
[activeOrgId],
|
|
2430
2432
|
)
|
|
2431
2433
|
const loadPeopleOptions = React.useCallback(
|
|
2432
2434
|
async (query: string, signal: AbortSignal): Promise<EntityFilterOption[]> => {
|
|
@@ -26,6 +26,7 @@ import type { AdvancedFilterTree } from '@open-mercato/shared/lib/query/advanced
|
|
|
26
26
|
import { createEmptyTree, makeRuleTree } from '@open-mercato/shared/lib/query/advanced-filter-tree'
|
|
27
27
|
import { deserializeAdvancedFilter, deserializeTree, flatToTree, mapDictionaryColorToTone, serializeTree } from '@open-mercato/shared/lib/query/advanced-filter'
|
|
28
28
|
import { useCurrentUserId } from '@open-mercato/ui/backend/utils/useCurrentUserId'
|
|
29
|
+
import { useCurrentOrganization } from '@open-mercato/ui/backend/BackendChromeProvider'
|
|
29
30
|
import {
|
|
30
31
|
DictionaryValue,
|
|
31
32
|
createEmptyCustomerDictionaryMaps,
|
|
@@ -338,11 +339,12 @@ export default function CustomersPeoplePage() {
|
|
|
338
339
|
{ keyExtras: [scopeVersion, reloadToken] },
|
|
339
340
|
)
|
|
340
341
|
const currentUserId = useCurrentUserId()
|
|
342
|
+
const activeOrgId = useCurrentOrganization()?.id ?? null
|
|
341
343
|
const [ownerFilterOptions, setOwnerFilterOptions] = React.useState<AdvancedFilterOption[]>([])
|
|
342
344
|
React.useEffect(() => {
|
|
343
345
|
const controller = new AbortController()
|
|
344
346
|
let cancelled = false
|
|
345
|
-
void fetchAssignableStaffMembers('', { pageSize: 100, signal: controller.signal })
|
|
347
|
+
void fetchAssignableStaffMembers('', { pageSize: 100, activeOrgId, signal: controller.signal })
|
|
346
348
|
.then((items) => {
|
|
347
349
|
if (!cancelled) setOwnerFilterOptions(mapAssignableStaffToFilterOptions(items))
|
|
348
350
|
})
|
|
@@ -353,7 +355,7 @@ export default function CustomersPeoplePage() {
|
|
|
353
355
|
cancelled = true
|
|
354
356
|
controller.abort()
|
|
355
357
|
}
|
|
356
|
-
}, [scopeVersion])
|
|
358
|
+
}, [activeOrgId, scopeVersion])
|
|
357
359
|
const resolvedOwnerFilterOptions = React.useMemo(
|
|
358
360
|
() => ensureCurrentUserFilterOption(
|
|
359
361
|
ownerFilterOptions,
|
|
@@ -363,9 +365,9 @@ export default function CustomersPeoplePage() {
|
|
|
363
365
|
[currentUserId, ownerFilterOptions, t],
|
|
364
366
|
)
|
|
365
367
|
const loadOwnerFilterOptions = React.useCallback(async (query?: string): Promise<AdvancedFilterOption[]> => {
|
|
366
|
-
const items = await fetchAssignableStaffMembers(query ?? '', { pageSize: 100 })
|
|
368
|
+
const items = await fetchAssignableStaffMembers(query ?? '', { pageSize: 100, activeOrgId })
|
|
367
369
|
return mapAssignableStaffToFilterOptions(items)
|
|
368
|
-
}, [])
|
|
370
|
+
}, [activeOrgId])
|
|
369
371
|
|
|
370
372
|
const queryParams = React.useMemo(() => {
|
|
371
373
|
const params = new URLSearchParams()
|
|
@@ -9,6 +9,7 @@ import { Button } from '@open-mercato/ui/primitives/button'
|
|
|
9
9
|
import { Input } from '@open-mercato/ui/primitives/input'
|
|
10
10
|
import type { EditorParticipant } from '../../../lib/calendar/editorPayload'
|
|
11
11
|
import { composeAccessibleName } from '../../../lib/calendar/labels'
|
|
12
|
+
import { useCurrentOrganization } from '@open-mercato/ui/backend/BackendChromeProvider'
|
|
12
13
|
import { searchPeopleOptions, type PersonOption } from './lookups'
|
|
13
14
|
import { CONTROL_BORDER, DROPDOWN_PANEL_CLASS, PersonChip, UppercaseBadge, useDropdownDismiss } from './inputs'
|
|
14
15
|
|
|
@@ -40,6 +41,7 @@ export function PeopleField({
|
|
|
40
41
|
includeStaff?: boolean
|
|
41
42
|
}) {
|
|
42
43
|
const t = useT()
|
|
44
|
+
const activeOrgId = useCurrentOrganization()?.id ?? null
|
|
43
45
|
const [query, setQuery] = React.useState('')
|
|
44
46
|
const [open, setOpen] = React.useState(false)
|
|
45
47
|
const [options, setOptions] = React.useState<PersonOption[]>([])
|
|
@@ -54,7 +56,12 @@ export function PeopleField({
|
|
|
54
56
|
const timer = window.setTimeout(async () => {
|
|
55
57
|
setLoading(true)
|
|
56
58
|
try {
|
|
57
|
-
const results = await searchPeopleOptions(query.trim(), {
|
|
59
|
+
const results = await searchPeopleOptions(query.trim(), {
|
|
60
|
+
includeCustomers,
|
|
61
|
+
includeStaff,
|
|
62
|
+
activeOrgId,
|
|
63
|
+
signal: controller.signal,
|
|
64
|
+
})
|
|
58
65
|
if (cancelled) return
|
|
59
66
|
setOptions(results)
|
|
60
67
|
} catch {
|
|
@@ -68,7 +75,7 @@ export function PeopleField({
|
|
|
68
75
|
controller.abort()
|
|
69
76
|
window.clearTimeout(timer)
|
|
70
77
|
}
|
|
71
|
-
}, [open, query, includeCustomers, includeStaff])
|
|
78
|
+
}, [activeOrgId, open, query, includeCustomers, includeStaff])
|
|
72
79
|
|
|
73
80
|
const selectedIds = new Set(value.map((participant) => participant.userId))
|
|
74
81
|
const visibleOptions = options.filter((option) => !selectedIds.has(option.userId))
|
|
@@ -13,6 +13,7 @@ import { expandOccurrences } from '../../../lib/calendar/recurrence'
|
|
|
13
13
|
import { getFetchWindow } from '../../../lib/calendar/range'
|
|
14
14
|
import type { CalendarItem } from '../types'
|
|
15
15
|
import { fetchCalendarCandidates } from '../useCalendarItems'
|
|
16
|
+
import { useCurrentOrganization } from '@open-mercato/ui/backend/BackendChromeProvider'
|
|
16
17
|
import { fetchDealById, fetchRelatedEntityById, findStaffMemberName } from './lookups'
|
|
17
18
|
|
|
18
19
|
// Edit-mode prefill stores ids only (parseItemToFormState is pure); resolve the
|
|
@@ -22,6 +23,7 @@ export function useEditorLabelResolution(
|
|
|
22
23
|
form: EditorFormState,
|
|
23
24
|
update: (patch: Partial<EditorFormState>) => void,
|
|
24
25
|
): void {
|
|
26
|
+
const activeOrgId = useCurrentOrganization()?.id ?? null
|
|
25
27
|
React.useEffect(() => {
|
|
26
28
|
if (!open) return
|
|
27
29
|
const controller = new AbortController()
|
|
@@ -36,7 +38,7 @@ export function useEditorLabelResolution(
|
|
|
36
38
|
if (!cancelled && deal) update({ dealLabel: deal.label })
|
|
37
39
|
}
|
|
38
40
|
if (form.assigneeUserId && !form.assigneeName) {
|
|
39
|
-
const name = await findStaffMemberName(form.assigneeUserId, controller.signal)
|
|
41
|
+
const name = await findStaffMemberName(form.assigneeUserId, controller.signal, activeOrgId)
|
|
40
42
|
if (!cancelled && name) update({ assigneeName: name })
|
|
41
43
|
}
|
|
42
44
|
}
|
|
@@ -50,7 +52,7 @@ export function useEditorLabelResolution(
|
|
|
50
52
|
cancelled = true
|
|
51
53
|
controller.abort()
|
|
52
54
|
}
|
|
53
|
-
}, [open, form.relatedTo, form.dealId, form.dealLabel, form.assigneeUserId, form.assigneeName, update])
|
|
55
|
+
}, [activeOrgId, open, form.relatedTo, form.dealId, form.dealLabel, form.assigneeUserId, form.assigneeName, update])
|
|
54
56
|
}
|
|
55
57
|
|
|
56
58
|
function formatClock(date: Date): string {
|
|
@@ -126,7 +126,7 @@ export async function fetchDealById(dealId: string, signal: AbortSignal): Promis
|
|
|
126
126
|
|
|
127
127
|
export async function searchPeopleOptions(
|
|
128
128
|
query: string,
|
|
129
|
-
options: { includeCustomers: boolean; includeStaff?: boolean; signal: AbortSignal },
|
|
129
|
+
options: { includeCustomers: boolean; includeStaff?: boolean; signal: AbortSignal; activeOrgId?: string | null },
|
|
130
130
|
): Promise<PersonOption[]> {
|
|
131
131
|
// Staff lookup is optional twice over: skipped when the staff module is not
|
|
132
132
|
// loaded (includeStaff === false) and non-fatal when the endpoint errors, so
|
|
@@ -134,7 +134,11 @@ export async function searchPeopleOptions(
|
|
|
134
134
|
const [staff, customers] = await Promise.all([
|
|
135
135
|
options.includeStaff === false
|
|
136
136
|
? Promise.resolve<Awaited<ReturnType<typeof fetchAssignableStaffMembers>>>([])
|
|
137
|
-
: fetchAssignableStaffMembers(query, {
|
|
137
|
+
: fetchAssignableStaffMembers(query, {
|
|
138
|
+
pageSize: 10,
|
|
139
|
+
activeOrgId: options.activeOrgId,
|
|
140
|
+
signal: options.signal,
|
|
141
|
+
}).catch(() => []),
|
|
138
142
|
options.includeCustomers
|
|
139
143
|
? searchRelatedEntities('person', query, options.signal)
|
|
140
144
|
: Promise.resolve<RelatedEntityOption[]>([]),
|
|
@@ -262,9 +266,13 @@ export async function fetchPeoplePhones(ids: string[], signal: AbortSignal): Pro
|
|
|
262
266
|
}
|
|
263
267
|
}
|
|
264
268
|
|
|
265
|
-
export async function findStaffMemberName(
|
|
269
|
+
export async function findStaffMemberName(
|
|
270
|
+
userId: string,
|
|
271
|
+
signal: AbortSignal,
|
|
272
|
+
activeOrgId?: string | null,
|
|
273
|
+
): Promise<string | null> {
|
|
266
274
|
try {
|
|
267
|
-
const members = await fetchAssignableStaffMembers('', { pageSize: 100, signal })
|
|
275
|
+
const members = await fetchAssignableStaffMembers('', { pageSize: 100, activeOrgId, signal })
|
|
268
276
|
const match = members.find((member) => member.userId === userId)
|
|
269
277
|
return match ? match.displayName : null
|
|
270
278
|
} catch {
|
|
@@ -20,6 +20,7 @@ import {
|
|
|
20
20
|
} from '@open-mercato/ui/primitives/dialog'
|
|
21
21
|
import type { DictionaryEntryOption } from '@open-mercato/core/modules/dictionaries/lib/clientEntries'
|
|
22
22
|
import type { RoleAssignment } from './RoleAssignmentRow'
|
|
23
|
+
import { useCurrentOrganization } from '@open-mercato/ui/backend/BackendChromeProvider'
|
|
23
24
|
import { fetchAssignableStaffMembersPage } from './assignableStaff'
|
|
24
25
|
|
|
25
26
|
const MANAGE_ROLE_TYPES_HREF = '/backend/config/customers'
|
|
@@ -65,6 +66,7 @@ export function AssignRoleDialog({
|
|
|
65
66
|
canManageRoleTypes = false,
|
|
66
67
|
}: AssignRoleDialogProps) {
|
|
67
68
|
const t = useT()
|
|
69
|
+
const activeOrgId = useCurrentOrganization()?.id ?? null
|
|
68
70
|
const [step, setStep] = React.useState<StepId>(1)
|
|
69
71
|
const [selectedRoleType, setSelectedRoleType] = React.useState('')
|
|
70
72
|
const [selectedUser, setSelectedUser] = React.useState<StaffMember | null>(null)
|
|
@@ -144,6 +146,7 @@ export function AssignRoleDialog({
|
|
|
144
146
|
const result = await fetchAssignableStaffMembersPage(query, {
|
|
145
147
|
page,
|
|
146
148
|
pageSize: ASSIGNABLE_STAFF_PAGE_SIZE,
|
|
149
|
+
activeOrgId,
|
|
147
150
|
})
|
|
148
151
|
if (requestSequenceRef.current !== requestId) return
|
|
149
152
|
|
|
@@ -187,7 +190,7 @@ export function AssignRoleDialog({
|
|
|
187
190
|
}
|
|
188
191
|
}
|
|
189
192
|
},
|
|
190
|
-
[t],
|
|
193
|
+
[activeOrgId, t],
|
|
191
194
|
)
|
|
192
195
|
|
|
193
196
|
React.useEffect(() => {
|