@open-mercato/core 0.8.1-develop.7274.1.21a0083828 → 0.8.1-develop.7294.1.0ef99fc518
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +1 -1
- package/dist/modules/auth/api/users/acl/route.js.map +2 -2
- package/dist/modules/auth/components/AclEditor.js +21 -3
- package/dist/modules/auth/components/AclEditor.js.map +2 -2
- package/dist/modules/customers/backend/customers/companies/page.js +6 -4
- package/dist/modules/customers/backend/customers/companies/page.js.map +2 -2
- package/dist/modules/customers/backend/customers/deals/map/components/DealsMapView.js +6 -4
- package/dist/modules/customers/backend/customers/deals/map/components/DealsMapView.js.map +2 -2
- package/dist/modules/customers/backend/customers/deals/page.js +6 -4
- package/dist/modules/customers/backend/customers/deals/page.js.map +2 -2
- package/dist/modules/customers/backend/customers/deals/pipeline/components/ChangeOwnerDialog.js +5 -3
- package/dist/modules/customers/backend/customers/deals/pipeline/components/ChangeOwnerDialog.js.map +2 -2
- package/dist/modules/customers/backend/customers/deals/pipeline/page.js +6 -4
- package/dist/modules/customers/backend/customers/deals/pipeline/page.js.map +2 -2
- package/dist/modules/customers/backend/customers/people/page.js +6 -4
- package/dist/modules/customers/backend/customers/people/page.js.map +2 -2
- package/dist/modules/customers/components/calendar/editor/PeopleField.js +9 -2
- package/dist/modules/customers/components/calendar/editor/PeopleField.js.map +2 -2
- package/dist/modules/customers/components/calendar/editor/hooks.js +4 -2
- package/dist/modules/customers/components/calendar/editor/hooks.js.map +2 -2
- package/dist/modules/customers/components/calendar/editor/lookups.js +7 -3
- package/dist/modules/customers/components/calendar/editor/lookups.js.map +2 -2
- package/dist/modules/customers/components/detail/AssignRoleDialog.js +5 -2
- package/dist/modules/customers/components/detail/AssignRoleDialog.js.map +2 -2
- package/dist/modules/customers/components/detail/RoleAssignmentRow.js +4 -2
- package/dist/modules/customers/components/detail/RoleAssignmentRow.js.map +2 -2
- package/dist/modules/customers/components/detail/ScheduleActivityDialog.js +8 -5
- package/dist/modules/customers/components/detail/ScheduleActivityDialog.js.map +2 -2
- package/dist/modules/customers/components/detail/schedule/DateTimeFields.js +10 -7
- package/dist/modules/customers/components/detail/schedule/DateTimeFields.js.map +2 -2
- package/dist/modules/customers/components/detail/schedule/ParticipantsField.js +4 -2
- package/dist/modules/customers/components/detail/schedule/ParticipantsField.js.map +2 -2
- package/dist/modules/customers/components/detail/schedule/fieldConfig.js +9 -0
- package/dist/modules/customers/components/detail/schedule/fieldConfig.js.map +2 -2
- package/dist/modules/customers/components/detail/schedule/index.js +3 -1
- package/dist/modules/customers/components/detail/schedule/index.js.map +2 -2
- package/dist/modules/customers/components/detail/schedule/useScheduleFormState.js +11 -4
- package/dist/modules/customers/components/detail/schedule/useScheduleFormState.js.map +2 -2
- package/dist/modules/customers/components/formConfig.js +17 -9
- package/dist/modules/customers/components/formConfig.js.map +2 -2
- package/dist/modules/customers/data/validators.js +12 -7
- package/dist/modules/customers/data/validators.js.map +2 -2
- package/dist/modules/customers/lib/assignableStaff.js +103 -22
- package/dist/modules/customers/lib/assignableStaff.js.map +2 -2
- package/dist/modules/customers/setup.js +10 -2
- package/dist/modules/customers/setup.js.map +2 -2
- package/dist/modules/data_sync/api/schedules/[id]/route.js +5 -0
- package/dist/modules/data_sync/api/schedules/[id]/route.js.map +2 -2
- package/dist/modules/data_sync/api/schedules/route.js +5 -0
- package/dist/modules/data_sync/api/schedules/route.js.map +2 -2
- package/dist/modules/data_sync/backend/data-sync/page.js +29 -5
- package/dist/modules/data_sync/backend/data-sync/page.js.map +2 -2
- package/dist/modules/data_sync/components/IntegrationScheduleTab.js +48 -11
- package/dist/modules/data_sync/components/IntegrationScheduleTab.js.map +2 -2
- package/dist/modules/data_sync/data/validators.js +13 -2
- package/dist/modules/data_sync/data/validators.js.map +2 -2
- package/dist/modules/data_sync/lib/schedule-value.js +30 -0
- package/dist/modules/data_sync/lib/schedule-value.js.map +7 -0
- package/dist/modules/eudr/data/validators.js.map +2 -2
- package/dist/modules/portal/frontend/[orgSlug]/portal/dashboard/page.js +3 -4
- package/dist/modules/portal/frontend/[orgSlug]/portal/dashboard/page.js.map +2 -2
- package/dist/modules/portal/frontend/[orgSlug]/portal/invite/page.js +3 -1
- package/dist/modules/portal/frontend/[orgSlug]/portal/invite/page.js.map +2 -2
- package/dist/modules/portal/frontend/[orgSlug]/portal/login/page.js +2 -1
- package/dist/modules/portal/frontend/[orgSlug]/portal/login/page.js.map +2 -2
- package/dist/modules/portal/frontend/[orgSlug]/portal/page.js +3 -4
- package/dist/modules/portal/frontend/[orgSlug]/portal/page.js.map +2 -2
- package/dist/modules/portal/frontend/[orgSlug]/portal/profile/page.js +3 -4
- package/dist/modules/portal/frontend/[orgSlug]/portal/profile/page.js.map +2 -2
- package/dist/modules/portal/lib/navigation.js +3 -4
- package/dist/modules/portal/lib/navigation.js.map +2 -2
- package/dist/modules/query_index/lib/engine.js +79 -14
- package/dist/modules/query_index/lib/engine.js.map +2 -2
- package/dist/modules/staff/backend/staff/time-tracking/page.js +122 -86
- package/dist/modules/staff/backend/staff/time-tracking/page.js.map +2 -2
- package/dist/modules/staff/backend/staff/time-tracking/projects/[id]/page.js +38 -17
- package/dist/modules/staff/backend/staff/time-tracking/projects/[id]/page.js.map +2 -2
- package/dist/modules/staff/backend/staff/time-tracking/reports/[id]/page.js +45 -18
- package/dist/modules/staff/backend/staff/time-tracking/reports/[id]/page.js.map +2 -2
- package/dist/modules/staff/extension-points.js +16 -0
- package/dist/modules/staff/extension-points.js.map +2 -2
- package/dist/modules/staff/frontend/[orgSlug]/portal/time-reports/[id]/page.js +3 -4
- package/dist/modules/staff/frontend/[orgSlug]/portal/time-reports/[id]/page.js.map +2 -2
- package/dist/modules/staff/frontend/[orgSlug]/portal/time-reports/page.js +3 -4
- package/dist/modules/staff/frontend/[orgSlug]/portal/time-reports/page.js.map +2 -2
- package/dist/modules/staff/lib/time-tracking-ui/ReportSheet.js +14 -13
- package/dist/modules/staff/lib/time-tracking-ui/ReportSheet.js.map +2 -2
- package/dist/modules/staff/lib/time-tracking-ui/TaskListView.js +60 -41
- package/dist/modules/staff/lib/time-tracking-ui/TaskListView.js.map +2 -2
- package/dist/modules/warranty_claims/api/ai/assess/route.js +2 -2
- package/dist/modules/warranty_claims/api/ai/assess/route.js.map +2 -2
- package/dist/modules/warranty_claims/api/ai/draft-reply/route.js +3 -4
- package/dist/modules/warranty_claims/api/ai/draft-reply/route.js.map +3 -3
- package/dist/modules/warranty_claims/api/ai/suggest/route.js +3 -3
- package/dist/modules/warranty_claims/api/ai/suggest/route.js.map +2 -2
- package/dist/modules/warranty_claims/api/assign/route.js +3 -3
- package/dist/modules/warranty_claims/api/assign/route.js.map +2 -2
- package/dist/modules/warranty_claims/api/credit-memo/route.js +2 -2
- package/dist/modules/warranty_claims/api/credit-memo/route.js.map +2 -2
- package/dist/modules/warranty_claims/api/entitlement/route.js +2 -2
- package/dist/modules/warranty_claims/api/entitlement/route.js.map +2 -2
- package/dist/modules/warranty_claims/api/events/route.js +4 -4
- package/dist/modules/warranty_claims/api/events/route.js.map +2 -2
- package/dist/modules/warranty_claims/api/external/claims/route.js +3 -3
- package/dist/modules/warranty_claims/api/external/claims/route.js.map +2 -2
- package/dist/modules/warranty_claims/api/portal/claims/[id]/submit/route.js +2 -2
- package/dist/modules/warranty_claims/api/portal/claims/[id]/submit/route.js.map +2 -2
- package/dist/modules/warranty_claims/api/portal/claims/[id]/withdraw/route.js +2 -2
- package/dist/modules/warranty_claims/api/portal/claims/[id]/withdraw/route.js.map +2 -2
- package/dist/modules/warranty_claims/api/portal/claims/route.js +2 -2
- package/dist/modules/warranty_claims/api/portal/claims/route.js.map +2 -2
- package/dist/modules/warranty_claims/api/portal/events/route.js +2 -2
- package/dist/modules/warranty_claims/api/portal/events/route.js.map +2 -2
- package/dist/modules/warranty_claims/api/receiving/route.js +2 -2
- package/dist/modules/warranty_claims/api/receiving/route.js.map +2 -2
- package/dist/modules/warranty_claims/api/replacement-order/route.js +2 -2
- package/dist/modules/warranty_claims/api/replacement-order/route.js.map +2 -2
- package/dist/modules/warranty_claims/api/return-label/route.js +2 -2
- package/dist/modules/warranty_claims/api/return-label/route.js.map +2 -2
- package/dist/modules/warranty_claims/api/risk/route.js +2 -2
- package/dist/modules/warranty_claims/api/risk/route.js.map +2 -2
- package/dist/modules/warranty_claims/api/sales-return/route.js +2 -2
- package/dist/modules/warranty_claims/api/sales-return/route.js.map +2 -2
- package/dist/modules/warranty_claims/api/settings-general/route.js +4 -4
- package/dist/modules/warranty_claims/api/settings-general/route.js.map +2 -2
- package/dist/modules/warranty_claims/api/stats/route.js +2 -2
- package/dist/modules/warranty_claims/api/stats/route.js.map +2 -2
- package/dist/modules/warranty_claims/api/submit/route.js +3 -3
- package/dist/modules/warranty_claims/api/submit/route.js.map +2 -2
- package/dist/modules/warranty_claims/api/transition/route.js +3 -3
- package/dist/modules/warranty_claims/api/transition/route.js.map +2 -2
- package/dist/modules/warranty_claims/api/vendor-recovery/route.js +3 -3
- package/dist/modules/warranty_claims/api/vendor-recovery/route.js.map +2 -2
- package/dist/modules/warranty_claims/api/vendor-recovery-suggestions/route.js +2 -2
- package/dist/modules/warranty_claims/api/vendor-recovery-suggestions/route.js.map +2 -2
- package/dist/modules/warranty_claims/backend/page.js +4 -2
- package/dist/modules/warranty_claims/backend/page.js.map +2 -2
- package/dist/modules/warranty_claims/backend/warranty_claims/[id]/page.js +9 -2
- package/dist/modules/warranty_claims/backend/warranty_claims/[id]/page.js.map +2 -2
- package/dist/modules/warranty_claims/backend/warranty_claims/settings/page.js +4 -2
- package/dist/modules/warranty_claims/backend/warranty_claims/settings/page.js.map +2 -2
- package/dist/modules/warranty_claims/frontend/[orgSlug]/portal/claims/[id]/page.js +3 -4
- package/dist/modules/warranty_claims/frontend/[orgSlug]/portal/claims/[id]/page.js.map +2 -2
- package/dist/modules/warranty_claims/frontend/[orgSlug]/portal/claims/new/page.js +3 -2
- package/dist/modules/warranty_claims/frontend/[orgSlug]/portal/claims/new/page.js.map +2 -2
- package/dist/modules/warranty_claims/frontend/[orgSlug]/portal/claims/page.js +3 -2
- package/dist/modules/warranty_claims/frontend/[orgSlug]/portal/claims/page.js.map +2 -2
- package/dist/modules/workflows/components/DefinitionTriggersEditor.js +1 -1
- package/dist/modules/workflows/components/DefinitionTriggersEditor.js.map +2 -2
- package/dist/modules/workflows/frontend/[orgSlug]/portal/tasks/[id]/page.js +2 -2
- package/dist/modules/workflows/frontend/[orgSlug]/portal/tasks/[id]/page.js.map +2 -2
- package/dist/modules/workflows/lib/event-trigger-service.js +56 -1
- package/dist/modules/workflows/lib/event-trigger-service.js.map +2 -2
- package/package.json +7 -7
- package/src/modules/auth/api/users/acl/route.ts +4 -3
- package/src/modules/auth/components/AclEditor.tsx +38 -2
- package/src/modules/auth/i18n/de.json +5 -1
- package/src/modules/auth/i18n/en.json +5 -1
- package/src/modules/auth/i18n/es.json +5 -1
- package/src/modules/auth/i18n/ko.json +5 -1
- package/src/modules/auth/i18n/pl.json +5 -1
- package/src/modules/customers/backend/customers/companies/page.tsx +6 -4
- package/src/modules/customers/backend/customers/deals/map/components/DealsMapView.tsx +6 -4
- package/src/modules/customers/backend/customers/deals/page.tsx +6 -4
- package/src/modules/customers/backend/customers/deals/pipeline/components/ChangeOwnerDialog.tsx +5 -3
- package/src/modules/customers/backend/customers/deals/pipeline/page.tsx +6 -4
- package/src/modules/customers/backend/customers/people/page.tsx +6 -4
- package/src/modules/customers/components/calendar/editor/PeopleField.tsx +9 -2
- package/src/modules/customers/components/calendar/editor/hooks.ts +4 -2
- package/src/modules/customers/components/calendar/editor/lookups.ts +12 -4
- package/src/modules/customers/components/detail/AssignRoleDialog.tsx +4 -1
- package/src/modules/customers/components/detail/RoleAssignmentRow.tsx +4 -2
- package/src/modules/customers/components/detail/ScheduleActivityDialog.tsx +15 -7
- package/src/modules/customers/components/detail/schedule/DateTimeFields.tsx +16 -7
- package/src/modules/customers/components/detail/schedule/ParticipantsField.tsx +4 -2
- package/src/modules/customers/components/detail/schedule/fieldConfig.ts +15 -0
- package/src/modules/customers/components/detail/schedule/index.ts +1 -1
- package/src/modules/customers/components/detail/schedule/useScheduleFormState.ts +16 -9
- package/src/modules/customers/components/formConfig.tsx +35 -12
- package/src/modules/customers/data/validators.ts +14 -8
- package/src/modules/customers/i18n/de.json +1 -0
- package/src/modules/customers/i18n/en.json +1 -0
- package/src/modules/customers/i18n/es.json +1 -0
- package/src/modules/customers/i18n/ko.json +1 -0
- package/src/modules/customers/i18n/pl.json +1 -0
- package/src/modules/customers/lib/assignableStaff.ts +172 -34
- package/src/modules/customers/setup.ts +8 -0
- package/src/modules/data_sync/api/schedules/[id]/route.ts +5 -0
- package/src/modules/data_sync/api/schedules/route.ts +5 -0
- package/src/modules/data_sync/backend/data-sync/page.tsx +48 -4
- package/src/modules/data_sync/components/IntegrationScheduleTab.tsx +61 -2
- package/src/modules/data_sync/data/validators.ts +26 -2
- package/src/modules/data_sync/i18n/de.json +2 -0
- package/src/modules/data_sync/i18n/en.json +2 -0
- package/src/modules/data_sync/i18n/es.json +2 -0
- package/src/modules/data_sync/i18n/ko.json +2 -0
- package/src/modules/data_sync/i18n/pl.json +2 -0
- package/src/modules/data_sync/lib/schedule-value.ts +45 -0
- package/src/modules/eudr/data/validators.ts +3 -4
- package/src/modules/portal/frontend/[orgSlug]/portal/dashboard/page.tsx +5 -4
- package/src/modules/portal/frontend/[orgSlug]/portal/invite/page.tsx +3 -1
- package/src/modules/portal/frontend/[orgSlug]/portal/login/page.tsx +2 -1
- package/src/modules/portal/frontend/[orgSlug]/portal/page.tsx +5 -5
- package/src/modules/portal/frontend/[orgSlug]/portal/profile/page.tsx +5 -4
- package/src/modules/portal/i18n/de.json +1 -0
- package/src/modules/portal/i18n/en.json +1 -0
- package/src/modules/portal/i18n/es.json +1 -0
- package/src/modules/portal/i18n/ko.json +1 -0
- package/src/modules/portal/i18n/pl.json +1 -0
- package/src/modules/portal/lib/navigation.ts +8 -3
- package/src/modules/query_index/lib/engine.ts +111 -16
- package/src/modules/staff/backend/staff/time-tracking/page.tsx +161 -130
- package/src/modules/staff/backend/staff/time-tracking/projects/[id]/page.tsx +55 -43
- package/src/modules/staff/backend/staff/time-tracking/reports/[id]/page.tsx +61 -38
- package/src/modules/staff/extension-points.ts +16 -0
- package/src/modules/staff/frontend/[orgSlug]/portal/time-reports/[id]/page.tsx +3 -4
- package/src/modules/staff/frontend/[orgSlug]/portal/time-reports/page.tsx +3 -4
- package/src/modules/staff/i18n/de.json +3 -0
- package/src/modules/staff/i18n/en.json +3 -0
- package/src/modules/staff/i18n/es.json +3 -0
- package/src/modules/staff/i18n/ko.json +3 -0
- package/src/modules/staff/i18n/pl.json +3 -0
- package/src/modules/staff/lib/time-tracking-ui/ReportSheet.tsx +32 -29
- package/src/modules/staff/lib/time-tracking-ui/TaskListView.tsx +89 -79
- package/src/modules/warranty_claims/api/ai/assess/route.ts +2 -2
- package/src/modules/warranty_claims/api/ai/draft-reply/route.ts +2 -3
- package/src/modules/warranty_claims/api/ai/suggest/route.ts +3 -3
- package/src/modules/warranty_claims/api/assign/route.ts +3 -3
- package/src/modules/warranty_claims/api/credit-memo/route.ts +2 -2
- package/src/modules/warranty_claims/api/entitlement/route.ts +2 -2
- package/src/modules/warranty_claims/api/events/route.ts +4 -4
- package/src/modules/warranty_claims/api/external/claims/route.ts +3 -3
- package/src/modules/warranty_claims/api/portal/claims/[id]/submit/route.ts +2 -2
- package/src/modules/warranty_claims/api/portal/claims/[id]/withdraw/route.ts +2 -2
- package/src/modules/warranty_claims/api/portal/claims/route.ts +2 -2
- package/src/modules/warranty_claims/api/portal/events/route.ts +2 -2
- package/src/modules/warranty_claims/api/receiving/route.ts +2 -2
- package/src/modules/warranty_claims/api/replacement-order/route.ts +2 -2
- package/src/modules/warranty_claims/api/return-label/route.ts +2 -2
- package/src/modules/warranty_claims/api/risk/route.ts +2 -2
- package/src/modules/warranty_claims/api/sales-return/route.ts +2 -2
- package/src/modules/warranty_claims/api/settings-general/route.ts +4 -4
- package/src/modules/warranty_claims/api/stats/route.ts +2 -2
- package/src/modules/warranty_claims/api/submit/route.ts +3 -3
- package/src/modules/warranty_claims/api/transition/route.ts +3 -3
- package/src/modules/warranty_claims/api/vendor-recovery/route.ts +3 -3
- package/src/modules/warranty_claims/api/vendor-recovery-suggestions/route.ts +2 -2
- package/src/modules/warranty_claims/backend/page.tsx +4 -2
- package/src/modules/warranty_claims/backend/warranty_claims/[id]/page.tsx +9 -2
- package/src/modules/warranty_claims/backend/warranty_claims/settings/page.tsx +4 -2
- package/src/modules/warranty_claims/frontend/[orgSlug]/portal/claims/[id]/page.tsx +5 -4
- package/src/modules/warranty_claims/frontend/[orgSlug]/portal/claims/new/page.tsx +5 -2
- package/src/modules/warranty_claims/frontend/[orgSlug]/portal/claims/page.tsx +5 -2
- package/src/modules/workflows/components/DefinitionTriggersEditor.tsx +1 -1
- package/src/modules/workflows/frontend/[orgSlug]/portal/tasks/[id]/page.tsx +2 -2
- package/src/modules/workflows/i18n/de.json +1 -1
- package/src/modules/workflows/i18n/en.json +1 -1
- package/src/modules/workflows/i18n/es.json +1 -1
- package/src/modules/workflows/i18n/ko.json +1 -1
- package/src/modules/workflows/i18n/pl.json +1 -1
- package/src/modules/workflows/lib/event-trigger-service.ts +139 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/modules/data_sync/components/IntegrationScheduleTab.tsx"],
|
|
4
|
-
"sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { apiCall, withScopedApiRequestHeaders } from '@open-mercato/ui/backend/utils/apiCall'\nimport { buildOptimisticLockHeader } from '@open-mercato/ui/backend/utils/optimisticLock'\nimport { useGuardedMutation } from '@open-mercato/ui/backend/injection/useGuardedMutation'\nimport { surfaceRecordConflict } from '@open-mercato/ui/backend/conflicts'\nimport { flash } from '@open-mercato/ui/backend/FlashMessages'\nimport { Badge } from '@open-mercato/ui/primitives/badge'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { Input } from '@open-mercato/ui/primitives/input'\nimport { Label } from '@open-mercato/ui/primitives/label'\nimport { Alert, AlertDescription } from '@open-mercato/ui/primitives/alert'\nimport {\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n} from '@open-mercato/ui/primitives/select'\nimport { Spinner } from '@open-mercato/ui/primitives/spinner'\nimport { Switch } from '@open-mercato/ui/primitives/switch'\nimport { useOrganizationScopeVersion } from '@open-mercato/shared/lib/frontend/useOrganizationScope'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { getSyncSummaryVariant } from '../lib/syncRunStatus'\nimport type { RunParameter } from '../lib/adapter'\nimport { getApplicableRunParameters } from '../lib/run-parameters'\nimport {\n buildDefaultRunParameterValues,\n hasRequiredRunParameterWithoutDefault,\n} from './RunParameterFields'\nimport {\n CalendarClock,\n Play,\n RefreshCw,\n Save,\n ShieldAlert,\n ShieldCheck,\n Trash2,\n} from 'lucide-react'\n\ntype SyncOption = {\n integrationId: string\n title: string\n direction: 'import' | 'export' | 'bidirectional'\n runMode?: 'generic' | 'provider'\n canStartRun?: boolean\n supportedEntities: string[]\n runParameters?: RunParameter[]\n hasCredentials: boolean\n isEnabled: boolean\n}\n\ntype SyncOptionsResponse = {\n items?: SyncOption[]\n}\n\ntype SyncScheduleRecord = {\n id: string\n integrationId: string\n entityType: string\n direction: 'import' | 'export'\n scheduleType: 'cron' | 'interval'\n scheduleValue: string\n timezone: string\n fullSync: boolean\n isEnabled: boolean\n lastRunAt: string | null\n updatedAt?: string | null\n}\n\ntype SyncSchedulesResponse = {\n items?: SyncScheduleRecord[]\n}\n\ntype SyncScheduleEditorState = {\n id?: string\n scheduleType: 'cron' | 'interval'\n scheduleValue: string\n timezone: string\n fullSync: boolean\n isEnabled: boolean\n lastRunAt: string | null\n updatedAt?: string | null\n}\n\ntype IntegrationScheduleTabProps = {\n integrationId: string\n hasCredentials: boolean\n isEnabled: boolean\n}\n\nconst DEFAULT_TIMEZONE = Intl.DateTimeFormat().resolvedOptions().timeZone || 'UTC'\n\nfunction formatEntityTypeLabel(entityType: string): string {\n return entityType\n .replace(/[_-]+/g, ' ')\n .replace(/\\b\\w/g, (letter) => letter.toUpperCase())\n}\n\nfunction buildDefaultScheduleState(entityType: string): SyncScheduleEditorState {\n const normalized = entityType.trim().toLowerCase()\n const longerInterval = normalized === 'categories' || normalized === 'attributes'\n return {\n scheduleType: 'interval',\n scheduleValue: longerInterval ? '6h' : '1h',\n timezone: DEFAULT_TIMEZONE,\n fullSync: normalized !== 'products',\n isEnabled: true,\n lastRunAt: null,\n updatedAt: null,\n }\n}\n\nfunction getSupportedDirections(direction: SyncOption['direction'] | null | undefined): Array<'import' | 'export'> {\n if (direction === 'export') return ['export']\n if (direction === 'bidirectional') return ['import', 'export']\n return ['import']\n}\n\nfunction buildScheduleKey(entityType: string, direction: 'import' | 'export'): string {\n return `${entityType}:${direction}`\n}\n\nfunction buildScheduleEditors(\n entityTypes: string[],\n directions: Array<'import' | 'export'>,\n records: SyncScheduleRecord[],\n): Record<string, SyncScheduleEditorState> {\n const nextEntries: Array<[string, SyncScheduleEditorState]> = []\n for (const entityType of entityTypes) {\n for (const direction of directions) {\n const record = records.find((item) => item.entityType === entityType && item.direction === direction)\n nextEntries.push([\n buildScheduleKey(entityType, direction),\n record\n ? {\n id: record.id,\n scheduleType: record.scheduleType,\n scheduleValue: record.scheduleValue,\n timezone: record.timezone,\n fullSync: record.fullSync,\n isEnabled: record.isEnabled,\n lastRunAt: record.lastRunAt,\n updatedAt: record.updatedAt ?? null,\n }\n : buildDefaultScheduleState(entityType),\n ])\n }\n }\n return Object.fromEntries(nextEntries)\n}\n\nexport function IntegrationScheduleTab(props: IntegrationScheduleTabProps) {\n const t = useT()\n const scopeVersion = useOrganizationScopeVersion()\n const { runMutation } = useGuardedMutation<Record<string, unknown>>({\n contextId: 'data_sync.integrationTab',\n })\n const [option, setOption] = React.useState<SyncOption | null>(null)\n const [schedules, setSchedules] = React.useState<Record<string, SyncScheduleEditorState>>({})\n const [isLoading, setIsLoading] = React.useState(true)\n const [runningKey, setRunningKey] = React.useState<string | null>(null)\n const [savingKey, setSavingKey] = React.useState<string | null>(null)\n const [deletingKey, setDeletingKey] = React.useState<string | null>(null)\n\n const load = React.useCallback(async () => {\n setIsLoading(true)\n try {\n const [optionsCall, schedulesCall] = await Promise.all([\n apiCall<SyncOptionsResponse>('/api/data_sync/options', undefined, { fallback: { items: [] } }),\n apiCall<SyncSchedulesResponse>(`/api/data_sync/schedules?integrationId=${encodeURIComponent(props.integrationId)}&page=1&pageSize=100`, undefined, { fallback: { items: [] } }),\n ])\n\n const resolvedOption = (optionsCall.result?.items ?? []).find((item) => item.integrationId === props.integrationId) ?? null\n setOption(resolvedOption)\n\n const supportedEntities = resolvedOption?.supportedEntities ?? []\n const supportedDirections = getSupportedDirections(resolvedOption?.direction)\n setSchedules(buildScheduleEditors(supportedEntities, supportedDirections, schedulesCall.result?.items ?? []))\n } catch (error) {\n const message = error instanceof Error ? error.message : t('data_sync.integrationTab.loadError', 'Failed to load sync schedules.')\n flash(message, 'error')\n } finally {\n setIsLoading(false)\n }\n }, [props.integrationId, t])\n\n React.useEffect(() => {\n void load()\n }, [load, scopeVersion])\n\n const supportedDirections = React.useMemo(\n () => getSupportedDirections(option?.direction),\n [option?.direction],\n )\n\n const rows = React.useMemo(\n () => (option?.supportedEntities ?? []).flatMap((entityType) => (\n supportedDirections.map((direction) => ({\n entityType,\n direction,\n key: buildScheduleKey(entityType, direction),\n }))\n )),\n [option?.supportedEntities, supportedDirections],\n )\n\n const updateScheduleEditor = React.useCallback((key: string, patch: Partial<SyncScheduleEditorState>, entityType: string) => {\n setSchedules((current) => ({\n ...current,\n [key]: {\n ...(current[key] ?? buildDefaultScheduleState(entityType)),\n ...patch,\n },\n }))\n }, [])\n\n const handleStartSync = React.useCallback(async (entityType: string, direction: 'import' | 'export', scheduleKey: string) => {\n if (!props.isEnabled) {\n flash(t('data_sync.integrationTab.integrationDisabled', 'Enable the integration before starting a sync.'), 'error')\n return\n }\n if (!props.hasCredentials) {\n flash(t('data_sync.integrationTab.credentialsMissing', 'Configure credentials before starting a sync.'), 'error')\n return\n }\n if (option?.canStartRun === false) {\n flash(t('data_sync.integrationTab.providerManaged', 'Start this integration from its provider-specific setup flow.'), 'error')\n return\n }\n\n // This table has no room for a parameter form, so a row run submits the\n // adapter's declared defaults. A parameter the operator must fill in has no\n // default to send, so route them to the Data Sync dashboard instead of\n // letting the run API reject the request.\n const runParameters = getApplicableRunParameters(option?.runParameters, direction, entityType)\n if (hasRequiredRunParameterWithoutDefault(runParameters)) {\n flash(t('data_sync.integrationTab.parametersRequired', 'This run needs parameters. Start it from the Data Sync dashboard.'), 'error')\n return\n }\n\n setRunningKey(scheduleKey)\n try {\n const scheduleState = schedules[scheduleKey] ?? buildDefaultScheduleState(entityType)\n const requestBody: Record<string, unknown> = {\n integrationId: props.integrationId,\n entityType,\n direction,\n fullSync: scheduleState.fullSync,\n batchSize: 100,\n }\n if (runParameters.length > 0) requestBody.parameters = buildDefaultRunParameterValues(runParameters)\n const call = await runMutation({\n // optimistic-lock-exempt: starts a new sync run (create), not a concurrent record edit\n operation: () => apiCall<{ id: string }>('/api/data_sync/run', {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify(requestBody),\n }, { fallback: null }),\n mutationPayload: requestBody,\n context: {\n operation: 'create',\n actionId: 'start-sync-run',\n integrationId: props.integrationId,\n },\n })\n\n if (!call.ok) {\n throw new Error((call.result as { error?: string } | null)?.error ?? 'Failed to start sync')\n }\n\n flash(t('data_sync.integrationTab.runStarted', 'Sync run started.'), 'success')\n } catch (error) {\n const message = error instanceof Error ? error.message : t('data_sync.integrationTab.runError', 'Failed to start sync.')\n flash(message, 'error')\n } finally {\n setRunningKey(null)\n }\n }, [option?.canStartRun, option?.runParameters, props.hasCredentials, props.integrationId, props.isEnabled, runMutation, schedules, t])\n\n const handleSaveSchedule = React.useCallback(async (entityType: string, direction: 'import' | 'export', scheduleKey: string) => {\n const scheduleState = schedules[scheduleKey] ?? buildDefaultScheduleState(entityType)\n setSavingKey(scheduleKey)\n try {\n // Keyed upsert (POST). When the server resolves an existing row the save\n // version-checks against this schedule's loaded `updatedAt`; for a brand\n // new row the header is empty so the create path is unaffected.\n const call = await runMutation({\n operation: () => withScopedApiRequestHeaders(\n buildOptimisticLockHeader(scheduleState.updatedAt),\n () => apiCall<SyncScheduleRecord>('/api/data_sync/schedules', {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({\n integrationId: props.integrationId,\n entityType,\n direction,\n scheduleType: scheduleState.scheduleType,\n scheduleValue: scheduleState.scheduleValue,\n timezone: scheduleState.timezone,\n fullSync: scheduleState.fullSync,\n isEnabled: scheduleState.isEnabled,\n }),\n }, { fallback: null }),\n ),\n mutationPayload: {\n integrationId: props.integrationId,\n entityType,\n direction,\n scheduleType: scheduleState.scheduleType,\n scheduleValue: scheduleState.scheduleValue,\n timezone: scheduleState.timezone,\n fullSync: scheduleState.fullSync,\n isEnabled: scheduleState.isEnabled,\n },\n context: {\n operation: 'update',\n actionId: 'save-sync-schedule',\n integrationId: props.integrationId,\n },\n })\n\n if (!call.ok || !call.result) {\n const conflictError = Object.assign(\n new Error((call.result as { error?: string } | null)?.error ?? 'Failed to save schedule'),\n {\n status: call.status,\n ...(call.result && typeof call.result === 'object' ? call.result : {}),\n },\n )\n if (surfaceRecordConflict(conflictError, t)) {\n return\n }\n throw conflictError\n }\n\n updateScheduleEditor(scheduleKey, {\n id: call.result.id,\n scheduleType: call.result.scheduleType,\n scheduleValue: call.result.scheduleValue,\n timezone: call.result.timezone,\n fullSync: call.result.fullSync,\n isEnabled: call.result.isEnabled,\n lastRunAt: call.result.lastRunAt,\n updatedAt: call.result.updatedAt ?? null,\n }, entityType)\n flash(t('data_sync.dashboard.schedule.success', 'Recurring schedule saved'), 'success')\n } catch (error) {\n const message = error instanceof Error ? error.message : t('data_sync.dashboard.schedule.error', 'Failed to save recurring schedule')\n flash(message, 'error')\n } finally {\n setSavingKey(null)\n }\n }, [props.integrationId, runMutation, schedules, t, updateScheduleEditor])\n\n const handleDeleteSchedule = React.useCallback(async (entityType: string, scheduleKey: string) => {\n const scheduleState = schedules[scheduleKey]\n if (!scheduleState?.id) {\n updateScheduleEditor(scheduleKey, buildDefaultScheduleState(entityType), entityType)\n return\n }\n\n setDeletingKey(scheduleKey)\n try {\n const call = await runMutation({\n operation: () => withScopedApiRequestHeaders(\n buildOptimisticLockHeader(scheduleState.updatedAt),\n () => apiCall(`/api/data_sync/schedules/${encodeURIComponent(scheduleState.id as string)}`, {\n method: 'DELETE',\n }, { fallback: null }),\n ),\n mutationPayload: {\n scheduleId: scheduleState.id,\n },\n context: {\n operation: 'delete',\n actionId: 'delete-sync-schedule',\n },\n })\n\n if (!call.ok) {\n throw new Error((call.result as { error?: string } | null)?.error ?? 'Failed to delete schedule')\n }\n\n setSchedules((current) => ({\n ...current,\n [scheduleKey]: buildDefaultScheduleState(entityType),\n }))\n flash(t('data_sync.dashboard.schedule.deleteSuccess', 'Recurring schedule removed'), 'success')\n } catch (error) {\n const message = error instanceof Error ? error.message : t('data_sync.dashboard.schedule.deleteError', 'Failed to remove recurring schedule')\n flash(message, 'error')\n } finally {\n setDeletingKey(null)\n }\n }, [runMutation, schedules, t, updateScheduleEditor])\n\n if (isLoading) {\n return (\n <div className=\"flex min-h-40 items-center justify-center rounded-lg border bg-card\">\n <Spinner />\n </div>\n )\n }\n\n if (!option) {\n return (\n <Alert status=\"warning\">\n <AlertDescription>\n {t('data_sync.integrationTab.notAvailable', 'This integration is not registered as a data sync provider.')}\n </AlertDescription>\n </Alert>\n )\n }\n\n return (\n <section className=\"space-y-4 rounded-lg border bg-card p-6\">\n <div className=\"flex flex-wrap items-start justify-between gap-3\">\n <div className=\"space-y-2\">\n <div className=\"flex flex-wrap items-center gap-2\">\n <Badge variant={getSyncSummaryVariant(props.isEnabled ? 'enabled' : 'disabled')}>\n {props.isEnabled ? <ShieldCheck className=\"mr-2 h-3.5 w-3.5\" /> : <ShieldAlert className=\"mr-2 h-3.5 w-3.5\" />}\n {props.isEnabled\n ? t('data_sync.dashboard.start.status.enabled', 'Integration enabled')\n : t('data_sync.dashboard.start.status.disabled', 'Integration disabled')}\n </Badge>\n <Badge variant={getSyncSummaryVariant(props.hasCredentials ? 'ready' : 'missing')}>\n <CalendarClock className=\"mr-2 h-3.5 w-3.5\" />\n {props.hasCredentials\n ? t('data_sync.dashboard.start.status.credentialsReady', 'Credentials ready')\n : t('data_sync.dashboard.start.status.credentialsMissing', 'Credentials missing')}\n </Badge>\n </div>\n <div>\n <h3 className=\"text-base font-semibold\">{t('data_sync.integrationTab.title', 'Sync schedules')}</h3>\n <p className=\"text-sm text-muted-foreground\">\n {t('data_sync.integrationTab.description', 'Run one-off syncs or save recurring schedules for every supported entity directly from the integration detail page.')}\n </p>\n </div>\n </div>\n <Button type=\"button\" variant=\"outline\" onClick={() => void load()} disabled={isLoading}>\n <RefreshCw className=\"mr-2 h-4 w-4\" />\n {t('data_sync.integrationTab.refresh', 'Refresh')}\n </Button>\n </div>\n\n {!props.isEnabled ? (\n <Alert status=\"warning\">\n <AlertDescription>\n {t('data_sync.integrationTab.integrationDisabledNotice', 'The integration is disabled. You can save schedules now, but runs will stay blocked until the integration is enabled.')}\n </AlertDescription>\n </Alert>\n ) : null}\n\n {!props.hasCredentials ? (\n <Alert status=\"warning\">\n <AlertDescription>\n {t('data_sync.integrationTab.credentialsMissingNotice', 'Credentials are still missing. Save schedules first if you want, but manual and scheduled runs will fail until credentials are configured.')}\n </AlertDescription>\n </Alert>\n ) : null}\n\n {option.canStartRun === false ? (\n <Alert status=\"information\">\n <AlertDescription>\n {t('data_sync.integrationTab.providerManagedNotice', 'This provider needs its own setup flow before a run can start. Use the provider tab on this page instead of generic schedules.')}\n </AlertDescription>\n </Alert>\n ) : null}\n\n {rows.length === 0 ? (\n <Alert status=\"information\">\n <AlertDescription>\n {t('data_sync.integrationTab.empty', 'This provider does not expose any schedulable sync entities yet.')}\n </AlertDescription>\n </Alert>\n ) : (\n <div className=\"overflow-x-auto rounded-lg border\">\n <table className=\"w-full min-w-[1080px] text-sm\">\n <thead className=\"bg-muted/50 text-left\">\n <tr>\n <th className=\"px-3 py-2 font-medium\">{t('data_sync.dashboard.columns.entityType', 'Entity Type')}</th>\n <th className=\"px-3 py-2 font-medium\">{t('data_sync.dashboard.columns.direction', 'Direction')}</th>\n <th className=\"px-3 py-2 font-medium\">{t('data_sync.dashboard.schedule.type', 'Schedule type')}</th>\n <th className=\"px-3 py-2 font-medium\">{t('data_sync.integrationTab.columns.value', 'Value')}</th>\n <th className=\"px-3 py-2 font-medium\">{t('data_sync.dashboard.schedule.timezone', 'Timezone')}</th>\n <th className=\"px-3 py-2 font-medium\">{t('data_sync.dashboard.start.fullSync', 'Run as full sync')}</th>\n <th className=\"px-3 py-2 font-medium\">{t('data_sync.dashboard.schedule.enabled', 'Schedule enabled')}</th>\n <th className=\"px-3 py-2 font-medium\">{t('data_sync.integrationTab.columns.lastRun', 'Last run')}</th>\n <th className=\"px-3 py-2 font-medium\">{t('data_sync.integrationTab.columns.actions', 'Actions')}</th>\n </tr>\n </thead>\n <tbody>\n {rows.map((row) => {\n const scheduleState = schedules[row.key] ?? buildDefaultScheduleState(row.entityType)\n const isRunning = runningKey === row.key\n const isSaving = savingKey === row.key\n const isDeleting = deletingKey === row.key\n const controlsDisabled = isRunning || isSaving || isDeleting\n return (\n <tr key={row.key} className=\"border-t align-top\">\n <td className=\"px-3 py-3 font-medium\">{formatEntityTypeLabel(row.entityType)}</td>\n <td className=\"px-3 py-3\">{t(`data_sync.dashboard.direction.${row.direction}`, row.direction === 'import' ? 'Import' : 'Export')}</td>\n <td className=\"px-3 py-3\">\n <Select\n value={scheduleState.scheduleType}\n onValueChange={(value) => updateScheduleEditor(row.key, {\n scheduleType: value === 'cron' ? 'cron' : 'interval',\n }, row.entityType)}\n disabled={controlsDisabled}\n >\n <SelectTrigger size=\"lg\" className=\"min-w-32\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value=\"interval\">{t('data_sync.dashboard.schedule.interval', 'Interval')}</SelectItem>\n <SelectItem value=\"cron\">{t('data_sync.dashboard.schedule.cron', 'Cron')}</SelectItem>\n </SelectContent>\n </Select>\n </td>\n <td className=\"px-3 py-3\">\n <Input\n value={scheduleState.scheduleValue}\n onChange={(event) => updateScheduleEditor(row.key, { scheduleValue: event.target.value }, row.entityType)}\n disabled={controlsDisabled}\n placeholder={scheduleState.scheduleType === 'cron' ? '0 * * * *' : '1h'}\n />\n </td>\n <td className=\"px-3 py-3\">\n <Input\n value={scheduleState.timezone}\n onChange={(event) => updateScheduleEditor(row.key, { timezone: event.target.value }, row.entityType)}\n disabled={controlsDisabled}\n />\n </td>\n <td className=\"px-3 py-3\">\n <label className=\"flex min-h-10 items-center gap-2 text-sm\">\n <Switch\n checked={scheduleState.fullSync}\n onCheckedChange={(checked) => updateScheduleEditor(row.key, { fullSync: checked }, row.entityType)}\n disabled={controlsDisabled}\n aria-label={t('data_sync.dashboard.start.fullSync', 'Run as full sync')}\n />\n <span>{t('data_sync.integrationTab.fullSyncShort', 'Full')}</span>\n </label>\n </td>\n <td className=\"px-3 py-3\">\n <label className=\"flex min-h-10 items-center gap-2 text-sm\">\n <Switch\n checked={scheduleState.isEnabled}\n onCheckedChange={(checked) => updateScheduleEditor(row.key, { isEnabled: checked }, row.entityType)}\n disabled={controlsDisabled}\n aria-label={t('data_sync.dashboard.schedule.enabled', 'Schedule enabled')}\n />\n <span>{scheduleState.isEnabled ? t('data_sync.dashboard.schedule.status.shortEnabled', 'Scheduled') : t('data_sync.dashboard.schedule.status.shortDisabled', 'Paused')}</span>\n </label>\n </td>\n <td className=\"px-3 py-3 text-muted-foreground\">\n {scheduleState.lastRunAt\n ? new Date(scheduleState.lastRunAt).toLocaleString()\n : scheduleState.id\n ? t('data_sync.dashboard.schedule.neverRun', 'Saved, but no scheduled execution has completed yet.')\n : t('data_sync.dashboard.schedule.none', 'No recurring schedule saved for this target yet.')}\n </td>\n <td className=\"px-3 py-3\">\n <div className=\"flex flex-wrap gap-2\">\n <Button\n type=\"button\"\n size=\"sm\"\n onClick={() => void handleStartSync(row.entityType, row.direction, row.key)}\n disabled={controlsDisabled || !props.isEnabled || !props.hasCredentials || option.canStartRun === false}\n >\n {isRunning ? <Spinner className=\"mr-2 h-4 w-4\" /> : <Play className=\"mr-2 h-4 w-4\" />}\n {isRunning\n ? t('data_sync.integrationTab.starting', 'Starting...')\n : t('data_sync.integrationTab.start', 'Run now')}\n </Button>\n <Button\n type=\"button\"\n size=\"sm\"\n variant=\"outline\"\n onClick={() => void handleSaveSchedule(row.entityType, row.direction, row.key)}\n disabled={controlsDisabled || option.canStartRun === false}\n >\n {isSaving ? <Spinner className=\"mr-2 h-4 w-4\" /> : <Save className=\"mr-2 h-4 w-4\" />}\n {isSaving\n ? t('data_sync.dashboard.schedule.saving', 'Saving...')\n : t('data_sync.dashboard.schedule.save', 'Save recurring schedule')}\n </Button>\n <Button\n type=\"button\"\n size=\"sm\"\n variant=\"outline\"\n onClick={() => void handleDeleteSchedule(row.entityType, row.key)}\n disabled={controlsDisabled || !scheduleState.id}\n >\n {isDeleting ? <Spinner className=\"mr-2 h-4 w-4\" /> : <Trash2 className=\"mr-2 h-4 w-4\" />}\n {isDeleting\n ? t('data_sync.dashboard.schedule.deleting', 'Removing...')\n : t('data_sync.dashboard.schedule.delete', 'Remove schedule')}\n </Button>\n </div>\n </td>\n </tr>\n )\n })}\n </tbody>\n </table>\n </div>\n )}\n\n <div className=\"grid gap-3 rounded-lg border border-dashed p-4 text-sm text-muted-foreground md:grid-cols-3\">\n <div className=\"space-y-1\">\n <Label>{t('data_sync.dashboard.schedule.interval', 'Interval')}</Label>\n <p>{t('data_sync.dashboard.schedule.intervalHelp', 'Example: `1h`, `6h`, or `24h` for repeating intervals.')}</p>\n </div>\n <div className=\"space-y-1\">\n <Label>{t('data_sync.dashboard.schedule.cron', 'Cron')}</Label>\n <p>{t('data_sync.dashboard.schedule.cronHelp', 'Example: `0 * * * *` runs at the start of every hour.')}</p>\n </div>\n <div className=\"space-y-1\">\n <Label>{t('data_sync.integrationTab.runNowTitle', 'Manual runs')}</Label>\n <p>{t('data_sync.integrationTab.runNowHelp', 'Run now uses the full-sync checkbox from the same row and starts progress tracking immediately in Data Sync.')}</p>\n </div>\n </div>\n </section>\n )\n}\n\nexport default IntegrationScheduleTab\n"],
|
|
5
|
-
"mappings": "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",
|
|
4
|
+
"sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { apiCall, withScopedApiRequestHeaders } from '@open-mercato/ui/backend/utils/apiCall'\nimport { buildOptimisticLockHeader } from '@open-mercato/ui/backend/utils/optimisticLock'\nimport { useGuardedMutation } from '@open-mercato/ui/backend/injection/useGuardedMutation'\nimport { surfaceRecordConflict } from '@open-mercato/ui/backend/conflicts'\nimport { flash } from '@open-mercato/ui/backend/FlashMessages'\nimport { Badge } from '@open-mercato/ui/primitives/badge'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { Input } from '@open-mercato/ui/primitives/input'\nimport { Label } from '@open-mercato/ui/primitives/label'\nimport { Alert, AlertDescription } from '@open-mercato/ui/primitives/alert'\nimport {\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n} from '@open-mercato/ui/primitives/select'\nimport { Spinner } from '@open-mercato/ui/primitives/spinner'\nimport { Switch } from '@open-mercato/ui/primitives/switch'\nimport { useOrganizationScopeVersion } from '@open-mercato/shared/lib/frontend/useOrganizationScope'\nimport { isValidScheduleInterval } from '@open-mercato/shared/lib/schedule/interval'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { hasScheduleValueFieldError } from '../lib/schedule-value'\nimport { getSyncSummaryVariant } from '../lib/syncRunStatus'\nimport type { RunParameter } from '../lib/adapter'\nimport { getApplicableRunParameters } from '../lib/run-parameters'\nimport {\n buildDefaultRunParameterValues,\n hasRequiredRunParameterWithoutDefault,\n} from './RunParameterFields'\nimport {\n CalendarClock,\n Play,\n RefreshCw,\n Save,\n ShieldAlert,\n ShieldCheck,\n Trash2,\n} from 'lucide-react'\n\ntype SyncOption = {\n integrationId: string\n title: string\n direction: 'import' | 'export' | 'bidirectional'\n runMode?: 'generic' | 'provider'\n canStartRun?: boolean\n supportedEntities: string[]\n runParameters?: RunParameter[]\n hasCredentials: boolean\n isEnabled: boolean\n}\n\ntype SyncOptionsResponse = {\n items?: SyncOption[]\n}\n\ntype SyncScheduleRecord = {\n id: string\n integrationId: string\n entityType: string\n direction: 'import' | 'export'\n scheduleType: 'cron' | 'interval'\n scheduleValue: string\n timezone: string\n fullSync: boolean\n isEnabled: boolean\n lastRunAt: string | null\n updatedAt?: string | null\n}\n\ntype SyncSchedulesResponse = {\n items?: SyncScheduleRecord[]\n}\n\ntype SyncScheduleEditorState = {\n id?: string\n scheduleType: 'cron' | 'interval'\n scheduleValue: string\n timezone: string\n fullSync: boolean\n isEnabled: boolean\n lastRunAt: string | null\n updatedAt?: string | null\n}\n\ntype IntegrationScheduleTabProps = {\n integrationId: string\n hasCredentials: boolean\n isEnabled: boolean\n}\n\nconst DEFAULT_TIMEZONE = Intl.DateTimeFormat().resolvedOptions().timeZone || 'UTC'\n\nfunction formatEntityTypeLabel(entityType: string): string {\n return entityType\n .replace(/[_-]+/g, ' ')\n .replace(/\\b\\w/g, (letter) => letter.toUpperCase())\n}\n\nfunction buildDefaultScheduleState(entityType: string): SyncScheduleEditorState {\n const normalized = entityType.trim().toLowerCase()\n const longerInterval = normalized === 'categories' || normalized === 'attributes'\n return {\n scheduleType: 'interval',\n scheduleValue: longerInterval ? '6h' : '1h',\n timezone: DEFAULT_TIMEZONE,\n fullSync: normalized !== 'products',\n isEnabled: true,\n lastRunAt: null,\n updatedAt: null,\n }\n}\n\nfunction getSupportedDirections(direction: SyncOption['direction'] | null | undefined): Array<'import' | 'export'> {\n if (direction === 'export') return ['export']\n if (direction === 'bidirectional') return ['import', 'export']\n return ['import']\n}\n\nfunction buildScheduleKey(entityType: string, direction: 'import' | 'export'): string {\n return `${entityType}:${direction}`\n}\n\ntype ScheduleValueError = 'empty' | 'format' | undefined\n\nfunction buildScheduleValueErrorId(scheduleKey: string): string {\n return `data-sync-schedule-value-error-${scheduleKey.replace(/[^a-zA-Z0-9]+/g, '-')}`\n}\n\nfunction detectScheduleValueError(\n scheduleType: 'cron' | 'interval',\n scheduleValue: string,\n): ScheduleValueError {\n if (scheduleValue.length === 0) return 'empty'\n if (scheduleType === 'interval' && !isValidScheduleInterval(scheduleValue)) return 'format'\n return undefined\n}\n\nfunction buildScheduleEditors(\n entityTypes: string[],\n directions: Array<'import' | 'export'>,\n records: SyncScheduleRecord[],\n): Record<string, SyncScheduleEditorState> {\n const nextEntries: Array<[string, SyncScheduleEditorState]> = []\n for (const entityType of entityTypes) {\n for (const direction of directions) {\n const record = records.find((item) => item.entityType === entityType && item.direction === direction)\n nextEntries.push([\n buildScheduleKey(entityType, direction),\n record\n ? {\n id: record.id,\n scheduleType: record.scheduleType,\n scheduleValue: record.scheduleValue,\n timezone: record.timezone,\n fullSync: record.fullSync,\n isEnabled: record.isEnabled,\n lastRunAt: record.lastRunAt,\n updatedAt: record.updatedAt ?? null,\n }\n : buildDefaultScheduleState(entityType),\n ])\n }\n }\n return Object.fromEntries(nextEntries)\n}\n\nexport function IntegrationScheduleTab(props: IntegrationScheduleTabProps) {\n const t = useT()\n const scopeVersion = useOrganizationScopeVersion()\n const { runMutation } = useGuardedMutation<Record<string, unknown>>({\n contextId: 'data_sync.integrationTab',\n })\n const [option, setOption] = React.useState<SyncOption | null>(null)\n const [schedules, setSchedules] = React.useState<Record<string, SyncScheduleEditorState>>({})\n const [isLoading, setIsLoading] = React.useState(true)\n const [runningKey, setRunningKey] = React.useState<string | null>(null)\n const [savingKey, setSavingKey] = React.useState<string | null>(null)\n const [deletingKey, setDeletingKey] = React.useState<string | null>(null)\n const [valueErrors, setValueErrors] = React.useState<Record<string, ScheduleValueError>>({})\n\n const describeScheduleValueError = React.useCallback((\n valueError: ScheduleValueError,\n scheduleType: 'cron' | 'interval',\n ) => {\n if (valueError === 'empty') return t('data_sync.dashboard.schedule.invalidValue', 'Provide a schedule value before saving.')\n return scheduleType === 'cron'\n ? t('data_sync.dashboard.schedule.invalidCron', 'Enter a cron expression the scheduler can parse, for example `0 * * * *`.')\n : t('data_sync.dashboard.schedule.invalidInterval', 'Enter a whole number followed by s, m, h or d (for example `15m`, `1h` or `24h`), at least one minute long.')\n }, [t])\n\n const load = React.useCallback(async () => {\n setIsLoading(true)\n try {\n const [optionsCall, schedulesCall] = await Promise.all([\n apiCall<SyncOptionsResponse>('/api/data_sync/options', undefined, { fallback: { items: [] } }),\n apiCall<SyncSchedulesResponse>(`/api/data_sync/schedules?integrationId=${encodeURIComponent(props.integrationId)}&page=1&pageSize=100`, undefined, { fallback: { items: [] } }),\n ])\n\n const resolvedOption = (optionsCall.result?.items ?? []).find((item) => item.integrationId === props.integrationId) ?? null\n setOption(resolvedOption)\n\n const supportedEntities = resolvedOption?.supportedEntities ?? []\n const supportedDirections = getSupportedDirections(resolvedOption?.direction)\n setSchedules(buildScheduleEditors(supportedEntities, supportedDirections, schedulesCall.result?.items ?? []))\n setValueErrors({})\n } catch (error) {\n const message = error instanceof Error ? error.message : t('data_sync.integrationTab.loadError', 'Failed to load sync schedules.')\n flash(message, 'error')\n } finally {\n setIsLoading(false)\n }\n }, [props.integrationId, t])\n\n React.useEffect(() => {\n void load()\n }, [load, scopeVersion])\n\n const supportedDirections = React.useMemo(\n () => getSupportedDirections(option?.direction),\n [option?.direction],\n )\n\n const rows = React.useMemo(\n () => (option?.supportedEntities ?? []).flatMap((entityType) => (\n supportedDirections.map((direction) => ({\n entityType,\n direction,\n key: buildScheduleKey(entityType, direction),\n }))\n )),\n [option?.supportedEntities, supportedDirections],\n )\n\n const updateScheduleEditor = React.useCallback((key: string, patch: Partial<SyncScheduleEditorState>, entityType: string) => {\n setSchedules((current) => ({\n ...current,\n [key]: {\n ...(current[key] ?? buildDefaultScheduleState(entityType)),\n ...patch,\n },\n }))\n if (patch.scheduleValue !== undefined || patch.scheduleType !== undefined) {\n setValueErrors((current) => (current[key] ? { ...current, [key]: undefined } : current))\n }\n }, [])\n\n const handleStartSync = React.useCallback(async (entityType: string, direction: 'import' | 'export', scheduleKey: string) => {\n if (!props.isEnabled) {\n flash(t('data_sync.integrationTab.integrationDisabled', 'Enable the integration before starting a sync.'), 'error')\n return\n }\n if (!props.hasCredentials) {\n flash(t('data_sync.integrationTab.credentialsMissing', 'Configure credentials before starting a sync.'), 'error')\n return\n }\n if (option?.canStartRun === false) {\n flash(t('data_sync.integrationTab.providerManaged', 'Start this integration from its provider-specific setup flow.'), 'error')\n return\n }\n\n // This table has no room for a parameter form, so a row run submits the\n // adapter's declared defaults. A parameter the operator must fill in has no\n // default to send, so route them to the Data Sync dashboard instead of\n // letting the run API reject the request.\n const runParameters = getApplicableRunParameters(option?.runParameters, direction, entityType)\n if (hasRequiredRunParameterWithoutDefault(runParameters)) {\n flash(t('data_sync.integrationTab.parametersRequired', 'This run needs parameters. Start it from the Data Sync dashboard.'), 'error')\n return\n }\n\n setRunningKey(scheduleKey)\n try {\n const scheduleState = schedules[scheduleKey] ?? buildDefaultScheduleState(entityType)\n const requestBody: Record<string, unknown> = {\n integrationId: props.integrationId,\n entityType,\n direction,\n fullSync: scheduleState.fullSync,\n batchSize: 100,\n }\n if (runParameters.length > 0) requestBody.parameters = buildDefaultRunParameterValues(runParameters)\n const call = await runMutation({\n // optimistic-lock-exempt: starts a new sync run (create), not a concurrent record edit\n operation: () => apiCall<{ id: string }>('/api/data_sync/run', {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify(requestBody),\n }, { fallback: null }),\n mutationPayload: requestBody,\n context: {\n operation: 'create',\n actionId: 'start-sync-run',\n integrationId: props.integrationId,\n },\n })\n\n if (!call.ok) {\n throw new Error((call.result as { error?: string } | null)?.error ?? 'Failed to start sync')\n }\n\n flash(t('data_sync.integrationTab.runStarted', 'Sync run started.'), 'success')\n } catch (error) {\n const message = error instanceof Error ? error.message : t('data_sync.integrationTab.runError', 'Failed to start sync.')\n flash(message, 'error')\n } finally {\n setRunningKey(null)\n }\n }, [option?.canStartRun, option?.runParameters, props.hasCredentials, props.integrationId, props.isEnabled, runMutation, schedules, t])\n\n const handleSaveSchedule = React.useCallback(async (entityType: string, direction: 'import' | 'export', scheduleKey: string) => {\n const scheduleState = schedules[scheduleKey] ?? buildDefaultScheduleState(entityType)\n const scheduleValue = scheduleState.scheduleValue.trim()\n\n // The documented interval format is checked here so a value the scheduler\n // can never run never reaches the API; cron stays server-validated and\n // comes back through the same inline field error.\n const valueError = detectScheduleValueError(scheduleState.scheduleType, scheduleValue)\n if (valueError) {\n setValueErrors((current) => ({ ...current, [scheduleKey]: valueError }))\n return\n }\n\n setValueErrors((current) => (current[scheduleKey] ? { ...current, [scheduleKey]: undefined } : current))\n setSavingKey(scheduleKey)\n try {\n // Keyed upsert (POST). When the server resolves an existing row the save\n // version-checks against this schedule's loaded `updatedAt`; for a brand\n // new row the header is empty so the create path is unaffected.\n const call = await runMutation({\n operation: () => withScopedApiRequestHeaders(\n buildOptimisticLockHeader(scheduleState.updatedAt),\n () => apiCall<SyncScheduleRecord>('/api/data_sync/schedules', {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({\n integrationId: props.integrationId,\n entityType,\n direction,\n scheduleType: scheduleState.scheduleType,\n scheduleValue,\n timezone: scheduleState.timezone,\n fullSync: scheduleState.fullSync,\n isEnabled: scheduleState.isEnabled,\n }),\n }, { fallback: null }),\n ),\n mutationPayload: {\n integrationId: props.integrationId,\n entityType,\n direction,\n scheduleType: scheduleState.scheduleType,\n scheduleValue,\n timezone: scheduleState.timezone,\n fullSync: scheduleState.fullSync,\n isEnabled: scheduleState.isEnabled,\n },\n context: {\n operation: 'update',\n actionId: 'save-sync-schedule',\n integrationId: props.integrationId,\n },\n })\n\n if (!call.ok || !call.result) {\n if (hasScheduleValueFieldError(call.result)) {\n setValueErrors((current) => ({ ...current, [scheduleKey]: 'format' }))\n return\n }\n const conflictError = Object.assign(\n new Error((call.result as { error?: string } | null)?.error ?? 'Failed to save schedule'),\n {\n status: call.status,\n ...(call.result && typeof call.result === 'object' ? call.result : {}),\n },\n )\n if (surfaceRecordConflict(conflictError, t)) {\n return\n }\n throw conflictError\n }\n\n updateScheduleEditor(scheduleKey, {\n id: call.result.id,\n scheduleType: call.result.scheduleType,\n scheduleValue: call.result.scheduleValue,\n timezone: call.result.timezone,\n fullSync: call.result.fullSync,\n isEnabled: call.result.isEnabled,\n lastRunAt: call.result.lastRunAt,\n updatedAt: call.result.updatedAt ?? null,\n }, entityType)\n flash(t('data_sync.dashboard.schedule.success', 'Recurring schedule saved'), 'success')\n } catch (error) {\n const message = error instanceof Error ? error.message : t('data_sync.dashboard.schedule.error', 'Failed to save recurring schedule')\n flash(message, 'error')\n } finally {\n setSavingKey(null)\n }\n }, [props.integrationId, runMutation, schedules, t, updateScheduleEditor])\n\n const handleDeleteSchedule = React.useCallback(async (entityType: string, scheduleKey: string) => {\n const scheduleState = schedules[scheduleKey]\n if (!scheduleState?.id) {\n updateScheduleEditor(scheduleKey, buildDefaultScheduleState(entityType), entityType)\n return\n }\n\n setDeletingKey(scheduleKey)\n try {\n const call = await runMutation({\n operation: () => withScopedApiRequestHeaders(\n buildOptimisticLockHeader(scheduleState.updatedAt),\n () => apiCall(`/api/data_sync/schedules/${encodeURIComponent(scheduleState.id as string)}`, {\n method: 'DELETE',\n }, { fallback: null }),\n ),\n mutationPayload: {\n scheduleId: scheduleState.id,\n },\n context: {\n operation: 'delete',\n actionId: 'delete-sync-schedule',\n },\n })\n\n if (!call.ok) {\n throw new Error((call.result as { error?: string } | null)?.error ?? 'Failed to delete schedule')\n }\n\n setSchedules((current) => ({\n ...current,\n [scheduleKey]: buildDefaultScheduleState(entityType),\n }))\n flash(t('data_sync.dashboard.schedule.deleteSuccess', 'Recurring schedule removed'), 'success')\n } catch (error) {\n const message = error instanceof Error ? error.message : t('data_sync.dashboard.schedule.deleteError', 'Failed to remove recurring schedule')\n flash(message, 'error')\n } finally {\n setDeletingKey(null)\n }\n }, [runMutation, schedules, t, updateScheduleEditor])\n\n if (isLoading) {\n return (\n <div className=\"flex min-h-40 items-center justify-center rounded-lg border bg-card\">\n <Spinner />\n </div>\n )\n }\n\n if (!option) {\n return (\n <Alert status=\"warning\">\n <AlertDescription>\n {t('data_sync.integrationTab.notAvailable', 'This integration is not registered as a data sync provider.')}\n </AlertDescription>\n </Alert>\n )\n }\n\n return (\n <section className=\"space-y-4 rounded-lg border bg-card p-6\">\n <div className=\"flex flex-wrap items-start justify-between gap-3\">\n <div className=\"space-y-2\">\n <div className=\"flex flex-wrap items-center gap-2\">\n <Badge variant={getSyncSummaryVariant(props.isEnabled ? 'enabled' : 'disabled')}>\n {props.isEnabled ? <ShieldCheck className=\"mr-2 h-3.5 w-3.5\" /> : <ShieldAlert className=\"mr-2 h-3.5 w-3.5\" />}\n {props.isEnabled\n ? t('data_sync.dashboard.start.status.enabled', 'Integration enabled')\n : t('data_sync.dashboard.start.status.disabled', 'Integration disabled')}\n </Badge>\n <Badge variant={getSyncSummaryVariant(props.hasCredentials ? 'ready' : 'missing')}>\n <CalendarClock className=\"mr-2 h-3.5 w-3.5\" />\n {props.hasCredentials\n ? t('data_sync.dashboard.start.status.credentialsReady', 'Credentials ready')\n : t('data_sync.dashboard.start.status.credentialsMissing', 'Credentials missing')}\n </Badge>\n </div>\n <div>\n <h3 className=\"text-base font-semibold\">{t('data_sync.integrationTab.title', 'Sync schedules')}</h3>\n <p className=\"text-sm text-muted-foreground\">\n {t('data_sync.integrationTab.description', 'Run one-off syncs or save recurring schedules for every supported entity directly from the integration detail page.')}\n </p>\n </div>\n </div>\n <Button type=\"button\" variant=\"outline\" onClick={() => void load()} disabled={isLoading}>\n <RefreshCw className=\"mr-2 h-4 w-4\" />\n {t('data_sync.integrationTab.refresh', 'Refresh')}\n </Button>\n </div>\n\n {!props.isEnabled ? (\n <Alert status=\"warning\">\n <AlertDescription>\n {t('data_sync.integrationTab.integrationDisabledNotice', 'The integration is disabled. You can save schedules now, but runs will stay blocked until the integration is enabled.')}\n </AlertDescription>\n </Alert>\n ) : null}\n\n {!props.hasCredentials ? (\n <Alert status=\"warning\">\n <AlertDescription>\n {t('data_sync.integrationTab.credentialsMissingNotice', 'Credentials are still missing. Save schedules first if you want, but manual and scheduled runs will fail until credentials are configured.')}\n </AlertDescription>\n </Alert>\n ) : null}\n\n {option.canStartRun === false ? (\n <Alert status=\"information\">\n <AlertDescription>\n {t('data_sync.integrationTab.providerManagedNotice', 'This provider needs its own setup flow before a run can start. Use the provider tab on this page instead of generic schedules.')}\n </AlertDescription>\n </Alert>\n ) : null}\n\n {rows.length === 0 ? (\n <Alert status=\"information\">\n <AlertDescription>\n {t('data_sync.integrationTab.empty', 'This provider does not expose any schedulable sync entities yet.')}\n </AlertDescription>\n </Alert>\n ) : (\n <div className=\"overflow-x-auto rounded-lg border\">\n <table className=\"w-full min-w-[1080px] text-sm\">\n <thead className=\"bg-muted/50 text-left\">\n <tr>\n <th className=\"px-3 py-2 font-medium\">{t('data_sync.dashboard.columns.entityType', 'Entity Type')}</th>\n <th className=\"px-3 py-2 font-medium\">{t('data_sync.dashboard.columns.direction', 'Direction')}</th>\n <th className=\"px-3 py-2 font-medium\">{t('data_sync.dashboard.schedule.type', 'Schedule type')}</th>\n <th className=\"px-3 py-2 font-medium\">{t('data_sync.integrationTab.columns.value', 'Value')}</th>\n <th className=\"px-3 py-2 font-medium\">{t('data_sync.dashboard.schedule.timezone', 'Timezone')}</th>\n <th className=\"px-3 py-2 font-medium\">{t('data_sync.dashboard.start.fullSync', 'Run as full sync')}</th>\n <th className=\"px-3 py-2 font-medium\">{t('data_sync.dashboard.schedule.enabled', 'Schedule enabled')}</th>\n <th className=\"px-3 py-2 font-medium\">{t('data_sync.integrationTab.columns.lastRun', 'Last run')}</th>\n <th className=\"px-3 py-2 font-medium\">{t('data_sync.integrationTab.columns.actions', 'Actions')}</th>\n </tr>\n </thead>\n <tbody>\n {rows.map((row) => {\n const scheduleState = schedules[row.key] ?? buildDefaultScheduleState(row.entityType)\n const isRunning = runningKey === row.key\n const isSaving = savingKey === row.key\n const isDeleting = deletingKey === row.key\n const controlsDisabled = isRunning || isSaving || isDeleting\n const valueError = valueErrors[row.key]\n return (\n <tr key={row.key} className=\"border-t align-top\">\n <td className=\"px-3 py-3 font-medium\">{formatEntityTypeLabel(row.entityType)}</td>\n <td className=\"px-3 py-3\">{t(`data_sync.dashboard.direction.${row.direction}`, row.direction === 'import' ? 'Import' : 'Export')}</td>\n <td className=\"px-3 py-3\">\n <Select\n value={scheduleState.scheduleType}\n onValueChange={(value) => updateScheduleEditor(row.key, {\n scheduleType: value === 'cron' ? 'cron' : 'interval',\n }, row.entityType)}\n disabled={controlsDisabled}\n >\n <SelectTrigger size=\"lg\" className=\"min-w-32\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value=\"interval\">{t('data_sync.dashboard.schedule.interval', 'Interval')}</SelectItem>\n <SelectItem value=\"cron\">{t('data_sync.dashboard.schedule.cron', 'Cron')}</SelectItem>\n </SelectContent>\n </Select>\n </td>\n <td className=\"px-3 py-3\">\n <Input\n value={scheduleState.scheduleValue}\n onChange={(event) => updateScheduleEditor(row.key, { scheduleValue: event.target.value }, row.entityType)}\n disabled={controlsDisabled}\n placeholder={scheduleState.scheduleType === 'cron' ? '0 * * * *' : '1h'}\n aria-invalid={valueError ? true : undefined}\n aria-describedby={valueError ? buildScheduleValueErrorId(row.key) : undefined}\n aria-label={scheduleState.scheduleType === 'cron'\n ? t('data_sync.dashboard.schedule.cronValue', 'Cron expression')\n : t('data_sync.dashboard.schedule.intervalValue', 'Interval')}\n />\n {valueError ? (\n <p id={buildScheduleValueErrorId(row.key)} className=\"mt-1 text-xs text-status-error-text\">\n {describeScheduleValueError(valueError, scheduleState.scheduleType)}\n </p>\n ) : null}\n </td>\n <td className=\"px-3 py-3\">\n <Input\n value={scheduleState.timezone}\n onChange={(event) => updateScheduleEditor(row.key, { timezone: event.target.value }, row.entityType)}\n disabled={controlsDisabled}\n />\n </td>\n <td className=\"px-3 py-3\">\n <label className=\"flex min-h-10 items-center gap-2 text-sm\">\n <Switch\n checked={scheduleState.fullSync}\n onCheckedChange={(checked) => updateScheduleEditor(row.key, { fullSync: checked }, row.entityType)}\n disabled={controlsDisabled}\n aria-label={t('data_sync.dashboard.start.fullSync', 'Run as full sync')}\n />\n <span>{t('data_sync.integrationTab.fullSyncShort', 'Full')}</span>\n </label>\n </td>\n <td className=\"px-3 py-3\">\n <label className=\"flex min-h-10 items-center gap-2 text-sm\">\n <Switch\n checked={scheduleState.isEnabled}\n onCheckedChange={(checked) => updateScheduleEditor(row.key, { isEnabled: checked }, row.entityType)}\n disabled={controlsDisabled}\n aria-label={t('data_sync.dashboard.schedule.enabled', 'Schedule enabled')}\n />\n <span>{scheduleState.isEnabled ? t('data_sync.dashboard.schedule.status.shortEnabled', 'Scheduled') : t('data_sync.dashboard.schedule.status.shortDisabled', 'Paused')}</span>\n </label>\n </td>\n <td className=\"px-3 py-3 text-muted-foreground\">\n {scheduleState.lastRunAt\n ? new Date(scheduleState.lastRunAt).toLocaleString()\n : scheduleState.id\n ? t('data_sync.dashboard.schedule.neverRun', 'Saved, but no scheduled execution has completed yet.')\n : t('data_sync.dashboard.schedule.none', 'No recurring schedule saved for this target yet.')}\n </td>\n <td className=\"px-3 py-3\">\n <div className=\"flex flex-wrap gap-2\">\n <Button\n type=\"button\"\n size=\"sm\"\n onClick={() => void handleStartSync(row.entityType, row.direction, row.key)}\n disabled={controlsDisabled || !props.isEnabled || !props.hasCredentials || option.canStartRun === false}\n >\n {isRunning ? <Spinner className=\"mr-2 h-4 w-4\" /> : <Play className=\"mr-2 h-4 w-4\" />}\n {isRunning\n ? t('data_sync.integrationTab.starting', 'Starting...')\n : t('data_sync.integrationTab.start', 'Run now')}\n </Button>\n <Button\n type=\"button\"\n size=\"sm\"\n variant=\"outline\"\n onClick={() => void handleSaveSchedule(row.entityType, row.direction, row.key)}\n disabled={controlsDisabled || option.canStartRun === false}\n >\n {isSaving ? <Spinner className=\"mr-2 h-4 w-4\" /> : <Save className=\"mr-2 h-4 w-4\" />}\n {isSaving\n ? t('data_sync.dashboard.schedule.saving', 'Saving...')\n : t('data_sync.dashboard.schedule.save', 'Save recurring schedule')}\n </Button>\n <Button\n type=\"button\"\n size=\"sm\"\n variant=\"outline\"\n onClick={() => void handleDeleteSchedule(row.entityType, row.key)}\n disabled={controlsDisabled || !scheduleState.id}\n >\n {isDeleting ? <Spinner className=\"mr-2 h-4 w-4\" /> : <Trash2 className=\"mr-2 h-4 w-4\" />}\n {isDeleting\n ? t('data_sync.dashboard.schedule.deleting', 'Removing...')\n : t('data_sync.dashboard.schedule.delete', 'Remove schedule')}\n </Button>\n </div>\n </td>\n </tr>\n )\n })}\n </tbody>\n </table>\n </div>\n )}\n\n <div className=\"grid gap-3 rounded-lg border border-dashed p-4 text-sm text-muted-foreground md:grid-cols-3\">\n <div className=\"space-y-1\">\n <Label>{t('data_sync.dashboard.schedule.interval', 'Interval')}</Label>\n <p>{t('data_sync.dashboard.schedule.intervalHelp', 'Example: `1h`, `6h`, or `24h` for repeating intervals.')}</p>\n </div>\n <div className=\"space-y-1\">\n <Label>{t('data_sync.dashboard.schedule.cron', 'Cron')}</Label>\n <p>{t('data_sync.dashboard.schedule.cronHelp', 'Example: `0 * * * *` runs at the start of every hour.')}</p>\n </div>\n <div className=\"space-y-1\">\n <Label>{t('data_sync.integrationTab.runNowTitle', 'Manual runs')}</Label>\n <p>{t('data_sync.integrationTab.runNowHelp', 'Run now uses the full-sync checkbox from the same row and starts progress tracking immediately in Data Sync.')}</p>\n </div>\n </div>\n </section>\n )\n}\n\nexport default IntegrationScheduleTab\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["supportedDirections"]
|
|
7
7
|
}
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
+
import { isValidScheduleInterval } from "@open-mercato/shared/lib/schedule/interval";
|
|
3
|
+
import { SCHEDULE_VALUE_FIELD, SCHEDULE_VALUE_FORMAT_MESSAGES } from "../lib/schedule-value.js";
|
|
2
4
|
const runSyncSchema = z.object({
|
|
3
5
|
integrationId: z.string().min(1),
|
|
4
6
|
entityType: z.string().min(1),
|
|
@@ -34,6 +36,15 @@ const listSyncSchedulesQuerySchema = z.object({
|
|
|
34
36
|
page: z.coerce.number().int().min(1).default(1),
|
|
35
37
|
pageSize: z.coerce.number().int().min(1).max(100).default(20)
|
|
36
38
|
});
|
|
39
|
+
function refineScheduleValueFormat(value, ctx) {
|
|
40
|
+
if (value.scheduleType !== "interval" || typeof value.scheduleValue !== "string") return;
|
|
41
|
+
if (isValidScheduleInterval(value.scheduleValue)) return;
|
|
42
|
+
ctx.addIssue({
|
|
43
|
+
code: "custom",
|
|
44
|
+
path: [SCHEDULE_VALUE_FIELD],
|
|
45
|
+
message: SCHEDULE_VALUE_FORMAT_MESSAGES.interval
|
|
46
|
+
});
|
|
47
|
+
}
|
|
37
48
|
const createSyncScheduleSchema = z.object({
|
|
38
49
|
integrationId: z.string().min(1),
|
|
39
50
|
entityType: z.string().min(1),
|
|
@@ -43,7 +54,7 @@ const createSyncScheduleSchema = z.object({
|
|
|
43
54
|
timezone: z.string().min(1).default("UTC"),
|
|
44
55
|
fullSync: z.boolean().default(false),
|
|
45
56
|
isEnabled: z.boolean().default(true)
|
|
46
|
-
});
|
|
57
|
+
}).superRefine(refineScheduleValueFormat);
|
|
47
58
|
const updateSyncScheduleSchema = z.object({
|
|
48
59
|
integrationId: z.string().min(1).optional(),
|
|
49
60
|
entityType: z.string().min(1).optional(),
|
|
@@ -55,7 +66,7 @@ const updateSyncScheduleSchema = z.object({
|
|
|
55
66
|
isEnabled: z.boolean().optional()
|
|
56
67
|
}).refine((value) => Object.keys(value).length > 0, {
|
|
57
68
|
message: "At least one field must be updated"
|
|
58
|
-
});
|
|
69
|
+
}).superRefine(refineScheduleValueFormat);
|
|
59
70
|
export {
|
|
60
71
|
createSyncScheduleSchema,
|
|
61
72
|
listSyncRunsQuerySchema,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/modules/data_sync/data/validators.ts"],
|
|
4
|
-
"sourcesContent": ["import { z } from 'zod'\n\nexport const runSyncSchema = z.object({\n integrationId: z.string().min(1),\n entityType: z.string().min(1),\n direction: z.enum(['import', 'export']),\n fullSync: z.boolean().default(false),\n batchSize: z.number().int().min(1).max(1000).default(100),\n triggeredBy: z.string().optional(),\n // Adapter-declared run parameters. Validated/coerced against the adapter's\n // `runParameters` declaration in the run route; here we only accept a record.\n parameters: z.record(z.string(), z.unknown()).optional(),\n})\n\nexport type RunSyncInput = z.infer<typeof runSyncSchema>\n\nexport const retrySyncSchema = z.object({\n fromBeginning: z.boolean().default(false),\n})\n\nexport type RetrySyncInput = z.infer<typeof retrySyncSchema>\n\nexport const validateConnectionSchema = z.object({\n integrationId: z.string().min(1),\n entityType: z.string().min(1),\n direction: z.enum(['import', 'export']),\n})\n\nexport const listSyncRunsQuerySchema = z.object({\n integrationId: z.string().optional(),\n entityType: z.string().optional(),\n direction: z.enum(['import', 'export']).optional(),\n status: z.enum(['pending', 'running', 'completed', 'failed', 'cancelled', 'paused']).optional(),\n search: z.string().trim().min(1).max(200).optional(),\n page: z.coerce.number().int().min(1).default(1),\n pageSize: z.coerce.number().int().min(1).max(100).default(20),\n})\n\nexport type ListSyncRunsQuery = z.infer<typeof listSyncRunsQuerySchema>\n\nexport const listSyncSchedulesQuerySchema = z.object({\n integrationId: z.string().optional(),\n entityType: z.string().optional(),\n direction: z.enum(['import', 'export']).optional(),\n page: z.coerce.number().int().min(1).default(1),\n pageSize: z.coerce.number().int().min(1).max(100).default(20),\n})\n\nexport const createSyncScheduleSchema = z.object({\n integrationId: z.string().min(1),\n entityType: z.string().min(1),\n direction: z.enum(['import', 'export']),\n scheduleType: z.enum(['cron', 'interval']),\n scheduleValue: z.string().min(1),\n timezone: z.string().min(1).default('UTC'),\n fullSync: z.boolean().default(false),\n isEnabled: z.boolean().default(true),\n})\n\nexport const updateSyncScheduleSchema = z.object({\n integrationId: z.string().min(1).optional(),\n entityType: z.string().min(1).optional(),\n direction: z.enum(['import', 'export']).optional(),\n scheduleType: z.enum(['cron', 'interval']).optional(),\n scheduleValue: z.string().min(1).optional(),\n timezone: z.string().min(1).optional(),\n fullSync: z.boolean().optional(),\n isEnabled: z.boolean().optional(),\n}).refine((value) => Object.keys(value).length > 0, {\n message: 'At least one field must be updated',\n})\n\nexport type CreateSyncScheduleInput = z.infer<typeof createSyncScheduleSchema>\nexport type UpdateSyncScheduleInput = z.infer<typeof updateSyncScheduleSchema>\n"],
|
|
5
|
-
"mappings": "AAAA,SAAS,SAAS;
|
|
4
|
+
"sourcesContent": ["import { z } from 'zod'\nimport { isValidScheduleInterval } from '@open-mercato/shared/lib/schedule/interval'\nimport { SCHEDULE_VALUE_FIELD, SCHEDULE_VALUE_FORMAT_MESSAGES } from '../lib/schedule-value'\n\nexport const runSyncSchema = z.object({\n integrationId: z.string().min(1),\n entityType: z.string().min(1),\n direction: z.enum(['import', 'export']),\n fullSync: z.boolean().default(false),\n batchSize: z.number().int().min(1).max(1000).default(100),\n triggeredBy: z.string().optional(),\n // Adapter-declared run parameters. Validated/coerced against the adapter's\n // `runParameters` declaration in the run route; here we only accept a record.\n parameters: z.record(z.string(), z.unknown()).optional(),\n})\n\nexport type RunSyncInput = z.infer<typeof runSyncSchema>\n\nexport const retrySyncSchema = z.object({\n fromBeginning: z.boolean().default(false),\n})\n\nexport type RetrySyncInput = z.infer<typeof retrySyncSchema>\n\nexport const validateConnectionSchema = z.object({\n integrationId: z.string().min(1),\n entityType: z.string().min(1),\n direction: z.enum(['import', 'export']),\n})\n\nexport const listSyncRunsQuerySchema = z.object({\n integrationId: z.string().optional(),\n entityType: z.string().optional(),\n direction: z.enum(['import', 'export']).optional(),\n status: z.enum(['pending', 'running', 'completed', 'failed', 'cancelled', 'paused']).optional(),\n search: z.string().trim().min(1).max(200).optional(),\n page: z.coerce.number().int().min(1).default(1),\n pageSize: z.coerce.number().int().min(1).max(100).default(20),\n})\n\nexport type ListSyncRunsQuery = z.infer<typeof listSyncRunsQuerySchema>\n\nexport const listSyncSchedulesQuerySchema = z.object({\n integrationId: z.string().optional(),\n entityType: z.string().optional(),\n direction: z.enum(['import', 'export']).optional(),\n page: z.coerce.number().int().min(1).default(1),\n pageSize: z.coerce.number().int().min(1).max(100).default(20),\n})\n\n/**\n * The documented interval format is part of the API contract, so a value the\n * scheduler can never run (`\"3600\"`) is rejected here instead of surfacing an\n * internal scheduler message from deep inside the write path. The value is\n * checked exactly as the scheduler will receive it \u2014 surrounding whitespace is\n * not tolerated here, because the scheduler's anchored parser would reject it\n * later. Cron is left to that parser, which reports back through the same\n * `scheduleValue` field error.\n */\nfunction refineScheduleValueFormat(\n value: { scheduleType?: 'cron' | 'interval'; scheduleValue?: string },\n ctx: z.RefinementCtx,\n): void {\n if (value.scheduleType !== 'interval' || typeof value.scheduleValue !== 'string') return\n if (isValidScheduleInterval(value.scheduleValue)) return\n ctx.addIssue({\n code: 'custom',\n path: [SCHEDULE_VALUE_FIELD],\n message: SCHEDULE_VALUE_FORMAT_MESSAGES.interval,\n })\n}\n\nexport const createSyncScheduleSchema = z.object({\n integrationId: z.string().min(1),\n entityType: z.string().min(1),\n direction: z.enum(['import', 'export']),\n scheduleType: z.enum(['cron', 'interval']),\n scheduleValue: z.string().min(1),\n timezone: z.string().min(1).default('UTC'),\n fullSync: z.boolean().default(false),\n isEnabled: z.boolean().default(true),\n}).superRefine(refineScheduleValueFormat)\n\nexport const updateSyncScheduleSchema = z.object({\n integrationId: z.string().min(1).optional(),\n entityType: z.string().min(1).optional(),\n direction: z.enum(['import', 'export']).optional(),\n scheduleType: z.enum(['cron', 'interval']).optional(),\n scheduleValue: z.string().min(1).optional(),\n timezone: z.string().min(1).optional(),\n fullSync: z.boolean().optional(),\n isEnabled: z.boolean().optional(),\n}).refine((value) => Object.keys(value).length > 0, {\n message: 'At least one field must be updated',\n}).superRefine(refineScheduleValueFormat)\n\nexport type CreateSyncScheduleInput = z.infer<typeof createSyncScheduleSchema>\nexport type UpdateSyncScheduleInput = z.infer<typeof updateSyncScheduleSchema>\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
const SCHEDULE_VALUE_FIELD = "scheduleValue";
|
|
2
|
+
const SCHEDULE_VALUE_FORMAT_MESSAGES = {
|
|
3
|
+
interval: "Interval must be a whole number followed by s, m, h or d (for example 15m, 1h or 24h) and cover at least one minute.",
|
|
4
|
+
cron: 'Cron expression could not be parsed. Use the five-field format, for example "0 * * * *".'
|
|
5
|
+
};
|
|
6
|
+
function buildScheduleValueErrorBody(scheduleType) {
|
|
7
|
+
return {
|
|
8
|
+
error: "Invalid payload",
|
|
9
|
+
details: {
|
|
10
|
+
formErrors: [],
|
|
11
|
+
fieldErrors: { [SCHEDULE_VALUE_FIELD]: [SCHEDULE_VALUE_FORMAT_MESSAGES[scheduleType]] }
|
|
12
|
+
}
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
function hasScheduleValueFieldError(payload) {
|
|
16
|
+
if (typeof payload !== "object" || payload === null) return false;
|
|
17
|
+
const details = payload.details;
|
|
18
|
+
if (typeof details !== "object" || details === null) return false;
|
|
19
|
+
const fieldErrors = details.fieldErrors;
|
|
20
|
+
if (typeof fieldErrors !== "object" || fieldErrors === null) return false;
|
|
21
|
+
const messages = fieldErrors[SCHEDULE_VALUE_FIELD];
|
|
22
|
+
return Array.isArray(messages) && messages.length > 0;
|
|
23
|
+
}
|
|
24
|
+
export {
|
|
25
|
+
SCHEDULE_VALUE_FIELD,
|
|
26
|
+
SCHEDULE_VALUE_FORMAT_MESSAGES,
|
|
27
|
+
buildScheduleValueErrorBody,
|
|
28
|
+
hasScheduleValueFieldError
|
|
29
|
+
};
|
|
30
|
+
//# sourceMappingURL=schedule-value.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../src/modules/data_sync/lib/schedule-value.ts"],
|
|
4
|
+
"sourcesContent": ["import type { ScheduleValueKind } from '@open-mercato/shared/lib/schedule/invalidScheduleValue'\n\nexport const SCHEDULE_VALUE_FIELD = 'scheduleValue'\n\nexport const SCHEDULE_VALUE_FORMAT_MESSAGES: Record<ScheduleValueKind, string> = {\n interval: 'Interval must be a whole number followed by s, m, h or d (for example 15m, 1h or 24h) and cover at least one minute.',\n cron: 'Cron expression could not be parsed. Use the five-field format, for example \"0 * * * *\".',\n}\n\nexport type ScheduleValueErrorBody = {\n error: string\n details: {\n formErrors: string[]\n fieldErrors: Record<string, string[]>\n }\n}\n\n/**\n * Mirrors zod's `flatten()` shape so a scheduler-reported format failure and a\n * schema-reported one reach the client as the same structured field error\n * instead of an internal scheduler message.\n */\nexport function buildScheduleValueErrorBody(scheduleType: ScheduleValueKind): ScheduleValueErrorBody {\n return {\n error: 'Invalid payload',\n details: {\n formErrors: [],\n fieldErrors: { [SCHEDULE_VALUE_FIELD]: [SCHEDULE_VALUE_FORMAT_MESSAGES[scheduleType]] },\n },\n }\n}\n\n/**\n * Lets a form render its own translated hint next to the field instead of\n * flashing the API's English message as a toast.\n */\nexport function hasScheduleValueFieldError(payload: unknown): boolean {\n if (typeof payload !== 'object' || payload === null) return false\n const details = (payload as { details?: unknown }).details\n if (typeof details !== 'object' || details === null) return false\n const fieldErrors = (details as { fieldErrors?: unknown }).fieldErrors\n if (typeof fieldErrors !== 'object' || fieldErrors === null) return false\n const messages = (fieldErrors as Record<string, unknown>)[SCHEDULE_VALUE_FIELD]\n return Array.isArray(messages) && messages.length > 0\n}\n"],
|
|
5
|
+
"mappings": "AAEO,MAAM,uBAAuB;AAE7B,MAAM,iCAAoE;AAAA,EAC/E,UAAU;AAAA,EACV,MAAM;AACR;AAeO,SAAS,4BAA4B,cAAyD;AACnG,SAAO;AAAA,IACL,OAAO;AAAA,IACP,SAAS;AAAA,MACP,YAAY,CAAC;AAAA,MACb,aAAa,EAAE,CAAC,oBAAoB,GAAG,CAAC,+BAA+B,YAAY,CAAC,EAAE;AAAA,IACxF;AAAA,EACF;AACF;AAMO,SAAS,2BAA2B,SAA2B;AACpE,MAAI,OAAO,YAAY,YAAY,YAAY,KAAM,QAAO;AAC5D,QAAM,UAAW,QAAkC;AACnD,MAAI,OAAO,YAAY,YAAY,YAAY,KAAM,QAAO;AAC5D,QAAM,cAAe,QAAsC;AAC3D,MAAI,OAAO,gBAAgB,YAAY,gBAAgB,KAAM,QAAO;AACpE,QAAM,WAAY,YAAwC,oBAAoB;AAC9E,SAAO,MAAM,QAAQ,QAAQ,KAAK,SAAS,SAAS;AACtD;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/modules/eudr/data/validators.ts"],
|
|
4
|
-
"sourcesContent": ["import { z } from 'zod'\n\nimport { EUDR_RISK_CRITERIA_KEYS } from '../lib/reference-data'\n\nexport const EUDR_COMMODITIES = ['cattle', 'cocoa', 'coffee', 'oil_palm', 'rubber', 'soya', 'wood'] as const\nexport type EudrCommodity = (typeof EUDR_COMMODITIES)[number]\n\nexport const EUDR_SUBMISSION_STATUSES = ['draft', 'submitted', 'verified', 'rejected'] as const\nexport type EudrSubmissionStatus = (typeof EUDR_SUBMISSION_STATUSES)[number]\n\nexport const EUDR_STATEMENT_STATUSES = ['draft', 'submitted', 'available', 'withdrawn', 'archived'] as const\nexport type EudrStatementStatus = (typeof EUDR_STATEMENT_STATUSES)[number]\n\nexport const EUDR_PLOT_TYPES = ['point', 'polygon'] as const\nexport type EudrPlotType = (typeof EUDR_PLOT_TYPES)[number]\n\nexport const EUDR_RISK_TIERS = ['low', 'standard', 'high', 'mixed', 'unknown'] as const\nexport type EudrRiskTier = (typeof EUDR_RISK_TIERS)[number]\n\nexport const EUDR_RISK_CONCLUSIONS = ['negligible', 'non_negligible'] as const\nexport type EudrRiskConclusion = (typeof EUDR_RISK_CONCLUSIONS)[number]\n\nexport const EUDR_CRITERIA_ANSWERS = ['no_concern', 'concern', 'not_applicable'] as const\nexport type EudrCriteriaAnswer = (typeof EUDR_CRITERIA_ANSWERS)[number]\n\nexport const EUDR_MITIGATION_TYPES = [\n 'request_documents',\n 'supplier_audit',\n 'satellite_verification',\n 'certification_check',\n 'switch_sourcing',\n 'other',\n] as const\nexport type EudrMitigationType = (typeof EUDR_MITIGATION_TYPES)[number]\n\nexport const EUDR_MITIGATION_STATUSES = ['planned', 'in_progress', 'completed', 'cancelled'] as const\nexport type EudrMitigationStatus = (typeof EUDR_MITIGATION_STATUSES)[number]\n\nexport const EUDR_ACTIVITY_TYPES = ['import', 'export', 'domestic_production', 'trade'] as const\nexport type EudrActivityType = (typeof EUDR_ACTIVITY_TYPES)[number]\n\nexport const EUDR_ACTOR_ROLES = ['operator', 'non_sme_trader', 'sme_trader'] as const\nexport type EudrActorRole = (typeof EUDR_ACTOR_ROLES)[number]\n\nexport const GEOJSON_TYPES = ['Feature', 'FeatureCollection', 'Point', 'Polygon', 'MultiPolygon'] as const\n\nconst uuid = () => z.string().uuid()\nconst geoJsonSizeLimit = 1_048_576\n// Two conventions for server-managed fields on these entities: fields listed below\n// are never advertised as create inputs, so a client sending a real value is rejected\n// (`rejectServerComputedFields` tolerates a null/undefined no-op echo). A field that\n// WAS advertised in the create schema \u2014 statements' `referenceIssuedAt` \u2014 is instead\n// dropped from the create schema, so it is stripped rather than rejected (#5508).\nconst serverComputedSubmissionFields = ['completenessScore', 'missingFields'] as const\nconst serverComputedPlotFields = ['validationWarnings', 'computedArea'] as const\nconst serverComputedRiskAssessmentFields = ['countryRisks', 'overallTier', 'isSimplified', 'assessedByName'] as const\nconst serverComputedMitigationActionFields = ['completedAt'] as const\nconst serverComputedStatementFields = ['submittedAt'] as const\nconst riskCriteriaKeySet = new Set(EUDR_RISK_CRITERIA_KEYS)\n\nconst productSnapshotSchema = z.object({\n name: z.string().max(500).optional().nullable(),\n sku: z.string().max(255).optional().nullable(),\n})\nconst supplierSnapshotSchema = z.object({\n displayName: z.string().max(500).optional().nullable(),\n})\nconst orderSnapshotSchema = z.object({\n orderNumber: z.string().max(255).optional().nullable(),\n})\n\n// A whole-object POST echoes server-computed fields back with their no-op value\n// (a fresh draft's `submittedAt` is null), so tolerate a null/undefined echo and\n// reject only a meaningful attempt to set server-owned state (#5508).\nfunction rejectServerComputedFields(fields: readonly string[]): z.ZodType<unknown> {\n return z.unknown().superRefine((input, context) => {\n if (input === null || typeof input !== 'object' || Array.isArray(input)) return\n const record = input as Record<string, unknown>\n for (const field of fields) {\n if (!(field in record)) continue\n if (record[field] === null || record[field] === undefined) continue\n context.addIssue({\n code: z.ZodIssueCode.custom,\n path: [field],\n message: 'eudr.errors.serverComputedField',\n })\n }\n })\n}\n\nfunction requiredUnknown(message: string): z.ZodType<unknown> {\n return z.unknown().refine((value) => value !== undefined, { message })\n}\n\nfunction isIsoDate(value: string): boolean {\n const match = /^(\\d{4})-(\\d{2})-(\\d{2})$/.exec(value)\n if (match === null) return false\n const year = Number(match[1])\n const month = Number(match[2])\n const day = Number(match[3])\n const date = new Date(Date.UTC(year, month - 1, day))\n return date.getUTCFullYear() === year && date.getUTCMonth() === month - 1 && date.getUTCDate() === day\n}\n\n// Route mapInput parses these schemas first (string -> Date) and commands parse\n// the mapped input again, so both schemas must also accept Date instances.\nconst isoDateSchema = () => z.union([\n z.date(),\n z\n .string()\n .refine(isIsoDate, { message: 'eudr.errors.invalidDate' })\n .transform((value) => new Date(`${value}T00:00:00.000Z`)),\n])\n\nconst isoDateTimeSchema = () => z.union([\n z.date(),\n z\n .string()\n .datetime({ message: 'eudr.errors.invalidDateTime' })\n .transform((value) => new Date(value)),\n])\n\nconst pastOrNowIsoDateTimeSchema = () => isoDateTimeSchema().refine((value) => value.getTime() <= Date.now(), {\n message: 'eudr.errors.assessedAtInFuture',\n})\n\nconst isoDateOrDateTimeSchema = () => z.union([isoDateSchema(), isoDateTimeSchema()])\n\n// Country codes are validated through ICU rather than the shared country helper.\n// That helper imports language-subtag-registry's JSON, and the build strips the\n// import attribute Node's ESM loader requires, so importing it from server-side\n// code (CLI, workers) fails with ERR_IMPORT_ATTRIBUTE_MISSING. UI components can\n// keep using the helper because bundlers resolve the JSON themselves.\nconst countryDisplayNames = typeof Intl !== 'undefined' && typeof Intl.DisplayNames !== 'undefined'\n ? new Intl.DisplayNames(['en'], { type: 'region' })\n : null\n\nfunction isIsoCountryCode(value: string): boolean {\n // Without ICU data there is nothing to check against, so accept the shape.\n if (!countryDisplayNames) return true\n try {\n // Intl echoes the input back when it cannot resolve the region.\n const label = countryDisplayNames.of(value)\n return typeof label === 'string' && label !== value\n } catch {\n return false\n }\n}\n\nconst countryCodeSchema = () => z\n .string()\n .regex(/^[A-Za-z]{2}$/)\n .transform((value) => value.toUpperCase())\n .refine(isIsoCountryCode, { message: 'eudr.errors.invalidCountry' })\n\nconst referencedStatementCodeSchema = (maxLength: number) => z\n .string()\n .trim()\n .min(1)\n .max(maxLength)\n .regex(/^[A-Za-z0-9._/-]+$/, { message: 'eudr.errors.invalidReferenceIdentifier' })\n .transform((value) => value.toUpperCase())\n\nexport const referencedStatementSchema = z.object({\n referenceNumber: referencedStatementCodeSchema(32),\n verificationNumber: referencedStatementCodeSchema(16).optional(),\n})\n\nexport const geoJsonSchema = z\n .object({\n type: z.enum(GEOJSON_TYPES),\n })\n .passthrough()\n .superRefine((value, context) => {\n try {\n const serialized = JSON.stringify(value)\n if (serialized.length <= geoJsonSizeLimit) return\n } catch {\n context.addIssue({\n code: z.ZodIssueCode.custom,\n message: 'eudr.errors.geolocationTooLarge',\n })\n return\n }\n context.addIssue({\n code: z.ZodIssueCode.custom,\n message: 'eudr.errors.geolocationTooLarge',\n })\n })\n\nexport const productMappingCreateSchema = z.object({\n productId: uuid(),\n productSnapshot: productSnapshotSchema.optional().nullable(),\n commodity: z.enum(EUDR_COMMODITIES),\n hsCode: z.string().max(20).optional().nullable(),\n speciesScientificName: z.string().trim().max(256).optional().nullable(),\n speciesCommonName: z.string().trim().max(256).optional().nullable(),\n isInScope: z.boolean().optional(),\n notes: z.string().max(5000).optional().nullable(),\n})\n\nexport const productMappingUpdateSchema = z\n .object({\n id: uuid(),\n })\n .merge(productMappingCreateSchema.partial())\n\nconst plotBaseSchema = z.object({\n supplierEntityId: uuid(),\n supplierSnapshot: supplierSnapshotSchema.optional().nullable(),\n name: z.string().min(1).max(200),\n externalId: z.string().max(100).optional().nullable(),\n description: z.string().max(2000).optional().nullable(),\n originCountry: countryCodeSchema(),\n geometry: requiredUnknown('eudr.errors.geometryRequired'),\n areaHa: z.coerce.number().positive().max(100_000).optional().nullable(),\n producerName: z.string().max(500).optional().nullable(),\n isActive: z.boolean().optional(),\n})\n\nexport const plotCreateSchema = rejectServerComputedFields(serverComputedPlotFields).pipe(plotBaseSchema)\n\nexport const plotUpdateSchema = rejectServerComputedFields(serverComputedPlotFields).pipe(\n z\n .object({\n id: uuid(),\n })\n .merge(plotBaseSchema.partial()),\n)\n\nconst evidenceSubmissionBaseSchema = z.object({\n supplierEntityId: uuid(),\n supplierSnapshot: supplierSnapshotSchema.optional().nullable(),\n commodity: z.enum(EUDR_COMMODITIES),\n productMappingId: uuid().optional().nullable(),\n statementId: uuid().optional().nullable(),\n originCountry: countryCodeSchema().optional().nullable(),\n geolocation: geoJsonSchema.optional().nullable(),\n quantityKg: z.coerce.number().positive().optional().nullable(),\n batchNumber: z.string().max(255).optional().nullable(),\n harvestFrom: z.coerce.date().optional().nullable(),\n harvestTo: z.coerce.date().optional().nullable(),\n producerName: z.string().max(500).optional().nullable(),\n attachmentIds: z.array(uuid()).max(100).optional(),\n plotIds: z.array(uuid()).max(200).optional(),\n status: z.enum(EUDR_SUBMISSION_STATUSES).optional(),\n notes: z.string().max(5000).optional().nullable(),\n})\n\nfunction validateHarvestRange(input: { harvestFrom?: Date | null; harvestTo?: Date | null }, context: z.RefinementCtx): void {\n if (!input.harvestFrom || !input.harvestTo || input.harvestFrom <= input.harvestTo) return\n context.addIssue({\n code: z.ZodIssueCode.custom,\n path: ['harvestTo'],\n message: 'eudr.errors.harvestRange',\n })\n}\n\nexport const evidenceSubmissionCreateSchema = rejectServerComputedFields(serverComputedSubmissionFields).pipe(\n evidenceSubmissionBaseSchema.superRefine(validateHarvestRange),\n)\n\nexport const evidenceSubmissionUpdateSchema = rejectServerComputedFields(serverComputedSubmissionFields).pipe(\n z\n .object({\n id: uuid(),\n })\n .merge(evidenceSubmissionBaseSchema.partial())\n .superRefine(validateHarvestRange),\n)\n\nconst riskCriteriaEntrySchema = z.object({\n answer: z.enum(EUDR_CRITERIA_ANSWERS),\n note: z.string().max(2000).optional().nullable(),\n})\n\nconst riskCriteriaSchema = z.record(z.string(), riskCriteriaEntrySchema).superRefine((criteria, context) => {\n for (const key of Object.keys(criteria)) {\n if (riskCriteriaKeySet.has(key)) continue\n context.addIssue({\n code: z.ZodIssueCode.custom,\n path: [key],\n message: 'eudr.errors.invalidRiskCriterion',\n })\n }\n})\n\nconst riskAssessmentBaseSchema = z.object({\n statementId: uuid(),\n criteria: riskCriteriaSchema,\n conclusion: z.enum(EUDR_RISK_CONCLUSIONS),\n reviewDueAt: isoDateOrDateTimeSchema().optional().nullable(),\n assessedAt: pastOrNowIsoDateTimeSchema().optional(),\n notes: z.string().max(4000).optional().nullable(),\n})\n\nexport const riskAssessmentCreateSchema = rejectServerComputedFields(serverComputedRiskAssessmentFields).pipe(riskAssessmentBaseSchema)\n\nexport const riskAssessmentUpdateSchema = rejectServerComputedFields(serverComputedRiskAssessmentFields).pipe(\n z\n .object({\n id: uuid(),\n })\n .merge(riskAssessmentBaseSchema.partial()),\n)\n\nconst mitigationActionBaseSchema = z.object({\n riskAssessmentId: uuid(),\n actionType: z.enum(EUDR_MITIGATION_TYPES).optional(),\n title: z.string().min(1).max(200),\n description: z.string().max(2000).optional().nullable(),\n status: z.enum(EUDR_MITIGATION_STATUSES).optional(),\n dueDate: isoDateSchema().optional().nullable(),\n notes: z.string().max(2000).optional().nullable(),\n})\n\nexport const mitigationActionCreateSchema = rejectServerComputedFields(serverComputedMitigationActionFields).pipe(mitigationActionBaseSchema)\n\nexport const mitigationActionUpdateSchema = rejectServerComputedFields(serverComputedMitigationActionFields).pipe(\n z\n .object({\n id: uuid(),\n })\n .merge(mitigationActionBaseSchema.partial()),\n)\n\nconst statementBaseSchema = z.object({\n title: z.string().min(1).max(500),\n commodity: z.enum(EUDR_COMMODITIES),\n referenceNumber: z.string().max(255).optional().nullable(),\n verificationNumber: z.string().max(255).optional().nullable(),\n status: z.enum(EUDR_STATEMENT_STATUSES).optional(),\n activityType: z.enum(EUDR_ACTIVITY_TYPES).optional().nullable(),\n actorRole: z.enum(EUDR_ACTOR_ROLES).optional().nullable(),\n referencedStatements: z.array(referencedStatementSchema).max(100).optional(),\n quantityKg: z.coerce.number().positive().optional().nullable(),\n supplementaryUnit: z.string().max(16).optional().nullable(),\n supplementaryQuantity: z.coerce.number().positive().optional().nullable(),\n orderId: uuid().optional().nullable(),\n referenceIssuedAt: isoDateTimeSchema().optional().nullable(),\n orderSnapshot: orderSnapshotSchema.optional().nullable(),\n notes: z.string().max(5000).optional().nullable(),\n})\n\n// referenceIssuedAt is server-managed (only set at the submitted->available\n// transition) and is never a create input, so it is dropped from the create\n// schema. A whole-object POST that echoes it (null or a value) is accepted and\n// the field ignored, instead of a self-contradictory 400 (#5508).\nexport const statementCreateSchema = rejectServerComputedFields(serverComputedStatementFields).pipe(\n statementBaseSchema.omit({ referenceIssuedAt: true }),\n)\n\nexport const statementUpdateSchema = rejectServerComputedFields(serverComputedStatementFields).pipe(\n z\n .object({\n id: uuid(),\n })\n .merge(statementBaseSchema.partial()),\n)\n\nexport type ProductMappingCreateInput = z.infer<typeof productMappingCreateSchema>\nexport type ProductMappingUpdateInput = z.infer<typeof productMappingUpdateSchema>\nexport type PlotCreateInput = z.infer<typeof plotCreateSchema>\nexport type PlotUpdateInput = z.infer<typeof plotUpdateSchema>\nexport type EvidenceSubmissionCreateInput = z.infer<typeof evidenceSubmissionCreateSchema>\nexport type EvidenceSubmissionUpdateInput = z.infer<typeof evidenceSubmissionUpdateSchema>\nexport type RiskAssessmentCreateInput = z.infer<typeof riskAssessmentCreateSchema>\nexport type RiskAssessmentUpdateInput = z.infer<typeof riskAssessmentUpdateSchema>\nexport type MitigationActionCreateInput = z.infer<typeof mitigationActionCreateSchema>\nexport type MitigationActionUpdateInput = z.infer<typeof mitigationActionUpdateSchema>\nexport type StatementCreateInput = z.infer<typeof statementCreateSchema>\nexport type StatementUpdateInput = z.infer<typeof statementUpdateSchema>\n"],
|
|
5
|
-
"mappings": "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
|
|
4
|
+
"sourcesContent": ["import { z } from 'zod'\n\nimport { EUDR_RISK_CRITERIA_KEYS } from '../lib/reference-data'\n\nexport const EUDR_COMMODITIES = ['cattle', 'cocoa', 'coffee', 'oil_palm', 'rubber', 'soya', 'wood'] as const\nexport type EudrCommodity = (typeof EUDR_COMMODITIES)[number]\n\nexport const EUDR_SUBMISSION_STATUSES = ['draft', 'submitted', 'verified', 'rejected'] as const\nexport type EudrSubmissionStatus = (typeof EUDR_SUBMISSION_STATUSES)[number]\n\nexport const EUDR_STATEMENT_STATUSES = ['draft', 'submitted', 'available', 'withdrawn', 'archived'] as const\nexport type EudrStatementStatus = (typeof EUDR_STATEMENT_STATUSES)[number]\n\nexport const EUDR_PLOT_TYPES = ['point', 'polygon'] as const\nexport type EudrPlotType = (typeof EUDR_PLOT_TYPES)[number]\n\nexport const EUDR_RISK_TIERS = ['low', 'standard', 'high', 'mixed', 'unknown'] as const\nexport type EudrRiskTier = (typeof EUDR_RISK_TIERS)[number]\n\nexport const EUDR_RISK_CONCLUSIONS = ['negligible', 'non_negligible'] as const\nexport type EudrRiskConclusion = (typeof EUDR_RISK_CONCLUSIONS)[number]\n\nexport const EUDR_CRITERIA_ANSWERS = ['no_concern', 'concern', 'not_applicable'] as const\nexport type EudrCriteriaAnswer = (typeof EUDR_CRITERIA_ANSWERS)[number]\n\nexport const EUDR_MITIGATION_TYPES = [\n 'request_documents',\n 'supplier_audit',\n 'satellite_verification',\n 'certification_check',\n 'switch_sourcing',\n 'other',\n] as const\nexport type EudrMitigationType = (typeof EUDR_MITIGATION_TYPES)[number]\n\nexport const EUDR_MITIGATION_STATUSES = ['planned', 'in_progress', 'completed', 'cancelled'] as const\nexport type EudrMitigationStatus = (typeof EUDR_MITIGATION_STATUSES)[number]\n\nexport const EUDR_ACTIVITY_TYPES = ['import', 'export', 'domestic_production', 'trade'] as const\nexport type EudrActivityType = (typeof EUDR_ACTIVITY_TYPES)[number]\n\nexport const EUDR_ACTOR_ROLES = ['operator', 'non_sme_trader', 'sme_trader'] as const\nexport type EudrActorRole = (typeof EUDR_ACTOR_ROLES)[number]\n\nexport const GEOJSON_TYPES = ['Feature', 'FeatureCollection', 'Point', 'Polygon', 'MultiPolygon'] as const\n\nconst uuid = () => z.string().uuid()\nconst geoJsonSizeLimit = 1_048_576\n// Two conventions for server-managed fields on these entities: fields listed below\n// are never advertised as create inputs, so a client sending a real value is rejected\n// (`rejectServerComputedFields` tolerates a null/undefined no-op echo). A field that\n// WAS advertised in the create schema \u2014 statements' `referenceIssuedAt` \u2014 is instead\n// dropped from the create schema, so it is stripped rather than rejected (#5508).\nconst serverComputedSubmissionFields = ['completenessScore', 'missingFields'] as const\nconst serverComputedPlotFields = ['validationWarnings', 'computedArea'] as const\nconst serverComputedRiskAssessmentFields = ['countryRisks', 'overallTier', 'isSimplified', 'assessedByName'] as const\nconst serverComputedMitigationActionFields = ['completedAt'] as const\nconst serverComputedStatementFields = ['submittedAt'] as const\nconst riskCriteriaKeySet = new Set(EUDR_RISK_CRITERIA_KEYS)\n\nconst productSnapshotSchema = z.object({\n name: z.string().max(500).optional().nullable(),\n sku: z.string().max(255).optional().nullable(),\n})\nconst supplierSnapshotSchema = z.object({\n displayName: z.string().max(500).optional().nullable(),\n})\nconst orderSnapshotSchema = z.object({\n orderNumber: z.string().max(255).optional().nullable(),\n})\n\n// A whole-object POST echoes server-computed fields back with their no-op value\n// (a fresh draft's `submittedAt` is null), so tolerate a null/undefined echo and\n// reject only a meaningful attempt to set server-owned state (#5508).\nfunction rejectServerComputedFields(fields: readonly string[]): z.ZodType<unknown> {\n return z.unknown().superRefine((input, context) => {\n if (input === null || typeof input !== 'object' || Array.isArray(input)) return\n const record = input as Record<string, unknown>\n for (const field of fields) {\n if (!(field in record)) continue\n if (record[field] === null || record[field] === undefined) continue\n context.addIssue({\n code: z.ZodIssueCode.custom,\n path: [field],\n message: 'eudr.errors.serverComputedField',\n })\n }\n })\n}\n\nfunction requiredUnknown(message: string): z.ZodType<unknown> {\n return z.unknown().refine((value) => value !== undefined, { message })\n}\n\nfunction isIsoDate(value: string): boolean {\n const match = /^(\\d{4})-(\\d{2})-(\\d{2})$/.exec(value)\n if (match === null) return false\n const year = Number(match[1])\n const month = Number(match[2])\n const day = Number(match[3])\n const date = new Date(Date.UTC(year, month - 1, day))\n return date.getUTCFullYear() === year && date.getUTCMonth() === month - 1 && date.getUTCDate() === day\n}\n\n// Route mapInput parses these schemas first (string -> Date) and commands parse\n// the mapped input again, so both schemas must also accept Date instances.\nconst isoDateSchema = () => z.union([\n z.date(),\n z\n .string()\n .refine(isIsoDate, { message: 'eudr.errors.invalidDate' })\n .transform((value) => new Date(`${value}T00:00:00.000Z`)),\n])\n\nconst isoDateTimeSchema = () => z.union([\n z.date(),\n z\n .string()\n .datetime({ message: 'eudr.errors.invalidDateTime' })\n .transform((value) => new Date(value)),\n])\n\nconst pastOrNowIsoDateTimeSchema = () => isoDateTimeSchema().refine((value) => value.getTime() <= Date.now(), {\n message: 'eudr.errors.assessedAtInFuture',\n})\n\nconst isoDateOrDateTimeSchema = () => z.union([isoDateSchema(), isoDateTimeSchema()])\n\n// Country codes are validated through ICU rather than the shared country helper.\n// ICU keeps this schema self-contained (no dependency on the generated country\n// list) and accepts any region code Node's DisplayNames can resolve, including\n// codes the shared helper supplements separately (e.g. XK).\nconst countryDisplayNames = typeof Intl !== 'undefined' && typeof Intl.DisplayNames !== 'undefined'\n ? new Intl.DisplayNames(['en'], { type: 'region' })\n : null\n\nfunction isIsoCountryCode(value: string): boolean {\n // Without ICU data there is nothing to check against, so accept the shape.\n if (!countryDisplayNames) return true\n try {\n // Intl echoes the input back when it cannot resolve the region.\n const label = countryDisplayNames.of(value)\n return typeof label === 'string' && label !== value\n } catch {\n return false\n }\n}\n\nconst countryCodeSchema = () => z\n .string()\n .regex(/^[A-Za-z]{2}$/)\n .transform((value) => value.toUpperCase())\n .refine(isIsoCountryCode, { message: 'eudr.errors.invalidCountry' })\n\nconst referencedStatementCodeSchema = (maxLength: number) => z\n .string()\n .trim()\n .min(1)\n .max(maxLength)\n .regex(/^[A-Za-z0-9._/-]+$/, { message: 'eudr.errors.invalidReferenceIdentifier' })\n .transform((value) => value.toUpperCase())\n\nexport const referencedStatementSchema = z.object({\n referenceNumber: referencedStatementCodeSchema(32),\n verificationNumber: referencedStatementCodeSchema(16).optional(),\n})\n\nexport const geoJsonSchema = z\n .object({\n type: z.enum(GEOJSON_TYPES),\n })\n .passthrough()\n .superRefine((value, context) => {\n try {\n const serialized = JSON.stringify(value)\n if (serialized.length <= geoJsonSizeLimit) return\n } catch {\n context.addIssue({\n code: z.ZodIssueCode.custom,\n message: 'eudr.errors.geolocationTooLarge',\n })\n return\n }\n context.addIssue({\n code: z.ZodIssueCode.custom,\n message: 'eudr.errors.geolocationTooLarge',\n })\n })\n\nexport const productMappingCreateSchema = z.object({\n productId: uuid(),\n productSnapshot: productSnapshotSchema.optional().nullable(),\n commodity: z.enum(EUDR_COMMODITIES),\n hsCode: z.string().max(20).optional().nullable(),\n speciesScientificName: z.string().trim().max(256).optional().nullable(),\n speciesCommonName: z.string().trim().max(256).optional().nullable(),\n isInScope: z.boolean().optional(),\n notes: z.string().max(5000).optional().nullable(),\n})\n\nexport const productMappingUpdateSchema = z\n .object({\n id: uuid(),\n })\n .merge(productMappingCreateSchema.partial())\n\nconst plotBaseSchema = z.object({\n supplierEntityId: uuid(),\n supplierSnapshot: supplierSnapshotSchema.optional().nullable(),\n name: z.string().min(1).max(200),\n externalId: z.string().max(100).optional().nullable(),\n description: z.string().max(2000).optional().nullable(),\n originCountry: countryCodeSchema(),\n geometry: requiredUnknown('eudr.errors.geometryRequired'),\n areaHa: z.coerce.number().positive().max(100_000).optional().nullable(),\n producerName: z.string().max(500).optional().nullable(),\n isActive: z.boolean().optional(),\n})\n\nexport const plotCreateSchema = rejectServerComputedFields(serverComputedPlotFields).pipe(plotBaseSchema)\n\nexport const plotUpdateSchema = rejectServerComputedFields(serverComputedPlotFields).pipe(\n z\n .object({\n id: uuid(),\n })\n .merge(plotBaseSchema.partial()),\n)\n\nconst evidenceSubmissionBaseSchema = z.object({\n supplierEntityId: uuid(),\n supplierSnapshot: supplierSnapshotSchema.optional().nullable(),\n commodity: z.enum(EUDR_COMMODITIES),\n productMappingId: uuid().optional().nullable(),\n statementId: uuid().optional().nullable(),\n originCountry: countryCodeSchema().optional().nullable(),\n geolocation: geoJsonSchema.optional().nullable(),\n quantityKg: z.coerce.number().positive().optional().nullable(),\n batchNumber: z.string().max(255).optional().nullable(),\n harvestFrom: z.coerce.date().optional().nullable(),\n harvestTo: z.coerce.date().optional().nullable(),\n producerName: z.string().max(500).optional().nullable(),\n attachmentIds: z.array(uuid()).max(100).optional(),\n plotIds: z.array(uuid()).max(200).optional(),\n status: z.enum(EUDR_SUBMISSION_STATUSES).optional(),\n notes: z.string().max(5000).optional().nullable(),\n})\n\nfunction validateHarvestRange(input: { harvestFrom?: Date | null; harvestTo?: Date | null }, context: z.RefinementCtx): void {\n if (!input.harvestFrom || !input.harvestTo || input.harvestFrom <= input.harvestTo) return\n context.addIssue({\n code: z.ZodIssueCode.custom,\n path: ['harvestTo'],\n message: 'eudr.errors.harvestRange',\n })\n}\n\nexport const evidenceSubmissionCreateSchema = rejectServerComputedFields(serverComputedSubmissionFields).pipe(\n evidenceSubmissionBaseSchema.superRefine(validateHarvestRange),\n)\n\nexport const evidenceSubmissionUpdateSchema = rejectServerComputedFields(serverComputedSubmissionFields).pipe(\n z\n .object({\n id: uuid(),\n })\n .merge(evidenceSubmissionBaseSchema.partial())\n .superRefine(validateHarvestRange),\n)\n\nconst riskCriteriaEntrySchema = z.object({\n answer: z.enum(EUDR_CRITERIA_ANSWERS),\n note: z.string().max(2000).optional().nullable(),\n})\n\nconst riskCriteriaSchema = z.record(z.string(), riskCriteriaEntrySchema).superRefine((criteria, context) => {\n for (const key of Object.keys(criteria)) {\n if (riskCriteriaKeySet.has(key)) continue\n context.addIssue({\n code: z.ZodIssueCode.custom,\n path: [key],\n message: 'eudr.errors.invalidRiskCriterion',\n })\n }\n})\n\nconst riskAssessmentBaseSchema = z.object({\n statementId: uuid(),\n criteria: riskCriteriaSchema,\n conclusion: z.enum(EUDR_RISK_CONCLUSIONS),\n reviewDueAt: isoDateOrDateTimeSchema().optional().nullable(),\n assessedAt: pastOrNowIsoDateTimeSchema().optional(),\n notes: z.string().max(4000).optional().nullable(),\n})\n\nexport const riskAssessmentCreateSchema = rejectServerComputedFields(serverComputedRiskAssessmentFields).pipe(riskAssessmentBaseSchema)\n\nexport const riskAssessmentUpdateSchema = rejectServerComputedFields(serverComputedRiskAssessmentFields).pipe(\n z\n .object({\n id: uuid(),\n })\n .merge(riskAssessmentBaseSchema.partial()),\n)\n\nconst mitigationActionBaseSchema = z.object({\n riskAssessmentId: uuid(),\n actionType: z.enum(EUDR_MITIGATION_TYPES).optional(),\n title: z.string().min(1).max(200),\n description: z.string().max(2000).optional().nullable(),\n status: z.enum(EUDR_MITIGATION_STATUSES).optional(),\n dueDate: isoDateSchema().optional().nullable(),\n notes: z.string().max(2000).optional().nullable(),\n})\n\nexport const mitigationActionCreateSchema = rejectServerComputedFields(serverComputedMitigationActionFields).pipe(mitigationActionBaseSchema)\n\nexport const mitigationActionUpdateSchema = rejectServerComputedFields(serverComputedMitigationActionFields).pipe(\n z\n .object({\n id: uuid(),\n })\n .merge(mitigationActionBaseSchema.partial()),\n)\n\nconst statementBaseSchema = z.object({\n title: z.string().min(1).max(500),\n commodity: z.enum(EUDR_COMMODITIES),\n referenceNumber: z.string().max(255).optional().nullable(),\n verificationNumber: z.string().max(255).optional().nullable(),\n status: z.enum(EUDR_STATEMENT_STATUSES).optional(),\n activityType: z.enum(EUDR_ACTIVITY_TYPES).optional().nullable(),\n actorRole: z.enum(EUDR_ACTOR_ROLES).optional().nullable(),\n referencedStatements: z.array(referencedStatementSchema).max(100).optional(),\n quantityKg: z.coerce.number().positive().optional().nullable(),\n supplementaryUnit: z.string().max(16).optional().nullable(),\n supplementaryQuantity: z.coerce.number().positive().optional().nullable(),\n orderId: uuid().optional().nullable(),\n referenceIssuedAt: isoDateTimeSchema().optional().nullable(),\n orderSnapshot: orderSnapshotSchema.optional().nullable(),\n notes: z.string().max(5000).optional().nullable(),\n})\n\n// referenceIssuedAt is server-managed (only set at the submitted->available\n// transition) and is never a create input, so it is dropped from the create\n// schema. A whole-object POST that echoes it (null or a value) is accepted and\n// the field ignored, instead of a self-contradictory 400 (#5508).\nexport const statementCreateSchema = rejectServerComputedFields(serverComputedStatementFields).pipe(\n statementBaseSchema.omit({ referenceIssuedAt: true }),\n)\n\nexport const statementUpdateSchema = rejectServerComputedFields(serverComputedStatementFields).pipe(\n z\n .object({\n id: uuid(),\n })\n .merge(statementBaseSchema.partial()),\n)\n\nexport type ProductMappingCreateInput = z.infer<typeof productMappingCreateSchema>\nexport type ProductMappingUpdateInput = z.infer<typeof productMappingUpdateSchema>\nexport type PlotCreateInput = z.infer<typeof plotCreateSchema>\nexport type PlotUpdateInput = z.infer<typeof plotUpdateSchema>\nexport type EvidenceSubmissionCreateInput = z.infer<typeof evidenceSubmissionCreateSchema>\nexport type EvidenceSubmissionUpdateInput = z.infer<typeof evidenceSubmissionUpdateSchema>\nexport type RiskAssessmentCreateInput = z.infer<typeof riskAssessmentCreateSchema>\nexport type RiskAssessmentUpdateInput = z.infer<typeof riskAssessmentUpdateSchema>\nexport type MitigationActionCreateInput = z.infer<typeof mitigationActionCreateSchema>\nexport type MitigationActionUpdateInput = z.infer<typeof mitigationActionUpdateSchema>\nexport type StatementCreateInput = z.infer<typeof statementCreateSchema>\nexport type StatementUpdateInput = z.infer<typeof statementUpdateSchema>\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
3
|
import { useEffect, useMemo, useState, useCallback } from "react";
|
|
4
4
|
import { extensionPoints } from "@open-mercato/core/modules/portal/extension-points";
|
|
5
|
-
import {
|
|
5
|
+
import { replaceWithPageReload } from "@open-mercato/core/modules/portal/lib/navigation";
|
|
6
6
|
import { useT } from "@open-mercato/shared/lib/i18n/context";
|
|
7
7
|
import { Button } from "@open-mercato/ui/primitives/button";
|
|
8
8
|
import { Spinner } from "@open-mercato/ui/primitives/spinner";
|
|
@@ -27,7 +27,6 @@ function WidgetIcon({ className }) {
|
|
|
27
27
|
}
|
|
28
28
|
function PortalDashboardPage({ params }) {
|
|
29
29
|
const t = useT();
|
|
30
|
-
const router = useRouter();
|
|
31
30
|
const { auth } = usePortalContext();
|
|
32
31
|
const { user, loading } = auth;
|
|
33
32
|
const [editing, setEditing] = useState(false);
|
|
@@ -41,9 +40,9 @@ function PortalDashboardPage({ params }) {
|
|
|
41
40
|
}
|
|
42
41
|
useEffect(() => {
|
|
43
42
|
if (!loading && !user) {
|
|
44
|
-
|
|
43
|
+
replaceWithPageReload(`/${params.orgSlug}/portal/login`);
|
|
45
44
|
}
|
|
46
|
-
}, [loading, user,
|
|
45
|
+
}, [loading, user, params.orgSlug]);
|
|
47
46
|
useEffect(() => {
|
|
48
47
|
clearLegacyHiddenWidgetsKey();
|
|
49
48
|
}, []);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../../../src/modules/portal/frontend/%5BorgSlug%5D/portal/dashboard/page.tsx"],
|
|
4
|
-
"sourcesContent": ["\"use client\"\nimport React, { useEffect, useMemo, useState, useCallback } from 'react'\nimport { extensionPoints } from '@open-mercato/core/modules/portal/extension-points'\nimport {
|
|
5
|
-
"mappings": ";AAuBI,SACE,KADF;AAtBJ,SAAgB,WAAW,SAAS,UAAU,mBAAmB;AACjE,SAAS,uBAAuB;AAChC,SAAS,
|
|
4
|
+
"sourcesContent": ["\"use client\"\nimport React, { useEffect, useMemo, useState, useCallback } from 'react'\nimport { extensionPoints } from '@open-mercato/core/modules/portal/extension-points'\nimport { replaceWithPageReload } from '@open-mercato/core/modules/portal/lib/navigation'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { Spinner } from '@open-mercato/ui/primitives/spinner'\nimport { usePortalContext } from '@open-mercato/ui/portal/PortalContext'\nimport { PortalPageHeader } from '@open-mercato/ui/portal/components/PortalPageHeader'\nimport { PortalCard, PortalCardHeader } from '@open-mercato/ui/portal/components/PortalCard'\nimport { PortalEmptyState } from '@open-mercato/ui/portal/components/PortalEmptyState'\nimport { usePortalDashboardWidgets } from '@open-mercato/ui/portal/hooks/usePortalDashboardWidgets'\nimport { InjectionSpot } from '@open-mercato/ui/backend/injection/InjectionSpot'\nimport {\n loadHiddenWidgets,\n saveHiddenWidgets,\n clearLegacyHiddenWidgetsKey,\n} from './hiddenWidgetsStorage'\n\ntype Props = { params: { orgSlug: string } }\n\nfunction WidgetIcon({ className }: { className?: string }) {\n return (\n <svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\" className={className}>\n <rect width=\"7\" height=\"9\" x=\"3\" y=\"3\" rx=\"1\" /><rect width=\"7\" height=\"5\" x=\"14\" y=\"3\" rx=\"1\" /><rect width=\"7\" height=\"5\" x=\"14\" y=\"12\" rx=\"1\" /><rect width=\"7\" height=\"9\" x=\"3\" y=\"16\" rx=\"1\" />\n </svg>\n )\n}\n\nexport default function PortalDashboardPage({ params }: Props) {\n const t = useT()\n const { auth } = usePortalContext()\n const { user, loading } = auth\n\n const [editing, setEditing] = useState(false)\n const [hiddenWidgetsScopeKey, setHiddenWidgetsScopeKey] = useState<string | null>(null)\n const [hiddenWidgets, setHiddenWidgets] = useState<Set<string>>(() => new Set())\n\n const { widgets: dashboardWidgets, isLoading: widgetsLoading } = usePortalDashboardWidgets('portal:dashboard:sections' as any)\n\n // Recompute synchronously during render (not in an effect) so a freshly\n // resolved `user` never paints a frame with the previous scope's hidden set.\n const activeHiddenWidgetsScopeKey = user ? `${params.orgSlug}:${user.id}` : null\n if (activeHiddenWidgetsScopeKey !== hiddenWidgetsScopeKey) {\n setHiddenWidgetsScopeKey(activeHiddenWidgetsScopeKey)\n setHiddenWidgets(user ? loadHiddenWidgets(params.orgSlug, user.id) : new Set())\n }\n\n // Leaving an authenticated page for the login page crosses the public/authenticated\n // boundary, so it must be a full page load \u2014 see `replaceWithPageReload`.\n useEffect(() => {\n if (!loading && !user) {\n replaceWithPageReload(`/${params.orgSlug}/portal/login`)\n }\n }, [loading, user, params.orgSlug])\n\n useEffect(() => {\n clearLegacyHiddenWidgetsKey()\n }, [])\n\n const toggleWidget = useCallback((widgetId: string) => {\n if (!user) return\n setHiddenWidgets((prev) => {\n const next = new Set(prev)\n if (next.has(widgetId)) {\n next.delete(widgetId)\n } else {\n next.add(widgetId)\n }\n saveHiddenWidgets(params.orgSlug, user.id, next)\n return next\n })\n }, [params.orgSlug, user?.id])\n\n const visibleWidgets = useMemo(\n () => dashboardWidgets.filter((w) => !hiddenWidgets.has(w.metadata.id)),\n [dashboardWidgets, hiddenWidgets],\n )\n\n const injectionContext = useMemo(\n () => ({ orgSlug: params.orgSlug, user, roles: auth.roles, resolvedFeatures: auth.resolvedFeatures }),\n [params.orgSlug, user, auth.roles, auth.resolvedFeatures],\n )\n\n if (loading) {\n return <div className=\"flex items-center justify-center py-20\"><Spinner /></div>\n }\n\n if (!user) return null\n\n return (\n <div className=\"flex flex-col gap-8\">\n <PortalPageHeader\n label={t('portal.dashboard.title', 'Dashboard')}\n title={t('portal.dashboard.welcome', { name: user.displayName })}\n action={\n dashboardWidgets.length > 0 ? (\n <Button\n type=\"button\"\n variant={editing ? 'default' : 'outline'}\n size=\"sm\"\n className=\"rounded-lg text-sm\"\n onClick={() => setEditing((prev) => !prev)}\n >\n {editing ? t('portal.dashboard.done', 'Done') : t('portal.dashboard.customize', 'Customize')}\n </Button>\n ) : null\n }\n />\n\n <InjectionSpot spotId={extensionPoints.hosts.dashboardBefore.spotId} context={injectionContext} />\n\n {editing && dashboardWidgets.length > 0 ? (\n <PortalCard>\n <PortalCardHeader\n label={t('portal.dashboard.customize', 'Customize')}\n title={t('portal.dashboard.widgets', 'Dashboard Widgets')}\n />\n <div className=\"flex flex-wrap gap-2\">\n {dashboardWidgets.map((widget) => {\n const isHidden = hiddenWidgets.has(widget.metadata.id)\n return (\n <Button key={widget.metadata.id} type=\"button\" variant={isHidden ? 'outline' : 'default'} size=\"sm\" className=\"rounded-lg text-sm\" onClick={() => toggleWidget(widget.metadata.id)}>\n {widget.metadata.title || widget.metadata.id}\n </Button>\n )\n })}\n </div>\n </PortalCard>\n ) : null}\n\n {visibleWidgets.length > 0 ? (\n <div className=\"grid gap-5 md:grid-cols-2 xl:grid-cols-3\">\n {visibleWidgets.map((widget) => {\n const WidgetComponent = widget.Widget\n if (!WidgetComponent) return null\n return (\n <PortalCard key={widget.metadata.id}>\n <PortalCardHeader title={widget.metadata.title || widget.metadata.id} />\n <WidgetComponent context={{ orgSlug: params.orgSlug, user, roles: auth.roles, resolvedFeatures: auth.resolvedFeatures }} />\n </PortalCard>\n )\n })}\n </div>\n ) : null}\n\n {dashboardWidgets.length === 0 && !widgetsLoading ? (\n <PortalEmptyState\n icon={<WidgetIcon className=\"size-5\" />}\n title={t('portal.dashboard.emptyWidgets', 'No dashboard widgets yet')}\n description=\"Modules can inject widgets into this dashboard via the portal:dashboard:sections injection spot.\"\n />\n ) : null}\n\n <InjectionSpot spotId={extensionPoints.hosts.dashboardAfter.spotId} context={injectionContext} />\n </div>\n )\n}\n"],
|
|
5
|
+
"mappings": ";AAuBI,SACE,KADF;AAtBJ,SAAgB,WAAW,SAAS,UAAU,mBAAmB;AACjE,SAAS,uBAAuB;AAChC,SAAS,6BAA6B;AACtC,SAAS,YAAY;AACrB,SAAS,cAAc;AACvB,SAAS,eAAe;AACxB,SAAS,wBAAwB;AACjC,SAAS,wBAAwB;AACjC,SAAS,YAAY,wBAAwB;AAC7C,SAAS,wBAAwB;AACjC,SAAS,iCAAiC;AAC1C,SAAS,qBAAqB;AAC9B;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAIP,SAAS,WAAW,EAAE,UAAU,GAA2B;AACzD,SACE,qBAAC,SAAI,OAAM,8BAA6B,SAAQ,aAAY,MAAK,QAAO,QAAO,gBAAe,aAAY,OAAM,eAAc,SAAQ,gBAAe,SAAQ,WAC3J;AAAA,wBAAC,UAAK,OAAM,KAAI,QAAO,KAAI,GAAE,KAAI,GAAE,KAAI,IAAG,KAAI;AAAA,IAAE,oBAAC,UAAK,OAAM,KAAI,QAAO,KAAI,GAAE,MAAK,GAAE,KAAI,IAAG,KAAI;AAAA,IAAE,oBAAC,UAAK,OAAM,KAAI,QAAO,KAAI,GAAE,MAAK,GAAE,MAAK,IAAG,KAAI;AAAA,IAAE,oBAAC,UAAK,OAAM,KAAI,QAAO,KAAI,GAAE,KAAI,GAAE,MAAK,IAAG,KAAI;AAAA,KACpM;AAEJ;AAEe,SAAR,oBAAqC,EAAE,OAAO,GAAU;AAC7D,QAAM,IAAI,KAAK;AACf,QAAM,EAAE,KAAK,IAAI,iBAAiB;AAClC,QAAM,EAAE,MAAM,QAAQ,IAAI;AAE1B,QAAM,CAAC,SAAS,UAAU,IAAI,SAAS,KAAK;AAC5C,QAAM,CAAC,uBAAuB,wBAAwB,IAAI,SAAwB,IAAI;AACtF,QAAM,CAAC,eAAe,gBAAgB,IAAI,SAAsB,MAAM,oBAAI,IAAI,CAAC;AAE/E,QAAM,EAAE,SAAS,kBAAkB,WAAW,eAAe,IAAI,0BAA0B,2BAAkC;AAI7H,QAAM,8BAA8B,OAAO,GAAG,OAAO,OAAO,IAAI,KAAK,EAAE,KAAK;AAC5E,MAAI,gCAAgC,uBAAuB;AACzD,6BAAyB,2BAA2B;AACpD,qBAAiB,OAAO,kBAAkB,OAAO,SAAS,KAAK,EAAE,IAAI,oBAAI,IAAI,CAAC;AAAA,EAChF;AAIA,YAAU,MAAM;AACd,QAAI,CAAC,WAAW,CAAC,MAAM;AACrB,4BAAsB,IAAI,OAAO,OAAO,eAAe;AAAA,IACzD;AAAA,EACF,GAAG,CAAC,SAAS,MAAM,OAAO,OAAO,CAAC;AAElC,YAAU,MAAM;AACd,gCAA4B;AAAA,EAC9B,GAAG,CAAC,CAAC;AAEL,QAAM,eAAe,YAAY,CAAC,aAAqB;AACrD,QAAI,CAAC,KAAM;AACX,qBAAiB,CAAC,SAAS;AACzB,YAAM,OAAO,IAAI,IAAI,IAAI;AACzB,UAAI,KAAK,IAAI,QAAQ,GAAG;AACtB,aAAK,OAAO,QAAQ;AAAA,MACtB,OAAO;AACL,aAAK,IAAI,QAAQ;AAAA,MACnB;AACA,wBAAkB,OAAO,SAAS,KAAK,IAAI,IAAI;AAC/C,aAAO;AAAA,IACT,CAAC;AAAA,EACH,GAAG,CAAC,OAAO,SAAS,MAAM,EAAE,CAAC;AAE7B,QAAM,iBAAiB;AAAA,IACrB,MAAM,iBAAiB,OAAO,CAAC,MAAM,CAAC,cAAc,IAAI,EAAE,SAAS,EAAE,CAAC;AAAA,IACtE,CAAC,kBAAkB,aAAa;AAAA,EAClC;AAEA,QAAM,mBAAmB;AAAA,IACvB,OAAO,EAAE,SAAS,OAAO,SAAS,MAAM,OAAO,KAAK,OAAO,kBAAkB,KAAK,iBAAiB;AAAA,IACnG,CAAC,OAAO,SAAS,MAAM,KAAK,OAAO,KAAK,gBAAgB;AAAA,EAC1D;AAEA,MAAI,SAAS;AACX,WAAO,oBAAC,SAAI,WAAU,0CAAyC,8BAAC,WAAQ,GAAE;AAAA,EAC5E;AAEA,MAAI,CAAC,KAAM,QAAO;AAElB,SACE,qBAAC,SAAI,WAAU,uBACb;AAAA;AAAA,MAAC;AAAA;AAAA,QACC,OAAO,EAAE,0BAA0B,WAAW;AAAA,QAC9C,OAAO,EAAE,4BAA4B,EAAE,MAAM,KAAK,YAAY,CAAC;AAAA,QAC/D,QACE,iBAAiB,SAAS,IACxB;AAAA,UAAC;AAAA;AAAA,YACC,MAAK;AAAA,YACL,SAAS,UAAU,YAAY;AAAA,YAC/B,MAAK;AAAA,YACL,WAAU;AAAA,YACV,SAAS,MAAM,WAAW,CAAC,SAAS,CAAC,IAAI;AAAA,YAExC,oBAAU,EAAE,yBAAyB,MAAM,IAAI,EAAE,8BAA8B,WAAW;AAAA;AAAA,QAC7F,IACE;AAAA;AAAA,IAER;AAAA,IAEA,oBAAC,iBAAc,QAAQ,gBAAgB,MAAM,gBAAgB,QAAQ,SAAS,kBAAkB;AAAA,IAE/F,WAAW,iBAAiB,SAAS,IACpC,qBAAC,cACC;AAAA;AAAA,QAAC;AAAA;AAAA,UACC,OAAO,EAAE,8BAA8B,WAAW;AAAA,UAClD,OAAO,EAAE,4BAA4B,mBAAmB;AAAA;AAAA,MAC1D;AAAA,MACA,oBAAC,SAAI,WAAU,wBACZ,2BAAiB,IAAI,CAAC,WAAW;AAChC,cAAM,WAAW,cAAc,IAAI,OAAO,SAAS,EAAE;AACrD,eACE,oBAAC,UAAgC,MAAK,UAAS,SAAS,WAAW,YAAY,WAAW,MAAK,MAAK,WAAU,sBAAqB,SAAS,MAAM,aAAa,OAAO,SAAS,EAAE,GAC9K,iBAAO,SAAS,SAAS,OAAO,SAAS,MAD/B,OAAO,SAAS,EAE7B;AAAA,MAEJ,CAAC,GACH;AAAA,OACF,IACE;AAAA,IAEH,eAAe,SAAS,IACvB,oBAAC,SAAI,WAAU,4CACZ,yBAAe,IAAI,CAAC,WAAW;AAC9B,YAAM,kBAAkB,OAAO;AAC/B,UAAI,CAAC,gBAAiB,QAAO;AAC7B,aACE,qBAAC,cACC;AAAA,4BAAC,oBAAiB,OAAO,OAAO,SAAS,SAAS,OAAO,SAAS,IAAI;AAAA,QACtE,oBAAC,mBAAgB,SAAS,EAAE,SAAS,OAAO,SAAS,MAAM,OAAO,KAAK,OAAO,kBAAkB,KAAK,iBAAiB,GAAG;AAAA,WAF1G,OAAO,SAAS,EAGjC;AAAA,IAEJ,CAAC,GACH,IACE;AAAA,IAEH,iBAAiB,WAAW,KAAK,CAAC,iBACjC;AAAA,MAAC;AAAA;AAAA,QACC,MAAM,oBAAC,cAAW,WAAU,UAAS;AAAA,QACrC,OAAO,EAAE,iCAAiC,0BAA0B;AAAA,QACpE,aAAY;AAAA;AAAA,IACd,IACE;AAAA,IAEJ,oBAAC,iBAAc,QAAQ,gBAAgB,MAAM,eAAe,QAAQ,SAAS,kBAAkB;AAAA,KACjG;AAEJ;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -67,7 +67,9 @@ function PortalInvitePage({ params }) {
|
|
|
67
67
|
navigateWithPageReload(`/${orgSlug}/portal/dashboard`);
|
|
68
68
|
return;
|
|
69
69
|
}
|
|
70
|
-
if (result.status ===
|
|
70
|
+
if (result.status === 409) {
|
|
71
|
+
setError(t("portal.invite.error.accountExists", "This email address already has a portal account. Sign in below instead of accepting the invitation."));
|
|
72
|
+
} else if (result.status === 400) {
|
|
71
73
|
setError(t("portal.invite.error.invalidToken", "Invalid or expired invitation."));
|
|
72
74
|
} else {
|
|
73
75
|
setError(result.result?.error || t("portal.invite.error.generic", "Invitation acceptance failed. Please try again."));
|