@open-mercato/core 0.4.6-develop-e321a4e2a1 → 0.4.6-main-24e64eef39
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/AGENTS.md +0 -22
- package/dist/modules/api_docs/frontend/docs/api/page.js +1 -1
- package/dist/modules/api_docs/frontend/docs/api/page.js.map +2 -2
- package/dist/modules/attachments/api/library/[id]/route.js +1 -0
- package/dist/modules/attachments/api/library/[id]/route.js.map +2 -2
- package/dist/modules/attachments/components/AttachmentLibrary.js +1 -1
- package/dist/modules/attachments/components/AttachmentLibrary.js.map +2 -2
- package/dist/modules/attachments/lib/partitionEnv.js +1 -1
- package/dist/modules/attachments/lib/partitionEnv.js.map +2 -2
- package/dist/modules/auth/backend/users/page.js +1 -1
- package/dist/modules/auth/backend/users/page.js.map +2 -2
- package/dist/modules/auth/cli.js +1 -1
- package/dist/modules/auth/cli.js.map +2 -2
- package/dist/modules/auth/commands/users.js +1 -1
- package/dist/modules/auth/commands/users.js.map +2 -2
- package/dist/modules/business_rules/components/utils/formHelpers.js +1 -1
- package/dist/modules/business_rules/components/utils/formHelpers.js.map +2 -2
- package/dist/modules/catalog/backend/catalog/products/create/page.js +1 -1
- package/dist/modules/catalog/backend/catalog/products/create/page.js.map +2 -2
- package/dist/modules/catalog/commands/products.js +1 -1
- package/dist/modules/catalog/commands/products.js.map +2 -2
- package/dist/modules/catalog/commands/shared.js +1 -1
- package/dist/modules/catalog/commands/shared.js.map +2 -2
- package/dist/modules/catalog/components/PriceKindSettings.js +1 -1
- package/dist/modules/catalog/components/PriceKindSettings.js.map +2 -2
- package/dist/modules/catalog/components/products/productForm.js +1 -1
- package/dist/modules/catalog/components/products/productForm.js.map +2 -2
- package/dist/modules/configs/lib/upgrade-actions.js.map +1 -1
- package/dist/modules/currencies/services/providers/raiffeisen.js +1 -1
- package/dist/modules/currencies/services/providers/raiffeisen.js.map +2 -2
- package/dist/modules/customers/backend/customers/companies/page.js +3 -3
- package/dist/modules/customers/backend/customers/companies/page.js.map +2 -2
- package/dist/modules/customers/backend/customers/deals/page.js +3 -3
- package/dist/modules/customers/backend/customers/deals/page.js.map +2 -2
- package/dist/modules/customers/backend/customers/people/page.js +3 -3
- package/dist/modules/customers/backend/customers/people/page.js.map +2 -2
- package/dist/modules/customers/cli.js +2 -2
- package/dist/modules/customers/cli.js.map +2 -2
- package/dist/modules/customers/lib/detailHelpers.js +1 -1
- package/dist/modules/customers/lib/detailHelpers.js.map +2 -2
- package/dist/modules/entities/cli.js +1 -1
- package/dist/modules/entities/cli.js.map +2 -2
- package/dist/modules/entities/lib/field-definitions.js +1 -1
- package/dist/modules/entities/lib/field-definitions.js.map +2 -2
- package/dist/modules/entities/lib/install-from-ce.js +1 -1
- package/dist/modules/entities/lib/install-from-ce.js.map +2 -2
- package/dist/modules/inbox_ops/lib/emailParser.js +1 -1
- package/dist/modules/inbox_ops/lib/emailParser.js.map +2 -2
- package/dist/modules/inbox_ops/widgets/notifications/ProposalCreatedRenderer.js +0 -8
- package/dist/modules/inbox_ops/widgets/notifications/ProposalCreatedRenderer.js.map +2 -2
- package/dist/modules/perspectives/services/perspectiveService.js +1 -1
- package/dist/modules/perspectives/services/perspectiveService.js.map +2 -2
- package/dist/modules/planner/backend/planner/availability-rulesets/page.js +3 -3
- package/dist/modules/planner/backend/planner/availability-rulesets/page.js.map +2 -2
- package/dist/modules/query_index/components/QueryIndexesTable.js +7 -7
- package/dist/modules/query_index/components/QueryIndexesTable.js.map +2 -2
- package/dist/modules/query_index/lib/engine.js +1 -1
- package/dist/modules/query_index/lib/engine.js.map +2 -2
- package/dist/modules/resources/backend/resources/resource-types/page.js +2 -2
- package/dist/modules/resources/backend/resources/resource-types/page.js.map +2 -2
- package/dist/modules/resources/backend/resources/resources/page.js +3 -3
- package/dist/modules/resources/backend/resources/resources/page.js.map +2 -2
- package/dist/modules/resources/commands/resources.js +1 -1
- package/dist/modules/resources/commands/resources.js.map +2 -2
- package/dist/modules/resources/lib/seeds.js +1 -1
- package/dist/modules/resources/lib/seeds.js.map +2 -2
- package/dist/modules/sales/api/dashboard/widgets/new-orders/route.js +1 -1
- package/dist/modules/sales/api/dashboard/widgets/new-orders/route.js.map +2 -2
- package/dist/modules/sales/api/dashboard/widgets/new-quotes/route.js +1 -1
- package/dist/modules/sales/api/dashboard/widgets/new-quotes/route.js.map +2 -2
- package/dist/modules/sales/backend/sales/channels/page.js +3 -3
- package/dist/modules/sales/backend/sales/channels/page.js.map +2 -2
- package/dist/modules/sales/commands/documents.js +2 -2
- package/dist/modules/sales/commands/documents.js.map +2 -2
- package/dist/modules/sales/components/channels/offerTableUtils.js +2 -3
- package/dist/modules/sales/components/channels/offerTableUtils.js.map +2 -2
- package/dist/modules/sales/components/documents/SalesDocumentsTable.js +4 -4
- package/dist/modules/sales/components/documents/SalesDocumentsTable.js.map +2 -2
- package/dist/modules/sales/components/documents/ShipmentDialog.js +1 -1
- package/dist/modules/sales/components/documents/ShipmentDialog.js.map +2 -2
- package/dist/modules/sales/lib/shipments/snapshots.js.map +1 -1
- package/dist/modules/sales/widgets/notifications/SalesOrderCreatedRenderer.js +0 -8
- package/dist/modules/sales/widgets/notifications/SalesOrderCreatedRenderer.js.map +2 -2
- package/dist/modules/sales/widgets/notifications/SalesQuoteCreatedRenderer.js +0 -8
- package/dist/modules/sales/widgets/notifications/SalesQuoteCreatedRenderer.js.map +2 -2
- package/dist/modules/staff/backend/staff/leave-requests/page.js +3 -3
- package/dist/modules/staff/backend/staff/leave-requests/page.js.map +2 -2
- package/dist/modules/staff/backend/staff/my-leave-requests/page.js +3 -3
- package/dist/modules/staff/backend/staff/my-leave-requests/page.js.map +2 -2
- package/dist/modules/staff/backend/staff/team-members/page.js +3 -3
- package/dist/modules/staff/backend/staff/team-members/page.js.map +2 -2
- package/dist/modules/staff/backend/staff/team-roles/page.js +2 -2
- package/dist/modules/staff/backend/staff/team-roles/page.js.map +2 -2
- package/dist/modules/staff/backend/staff/teams/[id]/edit/page.js +3 -3
- package/dist/modules/staff/backend/staff/teams/[id]/edit/page.js.map +2 -2
- package/dist/modules/staff/backend/staff/teams/page.js +2 -2
- package/dist/modules/staff/backend/staff/teams/page.js.map +2 -2
- package/dist/modules/workflows/backend/instances/page.js +2 -2
- package/dist/modules/workflows/backend/instances/page.js.map +2 -2
- package/dist/modules/workflows/backend/tasks/page.js +1 -1
- package/dist/modules/workflows/backend/tasks/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/lib/graph-utils.js +1 -1
- package/dist/modules/workflows/lib/graph-utils.js.map +2 -2
- package/package.json +2 -2
- package/src/modules/api_docs/frontend/docs/api/page.tsx +1 -1
- package/src/modules/attachments/api/library/[id]/route.ts +1 -0
- package/src/modules/attachments/components/AttachmentLibrary.tsx +1 -1
- package/src/modules/attachments/lib/partitionEnv.ts +1 -1
- package/src/modules/auth/backend/users/page.tsx +1 -1
- package/src/modules/auth/cli.ts +1 -1
- package/src/modules/auth/commands/users.ts +1 -1
- package/src/modules/business_rules/components/utils/formHelpers.ts +1 -1
- package/src/modules/catalog/backend/catalog/products/create/page.tsx +1 -1
- package/src/modules/catalog/commands/products.ts +1 -1
- package/src/modules/catalog/commands/shared.ts +1 -1
- package/src/modules/catalog/components/PriceKindSettings.tsx +1 -1
- package/src/modules/catalog/components/products/productForm.ts +1 -1
- package/src/modules/configs/lib/upgrade-actions.ts +1 -1
- package/src/modules/currencies/services/providers/raiffeisen.ts +1 -1
- package/src/modules/customers/backend/customers/companies/page.tsx +3 -3
- package/src/modules/customers/backend/customers/deals/page.tsx +3 -3
- package/src/modules/customers/backend/customers/people/page.tsx +3 -3
- package/src/modules/customers/cli.ts +2 -2
- package/src/modules/customers/lib/detailHelpers.ts +1 -1
- package/src/modules/entities/cli.ts +1 -1
- package/src/modules/entities/lib/field-definitions.ts +1 -1
- package/src/modules/entities/lib/install-from-ce.ts +1 -1
- package/src/modules/inbox_ops/lib/emailParser.ts +1 -1
- package/src/modules/inbox_ops/widgets/notifications/ProposalCreatedRenderer.tsx +0 -8
- package/src/modules/perspectives/services/perspectiveService.ts +1 -1
- package/src/modules/planner/backend/planner/availability-rulesets/page.tsx +4 -3
- package/src/modules/query_index/components/QueryIndexesTable.tsx +7 -7
- package/src/modules/query_index/lib/engine.ts +1 -1
- package/src/modules/resources/backend/resources/resource-types/page.tsx +3 -2
- package/src/modules/resources/backend/resources/resources/page.tsx +3 -3
- package/src/modules/resources/commands/resources.ts +1 -1
- package/src/modules/resources/lib/seeds.ts +1 -1
- package/src/modules/sales/api/dashboard/widgets/new-orders/route.ts +1 -1
- package/src/modules/sales/api/dashboard/widgets/new-quotes/route.ts +1 -1
- package/src/modules/sales/backend/sales/channels/page.tsx +3 -3
- package/src/modules/sales/commands/documents.ts +2 -2
- package/src/modules/sales/components/channels/offerTableUtils.tsx +2 -3
- package/src/modules/sales/components/documents/SalesDocumentsTable.tsx +4 -4
- package/src/modules/sales/components/documents/ShipmentDialog.tsx +1 -1
- package/src/modules/sales/lib/shipments/snapshots.ts +1 -1
- package/src/modules/sales/widgets/notifications/SalesOrderCreatedRenderer.tsx +0 -8
- package/src/modules/sales/widgets/notifications/SalesQuoteCreatedRenderer.tsx +0 -8
- package/src/modules/staff/backend/staff/leave-requests/page.tsx +3 -3
- package/src/modules/staff/backend/staff/my-leave-requests/page.tsx +3 -3
- package/src/modules/staff/backend/staff/team-members/page.tsx +3 -3
- package/src/modules/staff/backend/staff/team-roles/page.tsx +2 -2
- package/src/modules/staff/backend/staff/teams/[id]/edit/page.tsx +4 -3
- package/src/modules/staff/backend/staff/teams/page.tsx +3 -2
- package/src/modules/workflows/backend/instances/page.tsx +2 -2
- package/src/modules/workflows/backend/tasks/page.tsx +1 -1
- package/src/modules/workflows/components/DefinitionTriggersEditor.tsx +1 -1
- package/src/modules/workflows/lib/graph-utils.ts +1 -1
- package/dist/modules/integrations/acl.js +0 -8
- package/dist/modules/integrations/acl.js.map +0 -7
- package/dist/modules/integrations/data/enrichers.js +0 -72
- package/dist/modules/integrations/data/enrichers.js.map +0 -7
- package/dist/modules/integrations/data/entities.js +0 -63
- package/dist/modules/integrations/data/entities.js.map +0 -7
- package/dist/modules/integrations/index.js +0 -9
- package/dist/modules/integrations/index.js.map +0 -7
- package/dist/modules/integrations/setup.js +0 -13
- package/dist/modules/integrations/setup.js.map +0 -7
- package/dist/modules/integrations/widgets/injection/external-ids/widget.client.js +0 -69
- package/dist/modules/integrations/widgets/injection/external-ids/widget.client.js.map +0 -7
- package/dist/modules/integrations/widgets/injection-table.js +0 -13
- package/dist/modules/integrations/widgets/injection-table.js.map +0 -7
- package/src/modules/integrations/acl.ts +0 -4
- package/src/modules/integrations/data/enrichers.ts +0 -98
- package/src/modules/integrations/data/entities.ts +0 -46
- package/src/modules/integrations/index.ts +0 -5
- package/src/modules/integrations/setup.ts +0 -11
- package/src/modules/integrations/widgets/injection/external-ids/widget.client.tsx +0 -94
- package/src/modules/integrations/widgets/injection-table.ts +0 -17
|
@@ -7,7 +7,7 @@ import type { PluggableList } from 'unified'
|
|
|
7
7
|
import { useRouter } from 'next/navigation'
|
|
8
8
|
import type { ColumnDef } from '@tanstack/react-table'
|
|
9
9
|
import { Page, PageBody } from '@open-mercato/ui/backend/Page'
|
|
10
|
-
import { DataTable
|
|
10
|
+
import { DataTable } from '@open-mercato/ui/backend/DataTable'
|
|
11
11
|
import { RowActions } from '@open-mercato/ui/backend/RowActions'
|
|
12
12
|
import { Button } from '@open-mercato/ui/primitives/button'
|
|
13
13
|
import { readApiResultOrThrow, apiCall } from '@open-mercato/ui/backend/utils/apiCall'
|
|
@@ -394,7 +394,7 @@ function mapApiTeamRole(item: Record<string, unknown>): TeamRoleApiRow {
|
|
|
394
394
|
: null
|
|
395
395
|
const teamName = typeof team?.name === 'string' ? team.name : null
|
|
396
396
|
const memberCount = typeof item.memberCount === 'number' ? item.memberCount : 0
|
|
397
|
-
return
|
|
397
|
+
return { id, name, description, updatedAt, teamId, teamName, memberCount }
|
|
398
398
|
}
|
|
399
399
|
|
|
400
400
|
function buildTeamRoleRows(items: TeamRoleApiRow[], unassignedLabel: string): TeamRoleRow[] {
|
|
@@ -7,7 +7,7 @@ import type { ColumnDef, SortingState } from '@tanstack/react-table'
|
|
|
7
7
|
import { Page, PageBody } from '@open-mercato/ui/backend/Page'
|
|
8
8
|
import { readApiResultOrThrow } from '@open-mercato/ui/backend/utils/apiCall'
|
|
9
9
|
import { updateCrud, deleteCrud } from '@open-mercato/ui/backend/utils/crud'
|
|
10
|
-
import { DataTable
|
|
10
|
+
import { DataTable } from '@open-mercato/ui/backend/DataTable'
|
|
11
11
|
import { RowActions } from '@open-mercato/ui/backend/RowActions'
|
|
12
12
|
import { Button } from '@open-mercato/ui/primitives/button'
|
|
13
13
|
import { BooleanIcon } from '@open-mercato/ui/backend/ValueIcons'
|
|
@@ -424,7 +424,7 @@ function mapApiTeamMember(item: Record<string, unknown>): TeamMemberRow {
|
|
|
424
424
|
: typeof item.team_id === 'string'
|
|
425
425
|
? item.team_id
|
|
426
426
|
: null
|
|
427
|
-
return
|
|
427
|
+
return {
|
|
428
428
|
id,
|
|
429
429
|
displayName,
|
|
430
430
|
description,
|
|
@@ -434,6 +434,7 @@ function mapApiTeamMember(item: Record<string, unknown>): TeamMemberRow {
|
|
|
434
434
|
isActive,
|
|
435
435
|
updatedAt,
|
|
436
436
|
teamId,
|
|
437
|
-
}
|
|
437
|
+
}
|
|
438
438
|
}
|
|
439
439
|
|
|
440
|
+
|
|
@@ -7,7 +7,7 @@ import type { PluggableList } from 'unified'
|
|
|
7
7
|
import { useRouter } from 'next/navigation'
|
|
8
8
|
import type { ColumnDef, SortingState } from '@tanstack/react-table'
|
|
9
9
|
import { Page, PageBody } from '@open-mercato/ui/backend/Page'
|
|
10
|
-
import { DataTable
|
|
10
|
+
import { DataTable } from '@open-mercato/ui/backend/DataTable'
|
|
11
11
|
import { RowActions } from '@open-mercato/ui/backend/RowActions'
|
|
12
12
|
import { Button } from '@open-mercato/ui/primitives/button'
|
|
13
13
|
import { BooleanIcon } from '@open-mercato/ui/backend/ValueIcons'
|
|
@@ -317,6 +317,7 @@ function mapApiTeam(item: Record<string, unknown>): TeamRow {
|
|
|
317
317
|
: typeof item.member_count === 'number'
|
|
318
318
|
? item.member_count
|
|
319
319
|
: 0
|
|
320
|
-
return
|
|
320
|
+
return { id, name, description, isActive, updatedAt, memberCount }
|
|
321
321
|
}
|
|
322
322
|
|
|
323
|
+
|
|
@@ -288,7 +288,7 @@ export default function WorkflowInstancesListPage() {
|
|
|
288
288
|
items.push({
|
|
289
289
|
id: 'cancel',
|
|
290
290
|
label: t('workflows.instances.actions.cancel'),
|
|
291
|
-
onSelect: () =>
|
|
291
|
+
onSelect: () => handleCancel(row.original.id, row.original.workflowId),
|
|
292
292
|
})
|
|
293
293
|
}
|
|
294
294
|
|
|
@@ -296,7 +296,7 @@ export default function WorkflowInstancesListPage() {
|
|
|
296
296
|
items.push({
|
|
297
297
|
id: 'retry',
|
|
298
298
|
label: t('workflows.instances.actions.retry'),
|
|
299
|
-
onSelect: () =>
|
|
299
|
+
onSelect: () => handleRetry(row.original.id, row.original.workflowId),
|
|
300
300
|
})
|
|
301
301
|
}
|
|
302
302
|
|
|
@@ -296,7 +296,7 @@ export default function UserTasksListPage() {
|
|
|
296
296
|
items.push({
|
|
297
297
|
id: 'claim',
|
|
298
298
|
label: t('workflows.tasks.actions.claim'),
|
|
299
|
-
onSelect: () =>
|
|
299
|
+
onSelect: () => handleClaim(row.original.id, row.original.taskName),
|
|
300
300
|
})
|
|
301
301
|
}
|
|
302
302
|
|
|
@@ -631,7 +631,7 @@ export function sanitizeId(input: string): string {
|
|
|
631
631
|
.toLowerCase()
|
|
632
632
|
.replace(/[^a-z0-9_-]/g, '_')
|
|
633
633
|
.replace(/_{2,}/g, '_') // Replace multiple underscores with single
|
|
634
|
-
.replace(
|
|
634
|
+
.replace(/^_|_$/g, '') // Remove leading/trailing underscores
|
|
635
635
|
}
|
|
636
636
|
|
|
637
637
|
/**
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
const features = [
|
|
2
|
-
{ id: "integrations.view", title: "View integrations and external ID mappings", module: "integrations" },
|
|
3
|
-
{ id: "integrations.manage", title: "Manage integration configurations", module: "integrations" }
|
|
4
|
-
];
|
|
5
|
-
export {
|
|
6
|
-
features
|
|
7
|
-
};
|
|
8
|
-
//# sourceMappingURL=acl.js.map
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../../../src/modules/integrations/acl.ts"],
|
|
4
|
-
"sourcesContent": ["export const features = [\n { id: 'integrations.view', title: 'View integrations and external ID mappings', module: 'integrations' },\n { id: 'integrations.manage', title: 'Manage integration configurations', module: 'integrations' },\n]\n"],
|
|
5
|
-
"mappings": "AAAO,MAAM,WAAW;AAAA,EACtB,EAAE,IAAI,qBAAqB,OAAO,8CAA8C,QAAQ,eAAe;AAAA,EACvG,EAAE,IAAI,uBAAuB,OAAO,qCAAqC,QAAQ,eAAe;AAClG;",
|
|
6
|
-
"names": []
|
|
7
|
-
}
|
|
@@ -1,72 +0,0 @@
|
|
|
1
|
-
import { getIntegration } from "@open-mercato/shared/modules/integrations/types";
|
|
2
|
-
import { SyncExternalIdMapping } from "./entities.js";
|
|
3
|
-
function buildIntegrationData(mappings) {
|
|
4
|
-
const data = {};
|
|
5
|
-
for (const mapping of mappings) {
|
|
6
|
-
const definition = getIntegration(mapping.integrationId);
|
|
7
|
-
data[mapping.integrationId] = {
|
|
8
|
-
externalId: mapping.externalId,
|
|
9
|
-
externalUrl: definition?.buildExternalUrl?.(mapping.externalId),
|
|
10
|
-
lastSyncedAt: mapping.lastSyncedAt?.toISOString(),
|
|
11
|
-
syncStatus: mapping.syncStatus
|
|
12
|
-
};
|
|
13
|
-
}
|
|
14
|
-
return data;
|
|
15
|
-
}
|
|
16
|
-
const externalIdMappingEnricher = {
|
|
17
|
-
id: "integrations.external-id-mapping",
|
|
18
|
-
targetEntity: "*",
|
|
19
|
-
features: ["integrations.view"],
|
|
20
|
-
priority: 10,
|
|
21
|
-
timeout: 500,
|
|
22
|
-
critical: false,
|
|
23
|
-
fallback: {},
|
|
24
|
-
async enrichOne(record, context) {
|
|
25
|
-
const em = context.em.fork();
|
|
26
|
-
const targetEntity = context.targetEntity;
|
|
27
|
-
if (!targetEntity) return { ...record, _integrations: {} };
|
|
28
|
-
const mappings = await em.find(SyncExternalIdMapping, {
|
|
29
|
-
internalEntityType: targetEntity,
|
|
30
|
-
internalEntityId: record.id,
|
|
31
|
-
organizationId: context.organizationId,
|
|
32
|
-
deletedAt: null
|
|
33
|
-
});
|
|
34
|
-
if (mappings.length === 0) return { ...record, _integrations: {} };
|
|
35
|
-
return {
|
|
36
|
-
...record,
|
|
37
|
-
_integrations: buildIntegrationData(mappings)
|
|
38
|
-
};
|
|
39
|
-
},
|
|
40
|
-
async enrichMany(records, context) {
|
|
41
|
-
const em = context.em.fork();
|
|
42
|
-
const targetEntity = context.targetEntity;
|
|
43
|
-
if (!targetEntity || records.length === 0) return records.map((r) => ({ ...r, _integrations: {} }));
|
|
44
|
-
const recordIds = records.map((r) => r.id);
|
|
45
|
-
const allMappings = await em.find(SyncExternalIdMapping, {
|
|
46
|
-
internalEntityType: targetEntity,
|
|
47
|
-
internalEntityId: { $in: recordIds },
|
|
48
|
-
organizationId: context.organizationId,
|
|
49
|
-
deletedAt: null
|
|
50
|
-
});
|
|
51
|
-
if (allMappings.length === 0) return records.map((r) => ({ ...r, _integrations: {} }));
|
|
52
|
-
const mappingsByRecord = /* @__PURE__ */ new Map();
|
|
53
|
-
for (const mapping of allMappings) {
|
|
54
|
-
const list = mappingsByRecord.get(mapping.internalEntityId) ?? [];
|
|
55
|
-
list.push(mapping);
|
|
56
|
-
mappingsByRecord.set(mapping.internalEntityId, list);
|
|
57
|
-
}
|
|
58
|
-
return records.map((record) => {
|
|
59
|
-
const mappings = mappingsByRecord.get(record.id);
|
|
60
|
-
if (!mappings || mappings.length === 0) return { ...record, _integrations: {} };
|
|
61
|
-
return {
|
|
62
|
-
...record,
|
|
63
|
-
_integrations: buildIntegrationData(mappings)
|
|
64
|
-
};
|
|
65
|
-
});
|
|
66
|
-
}
|
|
67
|
-
};
|
|
68
|
-
const enrichers = [externalIdMappingEnricher];
|
|
69
|
-
export {
|
|
70
|
-
enrichers
|
|
71
|
-
};
|
|
72
|
-
//# sourceMappingURL=enrichers.js.map
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../../../../src/modules/integrations/data/enrichers.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n * External ID Mapping Enricher\n *\n * Enriches any entity's API response with external integration ID mappings.\n * Adds `_integrations` namespace containing all external IDs for the record.\n *\n * Uses batch queries via `enrichMany` to prevent N+1.\n */\n\nimport type { ResponseEnricher, EnricherContext } from '@open-mercato/shared/lib/crud/response-enricher'\nimport type { ExternalIdEnrichment } from '@open-mercato/shared/modules/integrations/types'\nimport { getIntegration } from '@open-mercato/shared/modules/integrations/types'\nimport { SyncExternalIdMapping } from './entities'\n\ntype EntityRecord = Record<string, unknown> & { id: string }\n\nfunction buildIntegrationData(\n mappings: SyncExternalIdMapping[],\n): ExternalIdEnrichment['_integrations'] {\n const data: ExternalIdEnrichment['_integrations'] = {}\n\n for (const mapping of mappings) {\n const definition = getIntegration(mapping.integrationId)\n data[mapping.integrationId] = {\n externalId: mapping.externalId,\n externalUrl: definition?.buildExternalUrl?.(mapping.externalId),\n lastSyncedAt: mapping.lastSyncedAt?.toISOString(),\n syncStatus: mapping.syncStatus,\n }\n }\n\n return data\n}\n\nconst externalIdMappingEnricher: ResponseEnricher<EntityRecord, ExternalIdEnrichment> = {\n id: 'integrations.external-id-mapping',\n targetEntity: '*',\n features: ['integrations.view'],\n priority: 10,\n timeout: 500,\n critical: false,\n fallback: {},\n\n async enrichOne(record, context: EnricherContext & { targetEntity?: string }) {\n const em = (context.em as any).fork()\n const targetEntity = (context as any).targetEntity as string | undefined\n if (!targetEntity) return { ...record, _integrations: {} }\n\n const mappings: SyncExternalIdMapping[] = await em.find(SyncExternalIdMapping, {\n internalEntityType: targetEntity,\n internalEntityId: record.id,\n organizationId: context.organizationId,\n deletedAt: null,\n })\n\n if (mappings.length === 0) return { ...record, _integrations: {} }\n\n return {\n ...record,\n _integrations: buildIntegrationData(mappings),\n }\n },\n\n async enrichMany(records, context: EnricherContext & { targetEntity?: string }) {\n const em = (context.em as any).fork()\n const targetEntity = (context as any).targetEntity as string | undefined\n if (!targetEntity || records.length === 0) return records.map((r) => ({ ...r, _integrations: {} }))\n\n const recordIds = records.map((r) => r.id)\n const allMappings: SyncExternalIdMapping[] = await em.find(SyncExternalIdMapping, {\n internalEntityType: targetEntity,\n internalEntityId: { $in: recordIds },\n organizationId: context.organizationId,\n deletedAt: null,\n })\n\n if (allMappings.length === 0) return records.map((r) => ({ ...r, _integrations: {} }))\n\n const mappingsByRecord = new Map<string, SyncExternalIdMapping[]>()\n for (const mapping of allMappings) {\n const list = mappingsByRecord.get(mapping.internalEntityId) ?? []\n list.push(mapping)\n mappingsByRecord.set(mapping.internalEntityId, list)\n }\n\n return records.map((record) => {\n const mappings = mappingsByRecord.get(record.id)\n if (!mappings || mappings.length === 0) return { ...record, _integrations: {} }\n\n return {\n ...record,\n _integrations: buildIntegrationData(mappings),\n }\n })\n },\n}\n\nexport const enrichers: ResponseEnricher[] = [externalIdMappingEnricher]\n"],
|
|
5
|
-
"mappings": "AAWA,SAAS,sBAAsB;AAC/B,SAAS,6BAA6B;AAItC,SAAS,qBACP,UACuC;AACvC,QAAM,OAA8C,CAAC;AAErD,aAAW,WAAW,UAAU;AAC9B,UAAM,aAAa,eAAe,QAAQ,aAAa;AACvD,SAAK,QAAQ,aAAa,IAAI;AAAA,MAC5B,YAAY,QAAQ;AAAA,MACpB,aAAa,YAAY,mBAAmB,QAAQ,UAAU;AAAA,MAC9D,cAAc,QAAQ,cAAc,YAAY;AAAA,MAChD,YAAY,QAAQ;AAAA,IACtB;AAAA,EACF;AAEA,SAAO;AACT;AAEA,MAAM,4BAAkF;AAAA,EACtF,IAAI;AAAA,EACJ,cAAc;AAAA,EACd,UAAU,CAAC,mBAAmB;AAAA,EAC9B,UAAU;AAAA,EACV,SAAS;AAAA,EACT,UAAU;AAAA,EACV,UAAU,CAAC;AAAA,EAEX,MAAM,UAAU,QAAQ,SAAsD;AAC5E,UAAM,KAAM,QAAQ,GAAW,KAAK;AACpC,UAAM,eAAgB,QAAgB;AACtC,QAAI,CAAC,aAAc,QAAO,EAAE,GAAG,QAAQ,eAAe,CAAC,EAAE;AAEzD,UAAM,WAAoC,MAAM,GAAG,KAAK,uBAAuB;AAAA,MAC7E,oBAAoB;AAAA,MACpB,kBAAkB,OAAO;AAAA,MACzB,gBAAgB,QAAQ;AAAA,MACxB,WAAW;AAAA,IACb,CAAC;AAED,QAAI,SAAS,WAAW,EAAG,QAAO,EAAE,GAAG,QAAQ,eAAe,CAAC,EAAE;AAEjE,WAAO;AAAA,MACL,GAAG;AAAA,MACH,eAAe,qBAAqB,QAAQ;AAAA,IAC9C;AAAA,EACF;AAAA,EAEA,MAAM,WAAW,SAAS,SAAsD;AAC9E,UAAM,KAAM,QAAQ,GAAW,KAAK;AACpC,UAAM,eAAgB,QAAgB;AACtC,QAAI,CAAC,gBAAgB,QAAQ,WAAW,EAAG,QAAO,QAAQ,IAAI,CAAC,OAAO,EAAE,GAAG,GAAG,eAAe,CAAC,EAAE,EAAE;AAElG,UAAM,YAAY,QAAQ,IAAI,CAAC,MAAM,EAAE,EAAE;AACzC,UAAM,cAAuC,MAAM,GAAG,KAAK,uBAAuB;AAAA,MAChF,oBAAoB;AAAA,MACpB,kBAAkB,EAAE,KAAK,UAAU;AAAA,MACnC,gBAAgB,QAAQ;AAAA,MACxB,WAAW;AAAA,IACb,CAAC;AAED,QAAI,YAAY,WAAW,EAAG,QAAO,QAAQ,IAAI,CAAC,OAAO,EAAE,GAAG,GAAG,eAAe,CAAC,EAAE,EAAE;AAErF,UAAM,mBAAmB,oBAAI,IAAqC;AAClE,eAAW,WAAW,aAAa;AACjC,YAAM,OAAO,iBAAiB,IAAI,QAAQ,gBAAgB,KAAK,CAAC;AAChE,WAAK,KAAK,OAAO;AACjB,uBAAiB,IAAI,QAAQ,kBAAkB,IAAI;AAAA,IACrD;AAEA,WAAO,QAAQ,IAAI,CAAC,WAAW;AAC7B,YAAM,WAAW,iBAAiB,IAAI,OAAO,EAAE;AAC/C,UAAI,CAAC,YAAY,SAAS,WAAW,EAAG,QAAO,EAAE,GAAG,QAAQ,eAAe,CAAC,EAAE;AAE9E,aAAO;AAAA,QACL,GAAG;AAAA,QACH,eAAe,qBAAqB,QAAQ;AAAA,MAC9C;AAAA,IACF,CAAC;AAAA,EACH;AACF;AAEO,MAAM,YAAgC,CAAC,yBAAyB;",
|
|
6
|
-
"names": []
|
|
7
|
-
}
|
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
var __defProp = Object.defineProperty;
|
|
2
|
-
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
3
|
-
var __decorateClass = (decorators, target, key, kind) => {
|
|
4
|
-
var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target;
|
|
5
|
-
for (var i = decorators.length - 1, decorator; i >= 0; i--)
|
|
6
|
-
if (decorator = decorators[i])
|
|
7
|
-
result = (kind ? decorator(target, key, result) : decorator(result)) || result;
|
|
8
|
-
if (kind && result) __defProp(target, key, result);
|
|
9
|
-
return result;
|
|
10
|
-
};
|
|
11
|
-
import { Entity, PrimaryKey, Property, Index } from "@mikro-orm/core";
|
|
12
|
-
let SyncExternalIdMapping = class {
|
|
13
|
-
constructor() {
|
|
14
|
-
this.syncStatus = "not_synced";
|
|
15
|
-
this.createdAt = /* @__PURE__ */ new Date();
|
|
16
|
-
this.updatedAt = /* @__PURE__ */ new Date();
|
|
17
|
-
}
|
|
18
|
-
};
|
|
19
|
-
__decorateClass([
|
|
20
|
-
PrimaryKey({ type: "uuid", defaultRaw: "gen_random_uuid()" })
|
|
21
|
-
], SyncExternalIdMapping.prototype, "id", 2);
|
|
22
|
-
__decorateClass([
|
|
23
|
-
Property({ name: "integration_id", type: "text" })
|
|
24
|
-
], SyncExternalIdMapping.prototype, "integrationId", 2);
|
|
25
|
-
__decorateClass([
|
|
26
|
-
Property({ name: "internal_entity_type", type: "text" })
|
|
27
|
-
], SyncExternalIdMapping.prototype, "internalEntityType", 2);
|
|
28
|
-
__decorateClass([
|
|
29
|
-
Property({ name: "internal_entity_id", type: "uuid" })
|
|
30
|
-
], SyncExternalIdMapping.prototype, "internalEntityId", 2);
|
|
31
|
-
__decorateClass([
|
|
32
|
-
Property({ name: "external_id", type: "text" })
|
|
33
|
-
], SyncExternalIdMapping.prototype, "externalId", 2);
|
|
34
|
-
__decorateClass([
|
|
35
|
-
Property({ name: "sync_status", type: "text", default: "not_synced" })
|
|
36
|
-
], SyncExternalIdMapping.prototype, "syncStatus", 2);
|
|
37
|
-
__decorateClass([
|
|
38
|
-
Property({ name: "last_synced_at", type: Date, nullable: true })
|
|
39
|
-
], SyncExternalIdMapping.prototype, "lastSyncedAt", 2);
|
|
40
|
-
__decorateClass([
|
|
41
|
-
Property({ name: "organization_id", type: "uuid" })
|
|
42
|
-
], SyncExternalIdMapping.prototype, "organizationId", 2);
|
|
43
|
-
__decorateClass([
|
|
44
|
-
Property({ name: "tenant_id", type: "uuid" })
|
|
45
|
-
], SyncExternalIdMapping.prototype, "tenantId", 2);
|
|
46
|
-
__decorateClass([
|
|
47
|
-
Property({ name: "created_at", type: Date, onCreate: () => /* @__PURE__ */ new Date() })
|
|
48
|
-
], SyncExternalIdMapping.prototype, "createdAt", 2);
|
|
49
|
-
__decorateClass([
|
|
50
|
-
Property({ name: "updated_at", type: Date, onUpdate: () => /* @__PURE__ */ new Date() })
|
|
51
|
-
], SyncExternalIdMapping.prototype, "updatedAt", 2);
|
|
52
|
-
__decorateClass([
|
|
53
|
-
Property({ name: "deleted_at", type: Date, nullable: true })
|
|
54
|
-
], SyncExternalIdMapping.prototype, "deletedAt", 2);
|
|
55
|
-
SyncExternalIdMapping = __decorateClass([
|
|
56
|
-
Entity({ tableName: "sync_external_id_mappings" }),
|
|
57
|
-
Index({ properties: ["internalEntityType", "internalEntityId", "organizationId"] }),
|
|
58
|
-
Index({ properties: ["integrationId", "externalId", "organizationId"] })
|
|
59
|
-
], SyncExternalIdMapping);
|
|
60
|
-
export {
|
|
61
|
-
SyncExternalIdMapping
|
|
62
|
-
};
|
|
63
|
-
//# sourceMappingURL=entities.js.map
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../../../../src/modules/integrations/data/entities.ts"],
|
|
4
|
-
"sourcesContent": ["import { Entity, PrimaryKey, Property, Index } from '@mikro-orm/core'\n\n/**\n * Stores mappings between internal entity IDs and external system IDs.\n * Used by integration modules to track synced records across platforms.\n */\n@Entity({ tableName: 'sync_external_id_mappings' })\n@Index({ properties: ['internalEntityType', 'internalEntityId', 'organizationId'] })\n@Index({ properties: ['integrationId', 'externalId', 'organizationId'] })\nexport class SyncExternalIdMapping {\n @PrimaryKey({ type: 'uuid', defaultRaw: 'gen_random_uuid()' })\n id!: string\n\n @Property({ name: 'integration_id', type: 'text' })\n integrationId!: string\n\n @Property({ name: 'internal_entity_type', type: 'text' })\n internalEntityType!: string\n\n @Property({ name: 'internal_entity_id', type: 'uuid' })\n internalEntityId!: string\n\n @Property({ name: 'external_id', type: 'text' })\n externalId!: string\n\n @Property({ name: 'sync_status', type: 'text', default: 'not_synced' })\n syncStatus: 'synced' | 'pending' | 'error' | 'not_synced' = 'not_synced'\n\n @Property({ name: 'last_synced_at', type: Date, nullable: true })\n lastSyncedAt?: Date | null\n\n @Property({ name: 'organization_id', type: 'uuid' })\n organizationId!: string\n\n @Property({ name: 'tenant_id', type: 'uuid' })\n tenantId!: string\n\n @Property({ name: 'created_at', type: Date, onCreate: () => new Date() })\n createdAt: Date = new Date()\n\n @Property({ name: 'updated_at', type: Date, onUpdate: () => new Date() })\n updatedAt: Date = new Date()\n\n @Property({ name: 'deleted_at', type: Date, nullable: true })\n deletedAt?: Date | null\n}\n"],
|
|
5
|
-
"mappings": ";;;;;;;;;;AAAA,SAAS,QAAQ,YAAY,UAAU,aAAa;AAS7C,IAAM,wBAAN,MAA4B;AAAA,EAA5B;AAiBL,sBAA4D;AAY5D,qBAAkB,oBAAI,KAAK;AAG3B,qBAAkB,oBAAI,KAAK;AAAA;AAI7B;AAlCE;AAAA,EADC,WAAW,EAAE,MAAM,QAAQ,YAAY,oBAAoB,CAAC;AAAA,GADlD,sBAEX;AAGA;AAAA,EADC,SAAS,EAAE,MAAM,kBAAkB,MAAM,OAAO,CAAC;AAAA,GAJvC,sBAKX;AAGA;AAAA,EADC,SAAS,EAAE,MAAM,wBAAwB,MAAM,OAAO,CAAC;AAAA,GAP7C,sBAQX;AAGA;AAAA,EADC,SAAS,EAAE,MAAM,sBAAsB,MAAM,OAAO,CAAC;AAAA,GAV3C,sBAWX;AAGA;AAAA,EADC,SAAS,EAAE,MAAM,eAAe,MAAM,OAAO,CAAC;AAAA,GAbpC,sBAcX;AAGA;AAAA,EADC,SAAS,EAAE,MAAM,eAAe,MAAM,QAAQ,SAAS,aAAa,CAAC;AAAA,GAhB3D,sBAiBX;AAGA;AAAA,EADC,SAAS,EAAE,MAAM,kBAAkB,MAAM,MAAM,UAAU,KAAK,CAAC;AAAA,GAnBrD,sBAoBX;AAGA;AAAA,EADC,SAAS,EAAE,MAAM,mBAAmB,MAAM,OAAO,CAAC;AAAA,GAtBxC,sBAuBX;AAGA;AAAA,EADC,SAAS,EAAE,MAAM,aAAa,MAAM,OAAO,CAAC;AAAA,GAzBlC,sBA0BX;AAGA;AAAA,EADC,SAAS,EAAE,MAAM,cAAc,MAAM,MAAM,UAAU,MAAM,oBAAI,KAAK,EAAE,CAAC;AAAA,GA5B7D,sBA6BX;AAGA;AAAA,EADC,SAAS,EAAE,MAAM,cAAc,MAAM,MAAM,UAAU,MAAM,oBAAI,KAAK,EAAE,CAAC;AAAA,GA/B7D,sBAgCX;AAGA;AAAA,EADC,SAAS,EAAE,MAAM,cAAc,MAAM,MAAM,UAAU,KAAK,CAAC;AAAA,GAlCjD,sBAmCX;AAnCW,wBAAN;AAAA,EAHN,OAAO,EAAE,WAAW,4BAA4B,CAAC;AAAA,EACjD,MAAM,EAAE,YAAY,CAAC,sBAAsB,oBAAoB,gBAAgB,EAAE,CAAC;AAAA,EAClF,MAAM,EAAE,YAAY,CAAC,iBAAiB,cAAc,gBAAgB,EAAE,CAAC;AAAA,GAC3D;",
|
|
6
|
-
"names": []
|
|
7
|
-
}
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../../../src/modules/integrations/index.ts"],
|
|
4
|
-
"sourcesContent": ["export const metadata = {\n id: 'integrations',\n title: 'Integrations',\n description: 'Core integration framework \u2014 external ID mapping, status badges, and integration registry.',\n}\n"],
|
|
5
|
-
"mappings": "AAAO,MAAM,WAAW;AAAA,EACtB,IAAI;AAAA,EACJ,OAAO;AAAA,EACP,aAAa;AACf;",
|
|
6
|
-
"names": []
|
|
7
|
-
}
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
const setup = {
|
|
2
|
-
defaultRoleFeatures: {
|
|
3
|
-
superadmin: ["integrations.view", "integrations.manage"],
|
|
4
|
-
admin: ["integrations.view", "integrations.manage"],
|
|
5
|
-
employee: ["integrations.view"]
|
|
6
|
-
}
|
|
7
|
-
};
|
|
8
|
-
var setup_default = setup;
|
|
9
|
-
export {
|
|
10
|
-
setup_default as default,
|
|
11
|
-
setup
|
|
12
|
-
};
|
|
13
|
-
//# sourceMappingURL=setup.js.map
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../../../src/modules/integrations/setup.ts"],
|
|
4
|
-
"sourcesContent": ["import type { ModuleSetupConfig } from '@open-mercato/shared/modules/setup'\n\nexport const setup: ModuleSetupConfig = {\n defaultRoleFeatures: {\n superadmin: ['integrations.view', 'integrations.manage'],\n admin: ['integrations.view', 'integrations.manage'],\n employee: ['integrations.view'],\n },\n}\n\nexport default setup\n"],
|
|
5
|
-
"mappings": "AAEO,MAAM,QAA2B;AAAA,EACtC,qBAAqB;AAAA,IACnB,YAAY,CAAC,qBAAqB,qBAAqB;AAAA,IACvD,OAAO,CAAC,qBAAqB,qBAAqB;AAAA,IAClD,UAAU,CAAC,mBAAmB;AAAA,EAChC;AACF;AAEA,IAAO,gBAAQ;",
|
|
6
|
-
"names": []
|
|
7
|
-
}
|
|
@@ -1,69 +0,0 @@
|
|
|
1
|
-
"use client";
|
|
2
|
-
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
-
import { getIntegrationTitle } from "@open-mercato/shared/modules/integrations/types";
|
|
4
|
-
import { useT } from "@open-mercato/shared/lib/i18n/context";
|
|
5
|
-
import { cn } from "@open-mercato/shared/lib/utils";
|
|
6
|
-
const SYNC_STATUS_STYLES = {
|
|
7
|
-
synced: { dot: "bg-green-500", label: "integrations.syncStatus.synced" },
|
|
8
|
-
pending: { dot: "bg-yellow-500", label: "integrations.syncStatus.pending" },
|
|
9
|
-
error: { dot: "bg-red-500", label: "integrations.syncStatus.error" },
|
|
10
|
-
not_synced: { dot: "bg-gray-400", label: "integrations.syncStatus.notSynced" }
|
|
11
|
-
};
|
|
12
|
-
function SyncStatusBadge({ status, lastSynced }) {
|
|
13
|
-
const t = useT();
|
|
14
|
-
const config = SYNC_STATUS_STYLES[status];
|
|
15
|
-
const label = t(config.label, status);
|
|
16
|
-
return /* @__PURE__ */ jsxs("span", { className: "inline-flex items-center gap-1 text-xs text-muted-foreground", children: [
|
|
17
|
-
/* @__PURE__ */ jsx("span", { className: cn("inline-block size-1.5 rounded-full", config.dot), "aria-hidden": "true" }),
|
|
18
|
-
/* @__PURE__ */ jsx("span", { children: label }),
|
|
19
|
-
lastSynced && /* @__PURE__ */ jsx("span", { title: lastSynced, children: new Date(lastSynced).toLocaleDateString() })
|
|
20
|
-
] });
|
|
21
|
-
}
|
|
22
|
-
function ExternalLinkIcon() {
|
|
23
|
-
return /* @__PURE__ */ jsxs("svg", { className: "size-3.5", viewBox: "0 0 16 16", fill: "none", stroke: "currentColor", strokeWidth: "1.5", children: [
|
|
24
|
-
/* @__PURE__ */ jsx("path", { d: "M6.5 3.5H3a1 1 0 0 0-1 1V13a1 1 0 0 0 1 1h8.5a1 1 0 0 0 1-1V9.5" }),
|
|
25
|
-
/* @__PURE__ */ jsx("path", { d: "M9.5 2h4.5v4.5M14 2 7.5 8.5" })
|
|
26
|
-
] });
|
|
27
|
-
}
|
|
28
|
-
function ExternalIdsWidget({ data }) {
|
|
29
|
-
const t = useT();
|
|
30
|
-
const integrations = data?._integrations;
|
|
31
|
-
if (!integrations || Object.keys(integrations).length === 0) return null;
|
|
32
|
-
return /* @__PURE__ */ jsxs("div", { className: "rounded-lg border bg-card p-4", children: [
|
|
33
|
-
/* @__PURE__ */ jsx("h3", { className: "mb-3 text-sm font-medium", children: t("integrations.externalIds.title", "External IDs") }),
|
|
34
|
-
/* @__PURE__ */ jsx("div", { className: "space-y-2", children: Object.entries(integrations).map(([integrationId, mapping]) => /* @__PURE__ */ jsxs(
|
|
35
|
-
"div",
|
|
36
|
-
{
|
|
37
|
-
className: "flex items-center justify-between gap-2 rounded-md bg-muted/50 px-3 py-2",
|
|
38
|
-
children: [
|
|
39
|
-
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 min-w-0", children: [
|
|
40
|
-
/* @__PURE__ */ jsx("span", { className: "text-sm font-medium truncate", children: getIntegrationTitle(integrationId) }),
|
|
41
|
-
/* @__PURE__ */ jsx("code", { className: "rounded bg-muted px-1.5 py-0.5 text-xs font-mono text-muted-foreground", children: mapping.externalId }),
|
|
42
|
-
mapping.externalUrl && /* @__PURE__ */ jsx(
|
|
43
|
-
"a",
|
|
44
|
-
{
|
|
45
|
-
href: mapping.externalUrl,
|
|
46
|
-
target: "_blank",
|
|
47
|
-
rel: "noopener noreferrer",
|
|
48
|
-
className: "text-muted-foreground hover:text-foreground transition-colors",
|
|
49
|
-
"aria-label": t("integrations.externalIds.openExternal", "Open in external system"),
|
|
50
|
-
children: /* @__PURE__ */ jsx(ExternalLinkIcon, {})
|
|
51
|
-
}
|
|
52
|
-
)
|
|
53
|
-
] }),
|
|
54
|
-
/* @__PURE__ */ jsx(SyncStatusBadge, { status: mapping.syncStatus, lastSynced: mapping.lastSyncedAt })
|
|
55
|
-
]
|
|
56
|
-
},
|
|
57
|
-
integrationId
|
|
58
|
-
)) })
|
|
59
|
-
] });
|
|
60
|
-
}
|
|
61
|
-
ExternalIdsWidget.metadata = {
|
|
62
|
-
id: "integrations.injection.external-ids",
|
|
63
|
-
title: "External IDs",
|
|
64
|
-
features: ["integrations.view"]
|
|
65
|
-
};
|
|
66
|
-
export {
|
|
67
|
-
ExternalIdsWidget as default
|
|
68
|
-
};
|
|
69
|
-
//# sourceMappingURL=widget.client.js.map
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../../../../../../src/modules/integrations/widgets/injection/external-ids/widget.client.tsx"],
|
|
4
|
-
"sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport type { InjectionWidgetComponentProps } from '@open-mercato/shared/modules/widgets/injection'\nimport type { ExternalIdMapping } from '@open-mercato/shared/modules/integrations/types'\nimport { getIntegrationTitle } from '@open-mercato/shared/modules/integrations/types'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { cn } from '@open-mercato/shared/lib/utils'\n\ntype IntegrationsData = Record<string, ExternalIdMapping>\n\nconst SYNC_STATUS_STYLES: Record<ExternalIdMapping['syncStatus'], { dot: string; label: string }> = {\n synced: { dot: 'bg-green-500', label: 'integrations.syncStatus.synced' },\n pending: { dot: 'bg-yellow-500', label: 'integrations.syncStatus.pending' },\n error: { dot: 'bg-red-500', label: 'integrations.syncStatus.error' },\n not_synced: { dot: 'bg-gray-400', label: 'integrations.syncStatus.notSynced' },\n}\n\nfunction SyncStatusBadge({ status, lastSynced }: { status: ExternalIdMapping['syncStatus']; lastSynced?: string }) {\n const t = useT()\n const config = SYNC_STATUS_STYLES[status]\n const label = t(config.label, status)\n\n return (\n <span className=\"inline-flex items-center gap-1 text-xs text-muted-foreground\">\n <span className={cn('inline-block size-1.5 rounded-full', config.dot)} aria-hidden=\"true\" />\n <span>{label}</span>\n {lastSynced && (\n <span title={lastSynced}>\n {new Date(lastSynced).toLocaleDateString()}\n </span>\n )}\n </span>\n )\n}\n\nfunction ExternalLinkIcon() {\n return (\n <svg className=\"size-3.5\" viewBox=\"0 0 16 16\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.5\">\n <path d=\"M6.5 3.5H3a1 1 0 0 0-1 1V13a1 1 0 0 0 1 1h8.5a1 1 0 0 0 1-1V9.5\" />\n <path d=\"M9.5 2h4.5v4.5M14 2 7.5 8.5\" />\n </svg>\n )\n}\n\nexport default function ExternalIdsWidget({ data }: InjectionWidgetComponentProps) {\n const t = useT()\n const integrations = (data as Record<string, unknown>)?._integrations as IntegrationsData | undefined\n\n if (!integrations || Object.keys(integrations).length === 0) return null\n\n return (\n <div className=\"rounded-lg border bg-card p-4\">\n <h3 className=\"mb-3 text-sm font-medium\">\n {t('integrations.externalIds.title', 'External IDs')}\n </h3>\n <div className=\"space-y-2\">\n {Object.entries(integrations).map(([integrationId, mapping]) => (\n <div\n key={integrationId}\n className=\"flex items-center justify-between gap-2 rounded-md bg-muted/50 px-3 py-2\"\n >\n <div className=\"flex items-center gap-2 min-w-0\">\n <span className=\"text-sm font-medium truncate\">\n {getIntegrationTitle(integrationId)}\n </span>\n <code className=\"rounded bg-muted px-1.5 py-0.5 text-xs font-mono text-muted-foreground\">\n {mapping.externalId}\n </code>\n {mapping.externalUrl && (\n <a\n href={mapping.externalUrl}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"text-muted-foreground hover:text-foreground transition-colors\"\n aria-label={t('integrations.externalIds.openExternal', 'Open in external system')}\n >\n <ExternalLinkIcon />\n </a>\n )}\n </div>\n <SyncStatusBadge status={mapping.syncStatus} lastSynced={mapping.lastSyncedAt} />\n </div>\n ))}\n </div>\n </div>\n )\n}\n\nExternalIdsWidget.metadata = {\n id: 'integrations.injection.external-ids',\n title: 'External IDs',\n features: ['integrations.view'],\n}\n"],
|
|
5
|
-
"mappings": ";AAwBI,SACE,KADF;AAnBJ,SAAS,2BAA2B;AACpC,SAAS,YAAY;AACrB,SAAS,UAAU;AAInB,MAAM,qBAA8F;AAAA,EAClG,QAAQ,EAAE,KAAK,gBAAgB,OAAO,iCAAiC;AAAA,EACvE,SAAS,EAAE,KAAK,iBAAiB,OAAO,kCAAkC;AAAA,EAC1E,OAAO,EAAE,KAAK,cAAc,OAAO,gCAAgC;AAAA,EACnE,YAAY,EAAE,KAAK,eAAe,OAAO,oCAAoC;AAC/E;AAEA,SAAS,gBAAgB,EAAE,QAAQ,WAAW,GAAqE;AACjH,QAAM,IAAI,KAAK;AACf,QAAM,SAAS,mBAAmB,MAAM;AACxC,QAAM,QAAQ,EAAE,OAAO,OAAO,MAAM;AAEpC,SACE,qBAAC,UAAK,WAAU,gEACd;AAAA,wBAAC,UAAK,WAAW,GAAG,sCAAsC,OAAO,GAAG,GAAG,eAAY,QAAO;AAAA,IAC1F,oBAAC,UAAM,iBAAM;AAAA,IACZ,cACC,oBAAC,UAAK,OAAO,YACV,cAAI,KAAK,UAAU,EAAE,mBAAmB,GAC3C;AAAA,KAEJ;AAEJ;AAEA,SAAS,mBAAmB;AAC1B,SACE,qBAAC,SAAI,WAAU,YAAW,SAAQ,aAAY,MAAK,QAAO,QAAO,gBAAe,aAAY,OAC1F;AAAA,wBAAC,UAAK,GAAE,mEAAkE;AAAA,IAC1E,oBAAC,UAAK,GAAE,+BAA8B;AAAA,KACxC;AAEJ;AAEe,SAAR,kBAAmC,EAAE,KAAK,GAAkC;AACjF,QAAM,IAAI,KAAK;AACf,QAAM,eAAgB,MAAkC;AAExD,MAAI,CAAC,gBAAgB,OAAO,KAAK,YAAY,EAAE,WAAW,EAAG,QAAO;AAEpE,SACE,qBAAC,SAAI,WAAU,iCACb;AAAA,wBAAC,QAAG,WAAU,4BACX,YAAE,kCAAkC,cAAc,GACrD;AAAA,IACA,oBAAC,SAAI,WAAU,aACZ,iBAAO,QAAQ,YAAY,EAAE,IAAI,CAAC,CAAC,eAAe,OAAO,MACxD;AAAA,MAAC;AAAA;AAAA,QAEC,WAAU;AAAA,QAEV;AAAA,+BAAC,SAAI,WAAU,mCACb;AAAA,gCAAC,UAAK,WAAU,gCACb,8BAAoB,aAAa,GACpC;AAAA,YACA,oBAAC,UAAK,WAAU,0EACb,kBAAQ,YACX;AAAA,YACC,QAAQ,eACP;AAAA,cAAC;AAAA;AAAA,gBACC,MAAM,QAAQ;AAAA,gBACd,QAAO;AAAA,gBACP,KAAI;AAAA,gBACJ,WAAU;AAAA,gBACV,cAAY,EAAE,yCAAyC,yBAAyB;AAAA,gBAEhF,8BAAC,oBAAiB;AAAA;AAAA,YACpB;AAAA,aAEJ;AAAA,UACA,oBAAC,mBAAgB,QAAQ,QAAQ,YAAY,YAAY,QAAQ,cAAc;AAAA;AAAA;AAAA,MAtB1E;AAAA,IAuBP,CACD,GACH;AAAA,KACF;AAEJ;AAEA,kBAAkB,WAAW;AAAA,EAC3B,IAAI;AAAA,EACJ,OAAO;AAAA,EACP,UAAU,CAAC,mBAAmB;AAChC;",
|
|
6
|
-
"names": []
|
|
7
|
-
}
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
const injectionTable = {
|
|
2
|
-
// External IDs widget appears in detail page sidebars for all entities
|
|
3
|
-
"detail:*:sidebar": {
|
|
4
|
-
widgetId: "integrations.injection.external-ids",
|
|
5
|
-
priority: -10
|
|
6
|
-
}
|
|
7
|
-
};
|
|
8
|
-
var injection_table_default = injectionTable;
|
|
9
|
-
export {
|
|
10
|
-
injection_table_default as default,
|
|
11
|
-
injectionTable
|
|
12
|
-
};
|
|
13
|
-
//# sourceMappingURL=injection-table.js.map
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../../../../src/modules/integrations/widgets/injection-table.ts"],
|
|
4
|
-
"sourcesContent": ["import type { ModuleInjectionTable } from '@open-mercato/shared/modules/widgets/injection'\n\n/**\n * Integrations module injection table.\n *\n * The external-ids widget auto-appears on entity detail pages via wildcard spot matching.\n * Status badge widgets are registered by individual integration modules (e.g. sync_medusa).\n */\nexport const injectionTable: ModuleInjectionTable = {\n // External IDs widget appears in detail page sidebars for all entities\n 'detail:*:sidebar': {\n widgetId: 'integrations.injection.external-ids',\n priority: -10,\n },\n}\n\nexport default injectionTable\n"],
|
|
5
|
-
"mappings": "AAQO,MAAM,iBAAuC;AAAA;AAAA,EAElD,oBAAoB;AAAA,IAClB,UAAU;AAAA,IACV,UAAU;AAAA,EACZ;AACF;AAEA,IAAO,0BAAQ;",
|
|
6
|
-
"names": []
|
|
7
|
-
}
|
|
@@ -1,98 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* External ID Mapping Enricher
|
|
3
|
-
*
|
|
4
|
-
* Enriches any entity's API response with external integration ID mappings.
|
|
5
|
-
* Adds `_integrations` namespace containing all external IDs for the record.
|
|
6
|
-
*
|
|
7
|
-
* Uses batch queries via `enrichMany` to prevent N+1.
|
|
8
|
-
*/
|
|
9
|
-
|
|
10
|
-
import type { ResponseEnricher, EnricherContext } from '@open-mercato/shared/lib/crud/response-enricher'
|
|
11
|
-
import type { ExternalIdEnrichment } from '@open-mercato/shared/modules/integrations/types'
|
|
12
|
-
import { getIntegration } from '@open-mercato/shared/modules/integrations/types'
|
|
13
|
-
import { SyncExternalIdMapping } from './entities'
|
|
14
|
-
|
|
15
|
-
type EntityRecord = Record<string, unknown> & { id: string }
|
|
16
|
-
|
|
17
|
-
function buildIntegrationData(
|
|
18
|
-
mappings: SyncExternalIdMapping[],
|
|
19
|
-
): ExternalIdEnrichment['_integrations'] {
|
|
20
|
-
const data: ExternalIdEnrichment['_integrations'] = {}
|
|
21
|
-
|
|
22
|
-
for (const mapping of mappings) {
|
|
23
|
-
const definition = getIntegration(mapping.integrationId)
|
|
24
|
-
data[mapping.integrationId] = {
|
|
25
|
-
externalId: mapping.externalId,
|
|
26
|
-
externalUrl: definition?.buildExternalUrl?.(mapping.externalId),
|
|
27
|
-
lastSyncedAt: mapping.lastSyncedAt?.toISOString(),
|
|
28
|
-
syncStatus: mapping.syncStatus,
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
return data
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
const externalIdMappingEnricher: ResponseEnricher<EntityRecord, ExternalIdEnrichment> = {
|
|
36
|
-
id: 'integrations.external-id-mapping',
|
|
37
|
-
targetEntity: '*',
|
|
38
|
-
features: ['integrations.view'],
|
|
39
|
-
priority: 10,
|
|
40
|
-
timeout: 500,
|
|
41
|
-
critical: false,
|
|
42
|
-
fallback: {},
|
|
43
|
-
|
|
44
|
-
async enrichOne(record, context: EnricherContext & { targetEntity?: string }) {
|
|
45
|
-
const em = (context.em as any).fork()
|
|
46
|
-
const targetEntity = (context as any).targetEntity as string | undefined
|
|
47
|
-
if (!targetEntity) return { ...record, _integrations: {} }
|
|
48
|
-
|
|
49
|
-
const mappings: SyncExternalIdMapping[] = await em.find(SyncExternalIdMapping, {
|
|
50
|
-
internalEntityType: targetEntity,
|
|
51
|
-
internalEntityId: record.id,
|
|
52
|
-
organizationId: context.organizationId,
|
|
53
|
-
deletedAt: null,
|
|
54
|
-
})
|
|
55
|
-
|
|
56
|
-
if (mappings.length === 0) return { ...record, _integrations: {} }
|
|
57
|
-
|
|
58
|
-
return {
|
|
59
|
-
...record,
|
|
60
|
-
_integrations: buildIntegrationData(mappings),
|
|
61
|
-
}
|
|
62
|
-
},
|
|
63
|
-
|
|
64
|
-
async enrichMany(records, context: EnricherContext & { targetEntity?: string }) {
|
|
65
|
-
const em = (context.em as any).fork()
|
|
66
|
-
const targetEntity = (context as any).targetEntity as string | undefined
|
|
67
|
-
if (!targetEntity || records.length === 0) return records.map((r) => ({ ...r, _integrations: {} }))
|
|
68
|
-
|
|
69
|
-
const recordIds = records.map((r) => r.id)
|
|
70
|
-
const allMappings: SyncExternalIdMapping[] = await em.find(SyncExternalIdMapping, {
|
|
71
|
-
internalEntityType: targetEntity,
|
|
72
|
-
internalEntityId: { $in: recordIds },
|
|
73
|
-
organizationId: context.organizationId,
|
|
74
|
-
deletedAt: null,
|
|
75
|
-
})
|
|
76
|
-
|
|
77
|
-
if (allMappings.length === 0) return records.map((r) => ({ ...r, _integrations: {} }))
|
|
78
|
-
|
|
79
|
-
const mappingsByRecord = new Map<string, SyncExternalIdMapping[]>()
|
|
80
|
-
for (const mapping of allMappings) {
|
|
81
|
-
const list = mappingsByRecord.get(mapping.internalEntityId) ?? []
|
|
82
|
-
list.push(mapping)
|
|
83
|
-
mappingsByRecord.set(mapping.internalEntityId, list)
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
return records.map((record) => {
|
|
87
|
-
const mappings = mappingsByRecord.get(record.id)
|
|
88
|
-
if (!mappings || mappings.length === 0) return { ...record, _integrations: {} }
|
|
89
|
-
|
|
90
|
-
return {
|
|
91
|
-
...record,
|
|
92
|
-
_integrations: buildIntegrationData(mappings),
|
|
93
|
-
}
|
|
94
|
-
})
|
|
95
|
-
},
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
export const enrichers: ResponseEnricher[] = [externalIdMappingEnricher]
|
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
import { Entity, PrimaryKey, Property, Index } from '@mikro-orm/core'
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Stores mappings between internal entity IDs and external system IDs.
|
|
5
|
-
* Used by integration modules to track synced records across platforms.
|
|
6
|
-
*/
|
|
7
|
-
@Entity({ tableName: 'sync_external_id_mappings' })
|
|
8
|
-
@Index({ properties: ['internalEntityType', 'internalEntityId', 'organizationId'] })
|
|
9
|
-
@Index({ properties: ['integrationId', 'externalId', 'organizationId'] })
|
|
10
|
-
export class SyncExternalIdMapping {
|
|
11
|
-
@PrimaryKey({ type: 'uuid', defaultRaw: 'gen_random_uuid()' })
|
|
12
|
-
id!: string
|
|
13
|
-
|
|
14
|
-
@Property({ name: 'integration_id', type: 'text' })
|
|
15
|
-
integrationId!: string
|
|
16
|
-
|
|
17
|
-
@Property({ name: 'internal_entity_type', type: 'text' })
|
|
18
|
-
internalEntityType!: string
|
|
19
|
-
|
|
20
|
-
@Property({ name: 'internal_entity_id', type: 'uuid' })
|
|
21
|
-
internalEntityId!: string
|
|
22
|
-
|
|
23
|
-
@Property({ name: 'external_id', type: 'text' })
|
|
24
|
-
externalId!: string
|
|
25
|
-
|
|
26
|
-
@Property({ name: 'sync_status', type: 'text', default: 'not_synced' })
|
|
27
|
-
syncStatus: 'synced' | 'pending' | 'error' | 'not_synced' = 'not_synced'
|
|
28
|
-
|
|
29
|
-
@Property({ name: 'last_synced_at', type: Date, nullable: true })
|
|
30
|
-
lastSyncedAt?: Date | null
|
|
31
|
-
|
|
32
|
-
@Property({ name: 'organization_id', type: 'uuid' })
|
|
33
|
-
organizationId!: string
|
|
34
|
-
|
|
35
|
-
@Property({ name: 'tenant_id', type: 'uuid' })
|
|
36
|
-
tenantId!: string
|
|
37
|
-
|
|
38
|
-
@Property({ name: 'created_at', type: Date, onCreate: () => new Date() })
|
|
39
|
-
createdAt: Date = new Date()
|
|
40
|
-
|
|
41
|
-
@Property({ name: 'updated_at', type: Date, onUpdate: () => new Date() })
|
|
42
|
-
updatedAt: Date = new Date()
|
|
43
|
-
|
|
44
|
-
@Property({ name: 'deleted_at', type: Date, nullable: true })
|
|
45
|
-
deletedAt?: Date | null
|
|
46
|
-
}
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import type { ModuleSetupConfig } from '@open-mercato/shared/modules/setup'
|
|
2
|
-
|
|
3
|
-
export const setup: ModuleSetupConfig = {
|
|
4
|
-
defaultRoleFeatures: {
|
|
5
|
-
superadmin: ['integrations.view', 'integrations.manage'],
|
|
6
|
-
admin: ['integrations.view', 'integrations.manage'],
|
|
7
|
-
employee: ['integrations.view'],
|
|
8
|
-
},
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
export default setup
|