@open-mercato/core 0.6.7-develop.6758.1.697eade236 → 0.6.7-develop.6768.1.9d2c4efc43
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/api_keys/backend/api-keys/page.js +2 -1
- package/dist/modules/api_keys/backend/api-keys/page.js.map +2 -2
- package/dist/modules/api_keys/extension-points.js +16 -0
- package/dist/modules/api_keys/extension-points.js.map +7 -0
- package/dist/modules/audit_logs/components/AccessLogsTable.js +2 -1
- package/dist/modules/audit_logs/components/AccessLogsTable.js.map +2 -2
- package/dist/modules/audit_logs/components/AuditLogsActions.js +2 -1
- package/dist/modules/audit_logs/components/AuditLogsActions.js.map +2 -2
- package/dist/modules/audit_logs/extension-points.js +14 -0
- package/dist/modules/audit_logs/extension-points.js.map +7 -0
- package/dist/modules/auth/backend/roles/page.js +2 -1
- package/dist/modules/auth/backend/roles/page.js.map +2 -2
- package/dist/modules/auth/backend/users/page.js +2 -1
- package/dist/modules/auth/backend/users/page.js.map +2 -2
- package/dist/modules/auth/extension-points.js +21 -0
- package/dist/modules/auth/extension-points.js.map +7 -0
- package/dist/modules/auth/frontend/login.js +5 -1
- package/dist/modules/auth/frontend/login.js.map +2 -2
- package/dist/modules/business_rules/backend/rules/page.js +2 -1
- package/dist/modules/business_rules/backend/rules/page.js.map +2 -2
- package/dist/modules/business_rules/events.js +13 -0
- package/dist/modules/business_rules/events.js.map +7 -0
- package/dist/modules/business_rules/extension-points.js +13 -0
- package/dist/modules/business_rules/extension-points.js.map +7 -0
- package/dist/modules/catalog/backend/catalog/products/[id]/page.js +2 -1
- package/dist/modules/catalog/backend/catalog/products/[id]/page.js.map +2 -2
- package/dist/modules/catalog/backend/catalog/products/create/page.js +2 -1
- package/dist/modules/catalog/backend/catalog/products/create/page.js.map +2 -2
- package/dist/modules/catalog/components/categories/CategoriesDataTable.js +2 -1
- package/dist/modules/catalog/components/categories/CategoriesDataTable.js.map +2 -2
- package/dist/modules/catalog/components/products/ProductsDataTable.js +3 -2
- package/dist/modules/catalog/components/products/ProductsDataTable.js.map +2 -2
- package/dist/modules/catalog/events.js +1 -0
- package/dist/modules/catalog/events.js.map +2 -2
- package/dist/modules/catalog/extension-points.js +27 -0
- package/dist/modules/catalog/extension-points.js.map +7 -0
- package/dist/modules/communication_channels/backend/communication_channels/channels/page.js +2 -1
- package/dist/modules/communication_channels/backend/communication_channels/channels/page.js.map +2 -2
- package/dist/modules/communication_channels/backend/profile/communication-channels/page.js +3 -2
- package/dist/modules/communication_channels/backend/profile/communication-channels/page.js.map +2 -2
- package/dist/modules/communication_channels/extension-points.js +20 -0
- package/dist/modules/communication_channels/extension-points.js.map +7 -0
- package/dist/modules/configs/backend/config/system-status/page.js +2 -1
- package/dist/modules/configs/backend/config/system-status/page.js.map +2 -2
- package/dist/modules/configs/extension-points.js +18 -0
- package/dist/modules/configs/extension-points.js.map +7 -0
- package/dist/modules/currencies/backend/currencies/page.js +2 -1
- package/dist/modules/currencies/backend/currencies/page.js.map +2 -2
- package/dist/modules/currencies/backend/exchange-rates/page.js +2 -1
- package/dist/modules/currencies/backend/exchange-rates/page.js.map +2 -2
- package/dist/modules/currencies/extension-points.js +14 -0
- package/dist/modules/currencies/extension-points.js.map +7 -0
- package/dist/modules/customer_accounts/backend/customer_accounts/roles/page.js +2 -1
- package/dist/modules/customer_accounts/backend/customer_accounts/roles/page.js.map +2 -2
- package/dist/modules/customer_accounts/backend/customer_accounts/users/page.js +2 -1
- package/dist/modules/customer_accounts/backend/customer_accounts/users/page.js.map +2 -2
- package/dist/modules/customer_accounts/extension-points.js +14 -0
- package/dist/modules/customer_accounts/extension-points.js.map +7 -0
- package/dist/modules/customers/api/deals/summary/route.js +9 -115
- package/dist/modules/customers/api/deals/summary/route.js.map +2 -2
- package/dist/modules/customers/backend/customers/companies/[id]/page.js +2 -1
- package/dist/modules/customers/backend/customers/companies/[id]/page.js.map +2 -2
- package/dist/modules/customers/backend/customers/companies/page.js +2 -1
- package/dist/modules/customers/backend/customers/companies/page.js.map +2 -2
- package/dist/modules/customers/backend/customers/companies-v2/[id]/page.js +5 -4
- package/dist/modules/customers/backend/customers/companies-v2/[id]/page.js.map +2 -2
- package/dist/modules/customers/backend/customers/deals/[id]/page.js +5 -4
- package/dist/modules/customers/backend/customers/deals/[id]/page.js.map +2 -2
- package/dist/modules/customers/backend/customers/deals/page.js +2 -1
- package/dist/modules/customers/backend/customers/deals/page.js.map +2 -2
- package/dist/modules/customers/backend/customers/people/[id]/page.js +2 -1
- package/dist/modules/customers/backend/customers/people/[id]/page.js.map +2 -2
- package/dist/modules/customers/backend/customers/people/page.js +2 -1
- package/dist/modules/customers/backend/customers/people/page.js.map +2 -2
- package/dist/modules/customers/backend/customers/people-v2/[id]/page.js +5 -4
- package/dist/modules/customers/backend/customers/people-v2/[id]/page.js.map +2 -2
- package/dist/modules/customers/components/CustomerTodosTable.js +2 -1
- package/dist/modules/customers/components/CustomerTodosTable.js.map +2 -2
- package/dist/modules/customers/extension-points.js +42 -0
- package/dist/modules/customers/extension-points.js.map +7 -0
- package/dist/modules/customers/lib/calendar/format.js +8 -4
- package/dist/modules/customers/lib/calendar/format.js.map +2 -2
- package/dist/modules/customers/lib/dealsSummaryQueries.js +144 -0
- package/dist/modules/customers/lib/dealsSummaryQueries.js.map +7 -0
- package/dist/modules/data_sync/backend/data-sync/page.js +2 -1
- package/dist/modules/data_sync/backend/data-sync/page.js.map +2 -2
- package/dist/modules/data_sync/extension-points.js +13 -0
- package/dist/modules/data_sync/extension-points.js.map +7 -0
- package/dist/modules/directory/backend/directory/organizations/page.js +2 -1
- package/dist/modules/directory/backend/directory/organizations/page.js.map +2 -2
- package/dist/modules/directory/backend/directory/tenants/page.js +2 -1
- package/dist/modules/directory/backend/directory/tenants/page.js.map +2 -2
- package/dist/modules/directory/extension-points.js +14 -0
- package/dist/modules/directory/extension-points.js.map +7 -0
- package/dist/modules/entities/backend/entities/user/[entityId]/records/page.js +5 -1
- package/dist/modules/entities/backend/entities/user/[entityId]/records/page.js.map +2 -2
- package/dist/modules/entities/components/SystemEntitiesTable.js +2 -1
- package/dist/modules/entities/components/SystemEntitiesTable.js.map +2 -2
- package/dist/modules/entities/components/UserEntitiesTable.js +2 -1
- package/dist/modules/entities/components/UserEntitiesTable.js.map +2 -2
- package/dist/modules/entities/extension-points.js +21 -0
- package/dist/modules/entities/extension-points.js.map +7 -0
- package/dist/modules/integrations/backend/integrations/[id]/page.js +2 -4
- package/dist/modules/integrations/backend/integrations/[id]/page.js.map +2 -2
- package/dist/modules/integrations/extension-points.js +30 -0
- package/dist/modules/integrations/extension-points.js.map +7 -0
- package/dist/modules/messages/components/ComposeMessagePageClient.js +2 -1
- package/dist/modules/messages/components/ComposeMessagePageClient.js.map +2 -2
- package/dist/modules/messages/components/MessageDetailPageClient.js +3 -2
- package/dist/modules/messages/components/MessageDetailPageClient.js.map +2 -2
- package/dist/modules/messages/components/MessagesInboxPageClient.js +2 -1
- package/dist/modules/messages/components/MessagesInboxPageClient.js.map +2 -2
- package/dist/modules/messages/extension-points.js +16 -0
- package/dist/modules/messages/extension-points.js.map +7 -0
- package/dist/modules/payment_gateways/backend/payment-gateways/page.js +3 -2
- package/dist/modules/payment_gateways/backend/payment-gateways/page.js.map +2 -2
- package/dist/modules/payment_gateways/extension-points.js +19 -0
- package/dist/modules/payment_gateways/extension-points.js.map +7 -0
- package/dist/modules/portal/extension-points.js +32 -0
- package/dist/modules/portal/extension-points.js.map +7 -0
- package/dist/modules/portal/frontend/[orgSlug]/portal/dashboard/page.js +3 -3
- package/dist/modules/portal/frontend/[orgSlug]/portal/dashboard/page.js.map +2 -2
- package/dist/modules/portal/frontend/[orgSlug]/portal/login/page.js +3 -3
- package/dist/modules/portal/frontend/[orgSlug]/portal/login/page.js.map +2 -2
- package/dist/modules/portal/frontend/[orgSlug]/portal/page.js +3 -3
- package/dist/modules/portal/frontend/[orgSlug]/portal/page.js.map +2 -2
- package/dist/modules/portal/frontend/[orgSlug]/portal/profile/page.js +3 -3
- package/dist/modules/portal/frontend/[orgSlug]/portal/profile/page.js.map +2 -2
- package/dist/modules/portal/frontend/[orgSlug]/portal/reset-password/page.js +3 -3
- package/dist/modules/portal/frontend/[orgSlug]/portal/reset-password/page.js.map +2 -2
- package/dist/modules/portal/frontend/[orgSlug]/portal/signup/page.js +3 -3
- package/dist/modules/portal/frontend/[orgSlug]/portal/signup/page.js.map +2 -2
- package/dist/modules/query_index/components/QueryIndexesTable.js +2 -1
- package/dist/modules/query_index/components/QueryIndexesTable.js.map +2 -2
- package/dist/modules/query_index/events.js +20 -0
- package/dist/modules/query_index/events.js.map +7 -0
- package/dist/modules/query_index/extension-points.js +13 -0
- package/dist/modules/query_index/extension-points.js.map +7 -0
- package/dist/modules/resources/backend/resources/resource-types/page.js +2 -1
- package/dist/modules/resources/backend/resources/resource-types/page.js.map +2 -2
- package/dist/modules/resources/backend/resources/resources/page.js +2 -1
- package/dist/modules/resources/backend/resources/resources/page.js.map +2 -2
- package/dist/modules/resources/extension-points.js +14 -0
- package/dist/modules/resources/extension-points.js.map +7 -0
- package/dist/modules/sales/backend/sales/documents/[id]/page.js +11 -3
- package/dist/modules/sales/backend/sales/documents/[id]/page.js.map +2 -2
- package/dist/modules/sales/components/documents/ItemsSection.js +2 -1
- package/dist/modules/sales/components/documents/ItemsSection.js.map +2 -2
- package/dist/modules/sales/components/documents/SalesDocumentsTable.js +4 -1
- package/dist/modules/sales/components/documents/SalesDocumentsTable.js.map +2 -2
- package/dist/modules/sales/events.js +1 -0
- package/dist/modules/sales/events.js.map +2 -2
- package/dist/modules/sales/extension-points.js +36 -0
- package/dist/modules/sales/extension-points.js.map +7 -0
- package/dist/modules/wms/components/backend/WmsConfigurationPage.js +5 -4
- package/dist/modules/wms/components/backend/WmsConfigurationPage.js.map +2 -2
- package/dist/modules/wms/components/backend/WmsInventoryConsolePage.js +4 -3
- package/dist/modules/wms/components/backend/WmsInventoryConsolePage.js.map +2 -2
- package/dist/modules/wms/components/backend/WmsLocationDetailPage.js +3 -2
- package/dist/modules/wms/components/backend/WmsLocationDetailPage.js.map +2 -2
- package/dist/modules/wms/components/backend/WmsLotDetailPage.js +3 -2
- package/dist/modules/wms/components/backend/WmsLotDetailPage.js.map +2 -2
- package/dist/modules/wms/components/backend/WmsLotsListPage.js +2 -1
- package/dist/modules/wms/components/backend/WmsLotsListPage.js.map +2 -2
- package/dist/modules/wms/components/backend/WmsSkuDetailPage.js +3 -2
- package/dist/modules/wms/components/backend/WmsSkuDetailPage.js.map +2 -2
- package/dist/modules/wms/extension-points.js +26 -0
- package/dist/modules/wms/extension-points.js.map +7 -0
- package/dist/modules/workflows/backend/definitions/page.js +2 -1
- package/dist/modules/workflows/backend/definitions/page.js.map +2 -2
- package/dist/modules/workflows/backend/instances/page.js +2 -1
- package/dist/modules/workflows/backend/instances/page.js.map +2 -2
- package/dist/modules/workflows/backend/tasks/page.js +2 -1
- package/dist/modules/workflows/backend/tasks/page.js.map +2 -2
- package/dist/modules/workflows/events.js +1 -0
- package/dist/modules/workflows/events.js.map +2 -2
- package/dist/modules/workflows/extension-points.js +15 -0
- package/dist/modules/workflows/extension-points.js.map +7 -0
- package/package.json +7 -7
- package/src/modules/api_keys/backend/api-keys/page.tsx +2 -1
- package/src/modules/api_keys/extension-points.ts +13 -0
- package/src/modules/audit_logs/components/AccessLogsTable.tsx +2 -1
- package/src/modules/audit_logs/components/AuditLogsActions.tsx +2 -1
- package/src/modules/audit_logs/extension-points.ts +11 -0
- package/src/modules/auth/backend/roles/page.tsx +2 -1
- package/src/modules/auth/backend/users/page.tsx +2 -1
- package/src/modules/auth/extension-points.ts +18 -0
- package/src/modules/auth/frontend/login.tsx +5 -1
- package/src/modules/business_rules/backend/rules/page.tsx +2 -1
- package/src/modules/business_rules/events.ts +10 -0
- package/src/modules/business_rules/extension-points.ts +10 -0
- package/src/modules/catalog/backend/catalog/products/[id]/page.tsx +2 -1
- package/src/modules/catalog/backend/catalog/products/create/page.tsx +2 -1
- package/src/modules/catalog/components/categories/CategoriesDataTable.tsx +2 -1
- package/src/modules/catalog/components/products/ProductsDataTable.tsx +3 -2
- package/src/modules/catalog/events.ts +1 -0
- package/src/modules/catalog/extension-points.ts +24 -0
- package/src/modules/communication_channels/backend/communication_channels/channels/page.tsx +2 -1
- package/src/modules/communication_channels/backend/profile/communication-channels/page.tsx +3 -2
- package/src/modules/communication_channels/extension-points.ts +17 -0
- package/src/modules/configs/backend/config/system-status/page.tsx +2 -1
- package/src/modules/configs/extension-points.ts +15 -0
- package/src/modules/currencies/backend/currencies/page.tsx +2 -1
- package/src/modules/currencies/backend/exchange-rates/page.tsx +2 -1
- package/src/modules/currencies/extension-points.ts +11 -0
- package/src/modules/customer_accounts/backend/customer_accounts/roles/page.tsx +2 -1
- package/src/modules/customer_accounts/backend/customer_accounts/users/page.tsx +2 -1
- package/src/modules/customer_accounts/extension-points.ts +11 -0
- package/src/modules/customers/api/deals/summary/route.ts +10 -158
- package/src/modules/customers/backend/customers/companies/[id]/page.tsx +2 -1
- package/src/modules/customers/backend/customers/companies/page.tsx +2 -1
- package/src/modules/customers/backend/customers/companies-v2/[id]/page.tsx +5 -4
- package/src/modules/customers/backend/customers/deals/[id]/page.tsx +5 -4
- package/src/modules/customers/backend/customers/deals/page.tsx +2 -1
- package/src/modules/customers/backend/customers/people/[id]/page.tsx +2 -1
- package/src/modules/customers/backend/customers/people/page.tsx +2 -1
- package/src/modules/customers/backend/customers/people-v2/[id]/page.tsx +5 -4
- package/src/modules/customers/components/CustomerTodosTable.tsx +2 -1
- package/src/modules/customers/extension-points.ts +40 -0
- package/src/modules/customers/lib/calendar/format.ts +10 -4
- package/src/modules/customers/lib/dealsSummaryQueries.ts +211 -0
- package/src/modules/data_sync/backend/data-sync/page.tsx +2 -1
- package/src/modules/data_sync/extension-points.ts +10 -0
- package/src/modules/directory/backend/directory/organizations/page.tsx +2 -1
- package/src/modules/directory/backend/directory/tenants/page.tsx +2 -1
- package/src/modules/directory/extension-points.ts +11 -0
- package/src/modules/entities/backend/entities/user/[entityId]/records/page.tsx +5 -1
- package/src/modules/entities/components/SystemEntitiesTable.tsx +2 -1
- package/src/modules/entities/components/UserEntitiesTable.tsx +2 -1
- package/src/modules/entities/extension-points.ts +18 -0
- package/src/modules/integrations/backend/integrations/[id]/page.tsx +2 -2
- package/src/modules/integrations/extension-points.ts +27 -0
- package/src/modules/messages/components/ComposeMessagePageClient.tsx +2 -1
- package/src/modules/messages/components/MessageDetailPageClient.tsx +3 -2
- package/src/modules/messages/components/MessagesInboxPageClient.tsx +2 -1
- package/src/modules/messages/extension-points.ts +13 -0
- package/src/modules/payment_gateways/backend/payment-gateways/page.tsx +3 -2
- package/src/modules/payment_gateways/extension-points.ts +16 -0
- package/src/modules/portal/extension-points.ts +30 -0
- package/src/modules/portal/frontend/[orgSlug]/portal/dashboard/page.tsx +3 -3
- package/src/modules/portal/frontend/[orgSlug]/portal/login/page.tsx +3 -3
- package/src/modules/portal/frontend/[orgSlug]/portal/page.tsx +3 -3
- package/src/modules/portal/frontend/[orgSlug]/portal/profile/page.tsx +3 -3
- package/src/modules/portal/frontend/[orgSlug]/portal/reset-password/page.tsx +4 -4
- package/src/modules/portal/frontend/[orgSlug]/portal/signup/page.tsx +3 -3
- package/src/modules/query_index/components/QueryIndexesTable.tsx +2 -1
- package/src/modules/query_index/events.ts +17 -0
- package/src/modules/query_index/extension-points.ts +10 -0
- package/src/modules/resources/backend/resources/resource-types/page.tsx +2 -1
- package/src/modules/resources/backend/resources/resources/page.tsx +2 -1
- package/src/modules/resources/extension-points.ts +11 -0
- package/src/modules/sales/backend/sales/documents/[id]/page.tsx +11 -3
- package/src/modules/sales/components/documents/ItemsSection.tsx +2 -1
- package/src/modules/sales/components/documents/SalesDocumentsTable.tsx +6 -1
- package/src/modules/sales/events.ts +1 -0
- package/src/modules/sales/extension-points.ts +33 -0
- package/src/modules/wms/components/backend/WmsConfigurationPage.tsx +5 -4
- package/src/modules/wms/components/backend/WmsInventoryConsolePage.tsx +4 -3
- package/src/modules/wms/components/backend/WmsLocationDetailPage.tsx +3 -2
- package/src/modules/wms/components/backend/WmsLotDetailPage.tsx +3 -2
- package/src/modules/wms/components/backend/WmsLotsListPage.tsx +2 -1
- package/src/modules/wms/components/backend/WmsSkuDetailPage.tsx +3 -2
- package/src/modules/wms/extension-points.ts +23 -0
- package/src/modules/workflows/backend/definitions/page.tsx +2 -1
- package/src/modules/workflows/backend/instances/page.tsx +2 -1
- package/src/modules/workflows/backend/tasks/page.tsx +2 -1
- package/src/modules/workflows/events.ts +1 -0
- package/src/modules/workflows/extension-points.ts +12 -0
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use client"
|
|
2
2
|
|
|
3
3
|
import * as React from 'react'
|
|
4
|
+
import { extensionPoints } from '@open-mercato/core/modules/customers/extension-points'
|
|
4
5
|
import Link from 'next/link'
|
|
5
6
|
import { useRouter, useSearchParams, usePathname } from 'next/navigation'
|
|
6
7
|
import { User, Hash, Users, Building2 } from 'lucide-react'
|
|
@@ -502,8 +503,8 @@ export default function PersonDetailV2Page({ params }: { params?: { id?: string
|
|
|
502
503
|
<PageBody>
|
|
503
504
|
<div className="space-y-4">
|
|
504
505
|
{/* UMES header injection (third-party extensions) */}
|
|
505
|
-
<InjectionSpot spotId=
|
|
506
|
-
<InjectionSpot spotId=
|
|
506
|
+
<InjectionSpot spotId={extensionPoints.hosts.personHeader.spotId} context={injectionContext} data={data} />
|
|
507
|
+
<InjectionSpot spotId={extensionPoints.hosts.personStatusBadges.spotId} context={injectionContext} data={data} />
|
|
507
508
|
|
|
508
509
|
{/* Persistent person header */}
|
|
509
510
|
<PersonDetailHeader
|
|
@@ -537,7 +538,7 @@ export default function PersonDetailV2Page({ params }: { params?: { id?: string
|
|
|
537
538
|
<CrudForm<PersonEditFormValues>
|
|
538
539
|
embedded
|
|
539
540
|
trackDirtyWhenEmbedded
|
|
540
|
-
injectionSpotId=
|
|
541
|
+
injectionSpotId={extensionPoints.hosts.personForm.spotId}
|
|
541
542
|
entityIds={[E.customers.customer_entity, E.customers.customer_person_profile]}
|
|
542
543
|
schema={formSchema}
|
|
543
544
|
fields={fields}
|
|
@@ -719,7 +720,7 @@ export default function PersonDetailV2Page({ params }: { params?: { id?: string
|
|
|
719
720
|
})()}
|
|
720
721
|
|
|
721
722
|
{/* UMES footer injection */}
|
|
722
|
-
<InjectionSpot spotId=
|
|
723
|
+
<InjectionSpot spotId={extensionPoints.hosts.personFooter.spotId} context={injectionContext} data={data} />
|
|
723
724
|
|
|
724
725
|
{/* Schedule Activity Dialog — opened from PlannedActivities "+ Schedule" or other triggers */}
|
|
725
726
|
<ScheduleActivityDialog
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use client"
|
|
2
2
|
|
|
3
3
|
import * as React from 'react'
|
|
4
|
+
import { extensionPoints } from '@open-mercato/core/modules/customers/extension-points'
|
|
4
5
|
import Link from 'next/link'
|
|
5
6
|
import { useRouter } from 'next/navigation'
|
|
6
7
|
import type { ColumnDef } from '@tanstack/react-table'
|
|
@@ -253,7 +254,7 @@ export function CustomerTodosTable(): React.JSX.Element {
|
|
|
253
254
|
setSearch(value)
|
|
254
255
|
setPage(1)
|
|
255
256
|
}}
|
|
256
|
-
perspective={{ tableId:
|
|
257
|
+
perspective={{ tableId: extensionPoints.hosts.todosTable.tableId }}
|
|
257
258
|
rowActions={(row) => {
|
|
258
259
|
const customerLink = buildCustomerHref(row)
|
|
259
260
|
const todoHref = row.externalHref ?? resolveTodoHref(row.todoSource, row.todoId)
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import {
|
|
2
|
+
crudFormExtensionHost,
|
|
3
|
+
dataTableExtensionHost,
|
|
4
|
+
defineModuleExtensionPoints,
|
|
5
|
+
injectionExtensionHost,
|
|
6
|
+
} from '@open-mercato/shared/modules/widgets/extension-points'
|
|
7
|
+
|
|
8
|
+
const detailHost = (spotId: string, source: string) => injectionExtensionHost({
|
|
9
|
+
family: 'detail',
|
|
10
|
+
spotId,
|
|
11
|
+
supported: ['render-widget'],
|
|
12
|
+
contextContract: 'customers.detail.v1',
|
|
13
|
+
source,
|
|
14
|
+
})
|
|
15
|
+
|
|
16
|
+
export const extensionPoints = defineModuleExtensionPoints({
|
|
17
|
+
moduleId: 'customers',
|
|
18
|
+
hosts: {
|
|
19
|
+
companiesTable: dataTableExtensionHost({ tableId: 'customers.companies.list', source: 'backend/customers/companies/page.tsx' }),
|
|
20
|
+
dealsTable: dataTableExtensionHost({ tableId: 'customers.deals.list', source: 'backend/customers/deals/page.tsx' }),
|
|
21
|
+
peopleTable: dataTableExtensionHost({ tableId: 'customers.people.list', source: 'backend/customers/people/page.tsx' }),
|
|
22
|
+
todosTable: dataTableExtensionHost({ tableId: 'customers.todos.list', source: 'components/CustomerTodosTable.tsx' }),
|
|
23
|
+
companyForm: crudFormExtensionHost({ entityId: 'customers.company', spotId: 'crud-form:customers.company', source: 'backend/customers/companies-v2/[id]/page.tsx' }),
|
|
24
|
+
dealForm: crudFormExtensionHost({ entityId: 'customers.deal', spotId: 'crud-form:customers.deal', source: 'backend/customers/deals/[id]/page.tsx' }),
|
|
25
|
+
personForm: crudFormExtensionHost({ entityId: 'customers.person', spotId: 'crud-form:customers.person', source: 'backend/customers/people-v2/[id]/page.tsx' }),
|
|
26
|
+
companyHeader: detailHost('detail:customers.company:header', 'backend/customers/companies-v2/[id]/page.tsx'),
|
|
27
|
+
companyStatusBadges: detailHost('detail:customers.company:status-badges', 'backend/customers/companies-v2/[id]/page.tsx'),
|
|
28
|
+
companyFooter: detailHost('detail:customers.company:footer', 'backend/customers/companies-v2/[id]/page.tsx'),
|
|
29
|
+
companyLegacyDetails: detailHost('customers.company.detail:details', 'backend/customers/companies/[id]/page.tsx'),
|
|
30
|
+
dealHeader: detailHost('detail:customers.deal:header', 'backend/customers/deals/[id]/page.tsx'),
|
|
31
|
+
dealStatusBadges: detailHost('detail:customers.deal:status-badges', 'backend/customers/deals/[id]/page.tsx'),
|
|
32
|
+
dealFooter: detailHost('detail:customers.deal:footer', 'backend/customers/deals/[id]/page.tsx'),
|
|
33
|
+
personHeader: detailHost('detail:customers.person:header', 'backend/customers/people-v2/[id]/page.tsx'),
|
|
34
|
+
personStatusBadges: detailHost('detail:customers.person:status-badges', 'backend/customers/people-v2/[id]/page.tsx'),
|
|
35
|
+
personFooter: detailHost('detail:customers.person:footer', 'backend/customers/people-v2/[id]/page.tsx'),
|
|
36
|
+
personLegacyDetails: detailHost('customers.person.detail:details', 'backend/customers/people/[id]/page.tsx'),
|
|
37
|
+
},
|
|
38
|
+
})
|
|
39
|
+
|
|
40
|
+
export default extensionPoints
|
|
@@ -2,6 +2,12 @@ const DATE_OPTIONS: Intl.DateTimeFormatOptions = { day: 'numeric', month: 'short
|
|
|
2
2
|
|
|
3
3
|
const TIME_OPTIONS: Intl.DateTimeFormatOptions = { hour: 'numeric', minute: '2-digit' }
|
|
4
4
|
|
|
5
|
+
const NON_CANONICAL_INTL_SPACING = /[\u00a0\u2007\u2009\u202f]/g
|
|
6
|
+
|
|
7
|
+
function normalizeIntlSpacing(value: string): string {
|
|
8
|
+
return value.replace(NON_CANONICAL_INTL_SPACING, ' ')
|
|
9
|
+
}
|
|
10
|
+
|
|
5
11
|
export function formatDateLabel(locale: string, date: Date): string {
|
|
6
12
|
return new Intl.DateTimeFormat(locale, DATE_OPTIONS).format(date)
|
|
7
13
|
}
|
|
@@ -9,17 +15,17 @@ export function formatDateLabel(locale: string, date: Date): string {
|
|
|
9
15
|
export function formatDateRangeLabel(locale: string, from: Date, to: Date): string {
|
|
10
16
|
const formatter = new Intl.DateTimeFormat(locale, DATE_OPTIONS)
|
|
11
17
|
try {
|
|
12
|
-
return formatter.formatRange(from, to)
|
|
18
|
+
return normalizeIntlSpacing(formatter.formatRange(from, to))
|
|
13
19
|
} catch {
|
|
14
|
-
return `${formatter.format(from)} – ${formatter.format(to)}`
|
|
20
|
+
return normalizeIntlSpacing(`${formatter.format(from)} – ${formatter.format(to)}`)
|
|
15
21
|
}
|
|
16
22
|
}
|
|
17
23
|
|
|
18
24
|
export function formatTimeRangeLabel(locale: string, start: Date, end: Date): string {
|
|
19
25
|
const formatter = new Intl.DateTimeFormat(locale, TIME_OPTIONS)
|
|
20
26
|
try {
|
|
21
|
-
return formatter.formatRange(start, end)
|
|
27
|
+
return normalizeIntlSpacing(formatter.formatRange(start, end))
|
|
22
28
|
} catch {
|
|
23
|
-
return `${formatter.format(start)} – ${formatter.format(end)}`
|
|
29
|
+
return normalizeIntlSpacing(`${formatter.format(start)} – ${formatter.format(end)}`)
|
|
24
30
|
}
|
|
25
31
|
}
|
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
import type { EntityManager as CoreEntityManager } from '@mikro-orm/core'
|
|
2
|
+
import type { EntityManager as PgEntityManager } from '@mikro-orm/postgresql'
|
|
3
|
+
import { fetchStuckDealIds } from './stuckDeals'
|
|
4
|
+
|
|
5
|
+
type DateWindow = {
|
|
6
|
+
start: Date
|
|
7
|
+
end: Date
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export type OpenPipelineRow = {
|
|
11
|
+
stage: string | null
|
|
12
|
+
currency: string | null
|
|
13
|
+
total: string | number | null
|
|
14
|
+
count: string | number
|
|
15
|
+
owner_user_id: string | null
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export type WindowSumRow = {
|
|
19
|
+
currency: string | null
|
|
20
|
+
current_total: string | number | null
|
|
21
|
+
current_count: string | number
|
|
22
|
+
previous_total: string | number | null
|
|
23
|
+
previous_count: string | number
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export type WinLossRow = {
|
|
27
|
+
current_won: string | number
|
|
28
|
+
current_lost: string | number
|
|
29
|
+
previous_won: string | number
|
|
30
|
+
previous_lost: string | number
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export type WinRateMonthRow = {
|
|
34
|
+
period: string
|
|
35
|
+
won: string | number
|
|
36
|
+
lost: string | number
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export type DealsSummaryQueryRows = {
|
|
40
|
+
openRows: OpenPipelineRow[]
|
|
41
|
+
inflowRows: WindowSumRow[]
|
|
42
|
+
wonRows: WindowSumRow[]
|
|
43
|
+
winLossRows: WinLossRow[]
|
|
44
|
+
seriesRows: WinRateMonthRow[]
|
|
45
|
+
overdueRows: Array<{ id: string }>
|
|
46
|
+
openStuckIds: string[]
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export type DealsSummaryQueryInput = {
|
|
50
|
+
em: CoreEntityManager
|
|
51
|
+
tenantId: string
|
|
52
|
+
organizationIds: string[]
|
|
53
|
+
currentQuarter: DateWindow
|
|
54
|
+
previousQuarter: DateWindow
|
|
55
|
+
seriesStart: Date
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
type SqlPredicate = {
|
|
59
|
+
clause: string
|
|
60
|
+
values: string[]
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export function buildOpenDealPredicate(statuses: readonly string[]): SqlPredicate {
|
|
64
|
+
if (statuses.length === 0) {
|
|
65
|
+
throw new Error('[internal] Open-deal predicate requires at least one status')
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const placeholders = statuses.map(() => '?').join(',')
|
|
69
|
+
return {
|
|
70
|
+
clause: `status IN (${placeholders}) AND closure_outcome IS NULL`,
|
|
71
|
+
values: [...statuses],
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export async function loadDealsSummaryQueryRows(input: DealsSummaryQueryInput): Promise<DealsSummaryQueryRows> {
|
|
76
|
+
if (input.organizationIds.length === 0) {
|
|
77
|
+
throw new Error('[internal] Deals summary query requires an organization scope')
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const connection = input.em.getConnection()
|
|
81
|
+
const organizationPlaceholders = input.organizationIds.map(() => '?').join(',')
|
|
82
|
+
const scopeWhere = `tenant_id = ? AND organization_id IN (${organizationPlaceholders}) AND deleted_at IS NULL`
|
|
83
|
+
const scopeValues: Array<string | number | null> = [input.tenantId, ...input.organizationIds]
|
|
84
|
+
const openDealsPredicate = buildOpenDealPredicate(['open', 'in_progress'])
|
|
85
|
+
|
|
86
|
+
const openRows = await connection.execute<OpenPipelineRow[]>(
|
|
87
|
+
`SELECT
|
|
88
|
+
pipeline_stage AS stage,
|
|
89
|
+
UPPER(COALESCE(value_currency, '')) AS currency,
|
|
90
|
+
COALESCE(SUM(value_amount), 0) AS total,
|
|
91
|
+
COUNT(*) AS count,
|
|
92
|
+
owner_user_id
|
|
93
|
+
FROM customer_deals
|
|
94
|
+
WHERE ${scopeWhere} AND ${openDealsPredicate.clause}
|
|
95
|
+
GROUP BY pipeline_stage, UPPER(COALESCE(value_currency, '')), owner_user_id`,
|
|
96
|
+
[...scopeValues, ...openDealsPredicate.values],
|
|
97
|
+
)
|
|
98
|
+
|
|
99
|
+
const inflowRows = await connection.execute<WindowSumRow[]>(
|
|
100
|
+
`SELECT
|
|
101
|
+
UPPER(COALESCE(value_currency, '')) AS currency,
|
|
102
|
+
COALESCE(SUM(value_amount) FILTER (WHERE created_at >= ? AND created_at < ?), 0) AS current_total,
|
|
103
|
+
COUNT(*) FILTER (WHERE created_at >= ? AND created_at < ?) AS current_count,
|
|
104
|
+
COALESCE(SUM(value_amount) FILTER (WHERE created_at >= ? AND created_at < ?), 0) AS previous_total,
|
|
105
|
+
COUNT(*) FILTER (WHERE created_at >= ? AND created_at < ?) AS previous_count
|
|
106
|
+
FROM customer_deals
|
|
107
|
+
WHERE ${scopeWhere} AND ${openDealsPredicate.clause}
|
|
108
|
+
GROUP BY UPPER(COALESCE(value_currency, ''))`,
|
|
109
|
+
[
|
|
110
|
+
input.currentQuarter.start.toISOString(),
|
|
111
|
+
input.currentQuarter.end.toISOString(),
|
|
112
|
+
input.currentQuarter.start.toISOString(),
|
|
113
|
+
input.currentQuarter.end.toISOString(),
|
|
114
|
+
input.previousQuarter.start.toISOString(),
|
|
115
|
+
input.previousQuarter.end.toISOString(),
|
|
116
|
+
input.previousQuarter.start.toISOString(),
|
|
117
|
+
input.previousQuarter.end.toISOString(),
|
|
118
|
+
...scopeValues,
|
|
119
|
+
...openDealsPredicate.values,
|
|
120
|
+
],
|
|
121
|
+
)
|
|
122
|
+
|
|
123
|
+
const wonRows = await connection.execute<WindowSumRow[]>(
|
|
124
|
+
`SELECT
|
|
125
|
+
UPPER(COALESCE(value_currency, '')) AS currency,
|
|
126
|
+
COALESCE(SUM(value_amount) FILTER (WHERE updated_at >= ? AND updated_at < ?), 0) AS current_total,
|
|
127
|
+
COUNT(*) FILTER (WHERE updated_at >= ? AND updated_at < ?) AS current_count,
|
|
128
|
+
COALESCE(SUM(value_amount) FILTER (WHERE updated_at >= ? AND updated_at < ?), 0) AS previous_total,
|
|
129
|
+
COUNT(*) FILTER (WHERE updated_at >= ? AND updated_at < ?) AS previous_count
|
|
130
|
+
FROM customer_deals
|
|
131
|
+
WHERE ${scopeWhere} AND (status = 'win' OR closure_outcome = 'won')
|
|
132
|
+
GROUP BY UPPER(COALESCE(value_currency, ''))`,
|
|
133
|
+
[
|
|
134
|
+
input.currentQuarter.start.toISOString(),
|
|
135
|
+
input.currentQuarter.end.toISOString(),
|
|
136
|
+
input.currentQuarter.start.toISOString(),
|
|
137
|
+
input.currentQuarter.end.toISOString(),
|
|
138
|
+
input.previousQuarter.start.toISOString(),
|
|
139
|
+
input.previousQuarter.end.toISOString(),
|
|
140
|
+
input.previousQuarter.start.toISOString(),
|
|
141
|
+
input.previousQuarter.end.toISOString(),
|
|
142
|
+
...scopeValues,
|
|
143
|
+
],
|
|
144
|
+
)
|
|
145
|
+
|
|
146
|
+
const winLossRows = await connection.execute<WinLossRow[]>(
|
|
147
|
+
`SELECT
|
|
148
|
+
COUNT(*) FILTER (WHERE (status = 'win' OR closure_outcome = 'won') AND updated_at >= ? AND updated_at < ?) AS current_won,
|
|
149
|
+
COUNT(*) FILTER (WHERE (status = 'loose' OR closure_outcome = 'lost') AND updated_at >= ? AND updated_at < ?) AS current_lost,
|
|
150
|
+
COUNT(*) FILTER (WHERE (status = 'win' OR closure_outcome = 'won') AND updated_at >= ? AND updated_at < ?) AS previous_won,
|
|
151
|
+
COUNT(*) FILTER (WHERE (status = 'loose' OR closure_outcome = 'lost') AND updated_at >= ? AND updated_at < ?) AS previous_lost
|
|
152
|
+
FROM customer_deals
|
|
153
|
+
WHERE ${scopeWhere}`,
|
|
154
|
+
[
|
|
155
|
+
input.currentQuarter.start.toISOString(),
|
|
156
|
+
input.currentQuarter.end.toISOString(),
|
|
157
|
+
input.currentQuarter.start.toISOString(),
|
|
158
|
+
input.currentQuarter.end.toISOString(),
|
|
159
|
+
input.previousQuarter.start.toISOString(),
|
|
160
|
+
input.previousQuarter.end.toISOString(),
|
|
161
|
+
input.previousQuarter.start.toISOString(),
|
|
162
|
+
input.previousQuarter.end.toISOString(),
|
|
163
|
+
...scopeValues,
|
|
164
|
+
],
|
|
165
|
+
)
|
|
166
|
+
|
|
167
|
+
const seriesRows = await connection.execute<WinRateMonthRow[]>(
|
|
168
|
+
`SELECT
|
|
169
|
+
to_char(date_trunc('month', updated_at AT TIME ZONE 'UTC'), 'YYYY-MM') AS period,
|
|
170
|
+
COUNT(*) FILTER (WHERE status = 'win' OR closure_outcome = 'won') AS won,
|
|
171
|
+
COUNT(*) FILTER (WHERE status = 'loose' OR closure_outcome = 'lost') AS lost
|
|
172
|
+
FROM customer_deals
|
|
173
|
+
WHERE ${scopeWhere} AND updated_at >= ?
|
|
174
|
+
GROUP BY 1`,
|
|
175
|
+
[...scopeValues, input.seriesStart.toISOString()],
|
|
176
|
+
)
|
|
177
|
+
|
|
178
|
+
const overdueDealsPredicate = buildOpenDealPredicate(['open'])
|
|
179
|
+
const overdueRows = await connection.execute<Array<{ id: string }>>(
|
|
180
|
+
`SELECT id FROM customer_deals
|
|
181
|
+
WHERE ${scopeWhere} AND ${overdueDealsPredicate.clause} AND expected_close_at IS NOT NULL AND expected_close_at < CURRENT_DATE`,
|
|
182
|
+
[...scopeValues, ...overdueDealsPredicate.values],
|
|
183
|
+
)
|
|
184
|
+
|
|
185
|
+
const stuckIdLists = await Promise.all(
|
|
186
|
+
input.organizationIds.map((organizationId) =>
|
|
187
|
+
fetchStuckDealIds(input.em as unknown as PgEntityManager, organizationId, input.tenantId),
|
|
188
|
+
),
|
|
189
|
+
)
|
|
190
|
+
const stuckIdValues = Array.from(new Set(stuckIdLists.flat()))
|
|
191
|
+
let openStuckIds: string[] = []
|
|
192
|
+
if (stuckIdValues.length > 0) {
|
|
193
|
+
const stuckPlaceholders = stuckIdValues.map(() => '?').join(',')
|
|
194
|
+
const openStuckRows: Array<{ id: string }> = await connection.execute<Array<{ id: string }>>(
|
|
195
|
+
`SELECT id FROM customer_deals
|
|
196
|
+
WHERE ${scopeWhere} AND ${openDealsPredicate.clause} AND id IN (${stuckPlaceholders})`,
|
|
197
|
+
[...scopeValues, ...openDealsPredicate.values, ...stuckIdValues],
|
|
198
|
+
)
|
|
199
|
+
openStuckIds = openStuckRows.map((row) => row.id)
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
return {
|
|
203
|
+
openRows,
|
|
204
|
+
inflowRows,
|
|
205
|
+
wonRows,
|
|
206
|
+
winLossRows,
|
|
207
|
+
seriesRows,
|
|
208
|
+
overdueRows,
|
|
209
|
+
openStuckIds,
|
|
210
|
+
}
|
|
211
|
+
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"use client"
|
|
2
2
|
import * as React from 'react'
|
|
3
|
+
import { extensionPoints } from '@open-mercato/core/modules/data_sync/extension-points'
|
|
3
4
|
import Link from 'next/link'
|
|
4
5
|
import { useRouter } from 'next/navigation'
|
|
5
6
|
import { Page, PageBody } from '@open-mercato/ui/backend/Page'
|
|
@@ -984,7 +985,7 @@ export default function SyncRunsDashboardPage() {
|
|
|
984
985
|
searchValue={search}
|
|
985
986
|
onSearchChange={(value) => { setSearch(value); setPage(1) }}
|
|
986
987
|
searchPlaceholder={t('data_sync.dashboard.searchPlaceholder')}
|
|
987
|
-
perspective={{ tableId:
|
|
988
|
+
perspective={{ tableId: extensionPoints.hosts.runsTable.tableId }}
|
|
988
989
|
onRowClick={(row) => {
|
|
989
990
|
router.push(`/backend/data-sync/runs/${encodeURIComponent(row.id)}`)
|
|
990
991
|
}}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { dataTableExtensionHost, defineModuleExtensionPoints } from '@open-mercato/shared/modules/widgets/extension-points'
|
|
2
|
+
|
|
3
|
+
export const extensionPoints = defineModuleExtensionPoints({
|
|
4
|
+
moduleId: 'data_sync',
|
|
5
|
+
hosts: {
|
|
6
|
+
runsTable: dataTableExtensionHost({ tableId: 'data_sync.runs', source: 'backend/data-sync/page.tsx' }),
|
|
7
|
+
},
|
|
8
|
+
})
|
|
9
|
+
|
|
10
|
+
export default extensionPoints
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"use client"
|
|
2
2
|
import * as React from 'react'
|
|
3
|
+
import { extensionPoints } from '@open-mercato/core/modules/directory/extension-points'
|
|
3
4
|
import Link from 'next/link'
|
|
4
5
|
import { useQuery, useQueryClient } from '@tanstack/react-query'
|
|
5
6
|
import type { ColumnDef } from '@tanstack/react-table'
|
|
@@ -271,7 +272,7 @@ export default function DirectoryOrganizationsPage() {
|
|
|
271
272
|
setPage(1)
|
|
272
273
|
}}
|
|
273
274
|
sortable={false}
|
|
274
|
-
perspective={{ tableId:
|
|
275
|
+
perspective={{ tableId: extensionPoints.hosts.organizationsTable.tableId }}
|
|
275
276
|
rowActions={(row) => (
|
|
276
277
|
canManage ? (
|
|
277
278
|
<RowActions
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"use client"
|
|
2
2
|
import * as React from 'react'
|
|
3
|
+
import { extensionPoints } from '@open-mercato/core/modules/directory/extension-points'
|
|
3
4
|
import Link from 'next/link'
|
|
4
5
|
import { useQuery, useQueryClient } from '@tanstack/react-query'
|
|
5
6
|
import type { ColumnDef, SortingState } from '@tanstack/react-table'
|
|
@@ -193,7 +194,7 @@ export default function DirectoryTenantsPage() {
|
|
|
193
194
|
sortable
|
|
194
195
|
sorting={sorting}
|
|
195
196
|
onSortingChange={(state) => { setSorting(state); setPage(1) }}
|
|
196
|
-
perspective={{ tableId:
|
|
197
|
+
perspective={{ tableId: extensionPoints.hosts.tenantsTable.tableId }}
|
|
197
198
|
rowActions={(row) => (
|
|
198
199
|
canManage ? (
|
|
199
200
|
<RowActions
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { dataTableExtensionHost, defineModuleExtensionPoints } from '@open-mercato/shared/modules/widgets/extension-points'
|
|
2
|
+
|
|
3
|
+
export const extensionPoints = defineModuleExtensionPoints({
|
|
4
|
+
moduleId: 'directory',
|
|
5
|
+
hosts: {
|
|
6
|
+
organizationsTable: dataTableExtensionHost({ tableId: 'directory.organizations.list', source: 'backend/directory/organizations/page.tsx' }),
|
|
7
|
+
tenantsTable: dataTableExtensionHost({ tableId: 'directory.tenants.list', source: 'backend/directory/tenants/page.tsx' }),
|
|
8
|
+
},
|
|
9
|
+
})
|
|
10
|
+
|
|
11
|
+
export default extensionPoints
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
"use client"
|
|
2
2
|
import * as React from 'react'
|
|
3
|
+
import { resolveExtensionPointPattern } from '@open-mercato/shared/modules/widgets/extension-points'
|
|
4
|
+
import { extensionPoints } from '@open-mercato/core/modules/entities/extension-points'
|
|
3
5
|
import { useSearchParams } from 'next/navigation'
|
|
4
6
|
import type { ColumnDef, SortingState } from '@tanstack/react-table'
|
|
5
7
|
import { filterCustomFieldDefs, useCustomFieldDefs } from '@open-mercato/ui/backend/utils/customFieldDefs'
|
|
@@ -383,7 +385,9 @@ export RECORD_ID="<record uuid>"`}</code></pre>
|
|
|
383
385
|
actions={actions}
|
|
384
386
|
columns={columns}
|
|
385
387
|
data={data}
|
|
386
|
-
perspective={{
|
|
388
|
+
perspective={{
|
|
389
|
+
tableId: resolveExtensionPointPattern(extensionPoints.hosts.userRecordsTable.pattern, { entityId }),
|
|
390
|
+
}}
|
|
387
391
|
exporter={exportConfig}
|
|
388
392
|
filters={baseFilters}
|
|
389
393
|
filterValues={filterValues}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"use client"
|
|
2
2
|
import * as React from 'react'
|
|
3
|
+
import { extensionPoints } from '@open-mercato/core/modules/entities/extension-points'
|
|
3
4
|
import { useQuery } from '@tanstack/react-query'
|
|
4
5
|
import type { ColumnDef, SortingState } from '@tanstack/react-table'
|
|
5
6
|
import { DataTable } from '@open-mercato/ui/backend/DataTable'
|
|
@@ -73,7 +74,7 @@ export default function SystemEntitiesTable() {
|
|
|
73
74
|
sortable
|
|
74
75
|
sorting={sorting}
|
|
75
76
|
onSortingChange={setSorting}
|
|
76
|
-
perspective={{ tableId:
|
|
77
|
+
perspective={{ tableId: extensionPoints.hosts.systemEntitiesTable.tableId }}
|
|
77
78
|
rowActions={(row) => (
|
|
78
79
|
<RowActions
|
|
79
80
|
items={[
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
|
|
2
2
|
"use client"
|
|
3
3
|
import * as React from 'react'
|
|
4
|
+
import { extensionPoints } from '@open-mercato/core/modules/entities/extension-points'
|
|
4
5
|
import Link from 'next/link'
|
|
5
6
|
import { useQuery } from '@tanstack/react-query'
|
|
6
7
|
import type { ColumnDef, SortingState } from '@tanstack/react-table'
|
|
@@ -96,7 +97,7 @@ export default function UserEntitiesTable() {
|
|
|
96
97
|
sortable
|
|
97
98
|
sorting={sorting}
|
|
98
99
|
onSortingChange={setSorting}
|
|
99
|
-
perspective={{ tableId:
|
|
100
|
+
perspective={{ tableId: extensionPoints.hosts.userEntitiesTable.tableId }}
|
|
100
101
|
emptyState={(
|
|
101
102
|
<ListEmptyState
|
|
102
103
|
entityName={t('entities.user.table.title', 'User Entities')}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { dataTableExtensionHost, defineModuleExtensionPoints, injectionExtensionHost } from '@open-mercato/shared/modules/widgets/extension-points'
|
|
2
|
+
|
|
3
|
+
export const extensionPoints = defineModuleExtensionPoints({
|
|
4
|
+
moduleId: 'entities',
|
|
5
|
+
hosts: {
|
|
6
|
+
systemEntitiesTable: dataTableExtensionHost({ tableId: 'entities.system.list', source: 'components/SystemEntitiesTable.tsx' }),
|
|
7
|
+
userEntitiesTable: dataTableExtensionHost({ tableId: 'entities.user.list', source: 'components/UserEntitiesTable.tsx' }),
|
|
8
|
+
userRecordsTable: injectionExtensionHost({
|
|
9
|
+
family: 'entity',
|
|
10
|
+
pattern: 'data-table:entities.user.records.{entityId}',
|
|
11
|
+
parameters: { entityId: { source: 'route.params.entityId' } },
|
|
12
|
+
supported: ['render-widget', 'headless-widget', 'column-widget', 'row-action', 'bulk-action', 'filter-widget'],
|
|
13
|
+
source: 'backend/entities/user/[entityId]/records/page.tsx',
|
|
14
|
+
}),
|
|
15
|
+
},
|
|
16
|
+
})
|
|
17
|
+
|
|
18
|
+
export default extensionPoints
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"use client"
|
|
2
2
|
import * as React from 'react'
|
|
3
|
+
import { extensionPoints } from '@open-mercato/core/modules/integrations/extension-points'
|
|
3
4
|
import { usePathname, useRouter, useSearchParams } from 'next/navigation'
|
|
4
5
|
import { z } from 'zod'
|
|
5
6
|
import { Page, PageBody } from '@open-mercato/ui/backend/Page'
|
|
@@ -31,7 +32,6 @@ import { raiseCrudError } from '@open-mercato/ui/backend/utils/serverErrors'
|
|
|
31
32
|
import { useT } from '@open-mercato/shared/lib/i18n/context'
|
|
32
33
|
import { cn } from '@open-mercato/shared/lib/utils'
|
|
33
34
|
import {
|
|
34
|
-
LEGACY_INTEGRATION_DETAIL_TABS_SPOT_ID,
|
|
35
35
|
type CredentialFieldType,
|
|
36
36
|
type IntegrationCredentialField,
|
|
37
37
|
type IntegrationDetailBuiltInTab,
|
|
@@ -530,7 +530,7 @@ export default function IntegrationDetailPage({ params }: IntegrationDetailPageP
|
|
|
530
530
|
}, [logLevel, resolveCurrentIntegrationId])
|
|
531
531
|
|
|
532
532
|
const detailWidgetSpotId = React.useMemo(
|
|
533
|
-
() => resolveIntegrationDetailWidgetSpotId(detail?.integration ?? null,
|
|
533
|
+
() => resolveIntegrationDetailWidgetSpotId(detail?.integration ?? null, extensionPoints.hosts.legacyDetailTabs.spotId),
|
|
534
534
|
[detail?.integration],
|
|
535
535
|
)
|
|
536
536
|
const mutationContextId = React.useMemo(
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { defineModuleExtensionPoints, injectionExtensionHost } from '@open-mercato/shared/modules/widgets/extension-points'
|
|
2
|
+
|
|
3
|
+
export const extensionPoints = defineModuleExtensionPoints({
|
|
4
|
+
moduleId: 'integrations',
|
|
5
|
+
hosts: {
|
|
6
|
+
detail: injectionExtensionHost({
|
|
7
|
+
family: 'integration',
|
|
8
|
+
pattern: 'integrations.detail:{integrationId}',
|
|
9
|
+
parameters: {
|
|
10
|
+
integrationId: { source: 'IntegrationDefinition.id', pattern: '^[a-z0-9_]+$' },
|
|
11
|
+
},
|
|
12
|
+
fallbacks: ['integrations.detail:tabs'],
|
|
13
|
+
supported: ['render-widget'],
|
|
14
|
+
contextContract: 'integrations.detail.v1',
|
|
15
|
+
source: 'backend/integrations/[id]/page.tsx',
|
|
16
|
+
}),
|
|
17
|
+
legacyDetailTabs: injectionExtensionHost({
|
|
18
|
+
family: 'integration',
|
|
19
|
+
spotId: 'integrations.detail:tabs',
|
|
20
|
+
supported: ['render-widget'],
|
|
21
|
+
contextContract: 'integrations.detail.v1',
|
|
22
|
+
source: 'backend/integrations/[id]/page.tsx',
|
|
23
|
+
}),
|
|
24
|
+
},
|
|
25
|
+
})
|
|
26
|
+
|
|
27
|
+
export default extensionPoints
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use client"
|
|
2
2
|
|
|
3
3
|
import { useRouter } from 'next/navigation'
|
|
4
|
+
import { extensionPoints } from '@open-mercato/core/modules/messages/extension-points'
|
|
4
5
|
import { MessageComposer } from '@open-mercato/ui/backend/messages'
|
|
5
6
|
// UMES extension surface — compose page injection spot (SPEC-045d §9.3a).
|
|
6
7
|
// Channel provider packages inject "composer capabilities" widgets here
|
|
@@ -21,7 +22,7 @@ export function ComposeMessagePageClient() {
|
|
|
21
22
|
scoping) into this spot purely as additional UI siblings.
|
|
22
23
|
*/}
|
|
23
24
|
<InjectionSpot
|
|
24
|
-
spotId=
|
|
25
|
+
spotId={extensionPoints.hosts.composeFields.spotId}
|
|
25
26
|
context={{ form: 'compose' }}
|
|
26
27
|
data={{}}
|
|
27
28
|
/>
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use client"
|
|
2
2
|
|
|
3
3
|
import * as React from 'react'
|
|
4
|
+
import { extensionPoints } from '@open-mercato/core/modules/messages/extension-points'
|
|
4
5
|
import { MessageComposer } from '@open-mercato/ui/backend/messages'
|
|
5
6
|
import { apiCall } from '@open-mercato/ui/backend/utils/apiCall'
|
|
6
7
|
import { useConfirmDialog } from '@open-mercato/ui/backend/confirm-dialog'
|
|
@@ -94,7 +95,7 @@ function MessageConversationDetailItem({
|
|
|
94
95
|
|
|
95
96
|
{/* UMES — channel payload renderer mounts here (channel-linked emails, Slack blocks, etc.). */}
|
|
96
97
|
<InjectionSpot
|
|
97
|
-
spotId=
|
|
98
|
+
spotId={extensionPoints.hosts.detailBodyAfter.spotId}
|
|
98
99
|
context={{ messageId }}
|
|
99
100
|
data={state.detail}
|
|
100
101
|
/>
|
|
@@ -105,7 +106,7 @@ function MessageConversationDetailItem({
|
|
|
105
106
|
`userFeatures` lets feature-gated widgets (e.g. the channel reassignment editor,
|
|
106
107
|
gated on `communication_channels.assign`) render their controls for permitted users. */}
|
|
107
108
|
<InjectionSpot
|
|
108
|
-
spotId=
|
|
109
|
+
spotId={extensionPoints.hosts.detailSidebar.spotId}
|
|
109
110
|
context={{ messageId, userFeatures }}
|
|
110
111
|
data={state.detail}
|
|
111
112
|
/>
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use client"
|
|
2
2
|
|
|
3
3
|
import * as React from 'react'
|
|
4
|
+
import { extensionPoints } from '@open-mercato/core/modules/messages/extension-points'
|
|
4
5
|
import Link from 'next/link'
|
|
5
6
|
import { useRouter } from 'next/navigation'
|
|
6
7
|
import { useQuery, useQueryClient } from '@tanstack/react-query'
|
|
@@ -369,7 +370,7 @@ export function MessagesInboxPageClient() {
|
|
|
369
370
|
// UMES extension surface — opt into widget injection at:
|
|
370
371
|
// data-table:messages:columns / :row-actions / :bulk-actions / :filters / :toolbar / :search-trailing
|
|
371
372
|
// (SPEC-045d §9.3a — communication_channels hub renders channel badge + delivery status here)
|
|
372
|
-
extensionTableId=
|
|
373
|
+
extensionTableId={extensionPoints.hosts.inboxTable.tableId}
|
|
373
374
|
columns={columns}
|
|
374
375
|
data={rows}
|
|
375
376
|
bulkActions={bulkActions}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { dataTableExtensionHost, defineModuleExtensionPoints, injectionExtensionHost } from '@open-mercato/shared/modules/widgets/extension-points'
|
|
2
|
+
|
|
3
|
+
export const extensionPoints = defineModuleExtensionPoints({
|
|
4
|
+
moduleId: 'messages',
|
|
5
|
+
hosts: {
|
|
6
|
+
inboxTable: dataTableExtensionHost({ tableId: 'messages', source: 'components/MessagesInboxPageClient.tsx' }),
|
|
7
|
+
composeFields: injectionExtensionHost({ family: 'generic', spotId: 'crud-form:messages:message:fields', supported: ['render-widget'], source: 'components/ComposeMessagePageClient.tsx' }),
|
|
8
|
+
detailBodyAfter: injectionExtensionHost({ family: 'detail', spotId: 'detail:messages:message:body:after', supported: ['render-widget'], source: 'components/MessageDetailPageClient.tsx' }),
|
|
9
|
+
detailSidebar: injectionExtensionHost({ family: 'detail', spotId: 'detail:messages:message:sidebar', supported: ['render-widget'], source: 'components/MessageDetailPageClient.tsx' }),
|
|
10
|
+
},
|
|
11
|
+
})
|
|
12
|
+
|
|
13
|
+
export default extensionPoints
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"use client"
|
|
2
2
|
import * as React from 'react'
|
|
3
|
+
import { extensionPoints } from '@open-mercato/core/modules/payment_gateways/extension-points'
|
|
3
4
|
import { useSearchParams } from 'next/navigation'
|
|
4
5
|
import type { ColumnDef } from '@tanstack/react-table'
|
|
5
6
|
import type { FilterDef, FilterValues } from '@open-mercato/ui/backend/FilterBar'
|
|
@@ -472,7 +473,7 @@ export default function PaymentTransactionsPage() {
|
|
|
472
473
|
searchValue={search}
|
|
473
474
|
onSearchChange={(value) => { setSearch(value); setPage(1) }}
|
|
474
475
|
searchPlaceholder={t('payment_gateways.transactions.searchPlaceholder', 'Search by payment, transaction, session, or gateway id')}
|
|
475
|
-
perspective={{ tableId:
|
|
476
|
+
perspective={{ tableId: extensionPoints.hosts.transactionsTable.tableId }}
|
|
476
477
|
pagination={{ page, pageSize: 20, total, totalPages, onPageChange: setPage }}
|
|
477
478
|
isLoading={isLoading}
|
|
478
479
|
onRowClick={(row) => setSelectedId((current) => current === row.id ? null : row.id)}
|
|
@@ -691,7 +692,7 @@ export default function PaymentTransactionsPage() {
|
|
|
691
692
|
className="p-4"
|
|
692
693
|
/>
|
|
693
694
|
<InjectionSpot
|
|
694
|
-
spotId=
|
|
695
|
+
spotId={extensionPoints.hosts.transactionsAfter.spotId}
|
|
695
696
|
context={{ selectedPaymentId: detail.transaction.paymentId }}
|
|
696
697
|
/>
|
|
697
698
|
</div>
|