@oronts/vendure-data-hub-plugin 0.1.1 → 0.1.3

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.
Files changed (357) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/README.md +6 -2
  3. package/dashboard/gql/gql.ts +6 -6
  4. package/dashboard/gql/graphql.ts +9 -4
  5. package/dashboard/hooks/api/use-pipeline-runs.ts +1 -0
  6. package/dashboard/hooks/api/use-queues.ts +1 -0
  7. package/dist/dashboard/components/common/ConnectionConfigEditor.tsx +589 -0
  8. package/dist/dashboard/components/common/HeadersEditor.tsx +90 -0
  9. package/dist/dashboard/components/common/ValidationFeedback.tsx +17 -0
  10. package/dist/dashboard/components/common/index.ts +10 -0
  11. package/dist/dashboard/components/pipelines/PipelineEditor.tsx +504 -0
  12. package/dist/dashboard/components/pipelines/PipelineExport.tsx +63 -0
  13. package/dist/dashboard/components/pipelines/PipelineImport.tsx +87 -0
  14. package/dist/dashboard/components/pipelines/ReactFlowPipelineEditor.tsx +539 -0
  15. package/dist/dashboard/components/pipelines/shared/NodePropertiesPanel.tsx +146 -0
  16. package/dist/dashboard/components/pipelines/shared/PipelineNode.tsx +155 -0
  17. package/dist/dashboard/components/pipelines/shared/PipelineSettingsPanel.tsx +392 -0
  18. package/dist/dashboard/components/pipelines/shared/StepListItem.tsx +144 -0
  19. package/dist/dashboard/components/pipelines/shared/index.ts +33 -0
  20. package/dist/dashboard/components/pipelines/shared/visual-node-config.ts +169 -0
  21. package/dist/dashboard/components/shared/LoadMoreButton.tsx +18 -0
  22. package/dist/dashboard/components/shared/entity-selector/EntitySelector.tsx +59 -0
  23. package/dist/dashboard/components/shared/entity-selector/index.ts +1 -0
  24. package/dist/dashboard/components/shared/error-boundary/ErrorBoundary.tsx +90 -0
  25. package/dist/dashboard/components/shared/error-boundary/index.ts +1 -0
  26. package/dist/dashboard/components/shared/feedback/EmptyState.tsx +36 -0
  27. package/dist/dashboard/components/shared/feedback/ErrorState.tsx +69 -0
  28. package/dist/dashboard/components/shared/feedback/LoadingState.tsx +104 -0
  29. package/dist/dashboard/components/shared/feedback/ValidationErrorDisplay.tsx +29 -0
  30. package/dist/dashboard/components/shared/feedback/index.ts +4 -0
  31. package/dist/dashboard/components/shared/file-dropzone/FileDropzone.tsx +167 -0
  32. package/dist/dashboard/components/shared/file-dropzone/index.ts +1 -0
  33. package/dist/dashboard/components/shared/filter-conditions-editor/FilterConditionsEditor.tsx +226 -0
  34. package/dist/dashboard/components/shared/filter-conditions-editor/index.ts +1 -0
  35. package/dist/dashboard/components/shared/index.ts +45 -0
  36. package/dist/dashboard/components/shared/schema-form/SchemaFormRenderer.tsx +248 -0
  37. package/dist/dashboard/components/shared/schema-form/fields/BooleanField.tsx +26 -0
  38. package/dist/dashboard/components/shared/schema-form/fields/FieldWrapper.tsx +28 -0
  39. package/dist/dashboard/components/shared/schema-form/fields/FileUploadField.tsx +171 -0
  40. package/dist/dashboard/components/shared/schema-form/fields/JsonField.tsx +132 -0
  41. package/dist/dashboard/components/shared/schema-form/fields/NumberField.tsx +33 -0
  42. package/dist/dashboard/components/shared/schema-form/fields/SelectField.tsx +70 -0
  43. package/dist/dashboard/components/shared/schema-form/fields/StringField.tsx +36 -0
  44. package/dist/dashboard/components/shared/schema-form/fields/TextareaField.tsx +31 -0
  45. package/dist/dashboard/components/shared/schema-form/fields/index.ts +23 -0
  46. package/dist/dashboard/components/shared/schema-form/index.ts +2 -0
  47. package/dist/dashboard/components/shared/schema-form/utils.ts +3 -0
  48. package/dist/dashboard/components/shared/selectable-card/SelectableCard.tsx +65 -0
  49. package/dist/dashboard/components/shared/selectable-card/index.ts +1 -0
  50. package/dist/dashboard/components/shared/stat-card/StatCard.tsx +121 -0
  51. package/dist/dashboard/components/shared/stat-card/index.ts +1 -0
  52. package/dist/dashboard/components/shared/step-config/AdapterRequiredWarning.tsx +25 -0
  53. package/dist/dashboard/components/shared/step-config/AdapterSelector.tsx +109 -0
  54. package/dist/dashboard/components/shared/step-config/AdvancedEditors.tsx +634 -0
  55. package/dist/dashboard/components/shared/step-config/EnrichConfigComponent.tsx +295 -0
  56. package/dist/dashboard/components/shared/step-config/ExtractTestResults.tsx +143 -0
  57. package/dist/dashboard/components/shared/step-config/GateConfigComponent.tsx +127 -0
  58. package/dist/dashboard/components/shared/step-config/LoadTestResults.tsx +104 -0
  59. package/dist/dashboard/components/shared/step-config/OperatorCard.tsx +266 -0
  60. package/dist/dashboard/components/shared/step-config/OperatorCheatSheetButton.tsx +54 -0
  61. package/dist/dashboard/components/shared/step-config/OperatorFieldInput.tsx +209 -0
  62. package/dist/dashboard/components/shared/step-config/RetrySettingsComponent.tsx +111 -0
  63. package/dist/dashboard/components/shared/step-config/RouteConfigComponent.tsx +125 -0
  64. package/dist/dashboard/components/shared/step-config/StepConfigPanel.tsx +564 -0
  65. package/dist/dashboard/components/shared/step-config/StepTester.tsx +165 -0
  66. package/dist/dashboard/components/shared/step-config/TestResultContainer.tsx +57 -0
  67. package/dist/dashboard/components/shared/step-config/TransformTestResults.tsx +130 -0
  68. package/dist/dashboard/components/shared/step-config/ValidateConfigComponent.tsx +334 -0
  69. package/dist/dashboard/components/shared/step-config/index.ts +29 -0
  70. package/dist/dashboard/components/shared/step-config/step-test-handlers.ts +297 -0
  71. package/dist/dashboard/components/shared/trigger-config/TriggerForm.tsx +478 -0
  72. package/dist/dashboard/components/shared/trigger-config/index.ts +1 -0
  73. package/dist/dashboard/components/shared/triggers-panel/TriggersPanel.tsx +281 -0
  74. package/dist/dashboard/components/shared/triggers-panel/index.ts +1 -0
  75. package/dist/dashboard/components/shared/wizard/ConfigurationNameCard.tsx +59 -0
  76. package/dist/dashboard/components/shared/wizard/SummaryCard.tsx +53 -0
  77. package/dist/dashboard/components/shared/wizard/WizardFooter.tsx +47 -0
  78. package/dist/dashboard/components/shared/wizard/WizardProgressBar.tsx +78 -0
  79. package/dist/dashboard/components/shared/wizard/index.ts +4 -0
  80. package/dist/dashboard/components/shared/wizard-trigger/TriggerSchemaFields.tsx +128 -0
  81. package/dist/dashboard/components/shared/wizard-trigger/TriggerSelector.tsx +33 -0
  82. package/dist/dashboard/components/shared/wizard-trigger/index.ts +2 -0
  83. package/dist/dashboard/components/templates/TemplateGallery.tsx +210 -0
  84. package/dist/dashboard/components/templates/TemplatePreview.tsx +214 -0
  85. package/dist/dashboard/components/templates/index.ts +4 -0
  86. package/dist/dashboard/components/wizards/export-wizard/DestinationStep.tsx +207 -0
  87. package/dist/dashboard/components/wizards/export-wizard/ExportWizard.tsx +221 -0
  88. package/dist/dashboard/components/wizards/export-wizard/FieldsStep.tsx +159 -0
  89. package/dist/dashboard/components/wizards/export-wizard/FormatStep.tsx +246 -0
  90. package/dist/dashboard/components/wizards/export-wizard/ReviewStep.tsx +231 -0
  91. package/dist/dashboard/components/wizards/export-wizard/SourceStep.tsx +154 -0
  92. package/dist/dashboard/components/wizards/export-wizard/TriggerStep.tsx +234 -0
  93. package/dist/dashboard/components/wizards/export-wizard/constants.ts +73 -0
  94. package/dist/dashboard/components/wizards/export-wizard/index.ts +2 -0
  95. package/dist/dashboard/components/wizards/export-wizard/types.ts +39 -0
  96. package/dist/dashboard/components/wizards/import-wizard/ImportWizard.tsx +350 -0
  97. package/dist/dashboard/components/wizards/import-wizard/MappingStep.tsx +286 -0
  98. package/dist/dashboard/components/wizards/import-wizard/PreviewStep.tsx +79 -0
  99. package/dist/dashboard/components/wizards/import-wizard/ReviewStep.tsx +266 -0
  100. package/dist/dashboard/components/wizards/import-wizard/SourceStep.tsx +537 -0
  101. package/dist/dashboard/components/wizards/import-wizard/StrategyStep.tsx +328 -0
  102. package/dist/dashboard/components/wizards/import-wizard/TargetStep.tsx +76 -0
  103. package/dist/dashboard/components/wizards/import-wizard/TemplateStep.tsx +116 -0
  104. package/dist/dashboard/components/wizards/import-wizard/TransformStep.tsx +666 -0
  105. package/dist/dashboard/components/wizards/import-wizard/TriggerStep.tsx +51 -0
  106. package/dist/dashboard/components/wizards/import-wizard/constants.ts +104 -0
  107. package/dist/dashboard/components/wizards/import-wizard/index.ts +3 -0
  108. package/dist/dashboard/components/wizards/import-wizard/types.ts +35 -0
  109. package/dist/dashboard/components/wizards/index.ts +7 -0
  110. package/dist/dashboard/components/wizards/shared/WizardStepContainer.tsx +27 -0
  111. package/dist/dashboard/components/wizards/shared/constants.ts +16 -0
  112. package/dist/dashboard/components/wizards/shared/index.ts +10 -0
  113. package/dist/dashboard/constants/colors.ts +25 -0
  114. package/dist/dashboard/constants/connection-defaults.ts +7 -0
  115. package/dist/dashboard/constants/connection-types.ts +1 -0
  116. package/dist/dashboard/constants/defaults.ts +18 -0
  117. package/dist/dashboard/constants/editor.ts +69 -0
  118. package/dist/dashboard/constants/enum-maps.ts +18 -0
  119. package/dist/dashboard/constants/fallbacks.ts +44 -0
  120. package/dist/dashboard/constants/file-format-registry.ts +206 -0
  121. package/dist/dashboard/constants/index.ts +24 -0
  122. package/dist/dashboard/constants/navigation.ts +29 -0
  123. package/dist/dashboard/constants/permissions.ts +41 -0
  124. package/dist/dashboard/constants/placeholders.ts +77 -0
  125. package/dist/dashboard/constants/routes.ts +12 -0
  126. package/dist/dashboard/constants/run-status.ts +1 -0
  127. package/dist/dashboard/constants/sentinel-values.ts +12 -0
  128. package/dist/dashboard/constants/step-configs.ts +9 -0
  129. package/dist/dashboard/constants/step-mappings.ts +170 -0
  130. package/dist/dashboard/constants/steps.ts +37 -0
  131. package/dist/dashboard/constants/toast-messages.ts +149 -0
  132. package/dist/dashboard/constants/triggers.ts +5 -0
  133. package/dist/dashboard/constants/ui-config.ts +139 -0
  134. package/dist/dashboard/constants/ui-dimensions.ts +145 -0
  135. package/dist/dashboard/constants/ui-states.ts +28 -0
  136. package/dist/dashboard/constants/ui-types.ts +85 -0
  137. package/dist/dashboard/constants/validation-patterns.ts +26 -0
  138. package/dist/dashboard/gql/gql.ts +370 -0
  139. package/dist/dashboard/gql/graphql.ts +10383 -0
  140. package/dist/dashboard/gql/index.ts +1 -0
  141. package/dist/dashboard/hooks/api/index.ts +115 -0
  142. package/dist/dashboard/hooks/api/mutation-helpers.ts +34 -0
  143. package/dist/dashboard/hooks/api/use-adapters.ts +92 -0
  144. package/dist/dashboard/hooks/api/use-config-options.ts +513 -0
  145. package/dist/dashboard/hooks/api/use-connections.ts +84 -0
  146. package/dist/dashboard/hooks/api/use-entity-field-schemas.ts +99 -0
  147. package/dist/dashboard/hooks/api/use-entity-loaders.ts +45 -0
  148. package/dist/dashboard/hooks/api/use-hooks.ts +68 -0
  149. package/dist/dashboard/hooks/api/use-logs.ts +102 -0
  150. package/dist/dashboard/hooks/api/use-pipeline-runs.ts +222 -0
  151. package/dist/dashboard/hooks/api/use-pipelines.ts +279 -0
  152. package/dist/dashboard/hooks/api/use-queues.ts +142 -0
  153. package/dist/dashboard/hooks/api/use-secrets.ts +75 -0
  154. package/dist/dashboard/hooks/api/use-settings.ts +55 -0
  155. package/dist/dashboard/hooks/api/use-step-tester.ts +79 -0
  156. package/dist/dashboard/hooks/index.ts +13 -0
  157. package/dist/dashboard/hooks/use-adapter-catalog.ts +253 -0
  158. package/dist/dashboard/hooks/use-export-templates.ts +80 -0
  159. package/dist/dashboard/hooks/use-import-templates.ts +139 -0
  160. package/dist/dashboard/hooks/use-load-more.ts +29 -0
  161. package/dist/dashboard/hooks/use-stable-keys.ts +54 -0
  162. package/dist/dashboard/hooks/use-trigger-types.ts +100 -0
  163. package/dist/dashboard/hooks/use-wizard-navigation.ts +128 -0
  164. package/dist/dashboard/index.tsx +55 -0
  165. package/dist/dashboard/routes/adapters/AdapterCard.tsx +102 -0
  166. package/dist/dashboard/routes/adapters/AdapterConstants.tsx +20 -0
  167. package/dist/dashboard/routes/adapters/AdapterDetail.tsx +208 -0
  168. package/dist/dashboard/routes/adapters/AdapterTypeSection.tsx +105 -0
  169. package/dist/dashboard/routes/adapters/AdaptersPage.tsx +276 -0
  170. package/dist/dashboard/routes/adapters/AdaptersTable.tsx +107 -0
  171. package/dist/dashboard/routes/adapters/index.ts +1 -0
  172. package/dist/dashboard/routes/connections/ConnectionDetail.tsx +218 -0
  173. package/dist/dashboard/routes/connections/ConnectionsList.tsx +34 -0
  174. package/dist/dashboard/routes/connections/index.ts +2 -0
  175. package/dist/dashboard/routes/hooks/Hooks.tsx +425 -0
  176. package/dist/dashboard/routes/hooks/hook-stages.ts +52 -0
  177. package/dist/dashboard/routes/hooks/index.ts +1 -0
  178. package/dist/dashboard/routes/index.ts +8 -0
  179. package/dist/dashboard/routes/logs/Logs.tsx +93 -0
  180. package/dist/dashboard/routes/logs/components/LogDetailDrawer.tsx +118 -0
  181. package/dist/dashboard/routes/logs/components/LogExplorerTab.tsx +367 -0
  182. package/dist/dashboard/routes/logs/components/LogLevelBadge.tsx +34 -0
  183. package/dist/dashboard/routes/logs/components/LogTableRow.tsx +70 -0
  184. package/dist/dashboard/routes/logs/components/LogsOverviewTab.tsx +178 -0
  185. package/dist/dashboard/routes/logs/components/RealtimeLogTab.tsx +122 -0
  186. package/dist/dashboard/routes/logs/index.ts +1 -0
  187. package/dist/dashboard/routes/pipelines/ErrorAuditList.tsx +39 -0
  188. package/dist/dashboard/routes/pipelines/ExportWizardPage.tsx +96 -0
  189. package/dist/dashboard/routes/pipelines/ImportWizardPage.tsx +104 -0
  190. package/dist/dashboard/routes/pipelines/PipelineDetail.tsx +211 -0
  191. package/dist/dashboard/routes/pipelines/PipelineRunsBlock.tsx +377 -0
  192. package/dist/dashboard/routes/pipelines/PipelinesList.tsx +87 -0
  193. package/dist/dashboard/routes/pipelines/RetryPatchHelper.tsx +51 -0
  194. package/dist/dashboard/routes/pipelines/RunDetailsPanel.tsx +238 -0
  195. package/dist/dashboard/routes/pipelines/RunErrorsList.tsx +116 -0
  196. package/dist/dashboard/routes/pipelines/StepCounters.tsx +24 -0
  197. package/dist/dashboard/routes/pipelines/StepSummaryTable.tsx +36 -0
  198. package/dist/dashboard/routes/pipelines/components/DryRunDialog.tsx +341 -0
  199. package/dist/dashboard/routes/pipelines/components/PipelineActionButtons.tsx +201 -0
  200. package/dist/dashboard/routes/pipelines/components/PipelineEditorToggle.tsx +116 -0
  201. package/dist/dashboard/routes/pipelines/components/PipelineFormFields.tsx +156 -0
  202. package/dist/dashboard/routes/pipelines/components/PipelineWebhookInfo.tsx +111 -0
  203. package/dist/dashboard/routes/pipelines/components/ReviewActionsPanel.tsx +342 -0
  204. package/dist/dashboard/routes/pipelines/components/ValidationPanel.tsx +121 -0
  205. package/dist/dashboard/routes/pipelines/components/VersionHistoryDialog.tsx +131 -0
  206. package/dist/dashboard/routes/pipelines/components/index.ts +25 -0
  207. package/dist/dashboard/routes/pipelines/hooks/index.ts +1 -0
  208. package/dist/dashboard/routes/pipelines/hooks/use-pipeline-validation.ts +114 -0
  209. package/dist/dashboard/routes/pipelines/index.ts +4 -0
  210. package/dist/dashboard/routes/pipelines/utils/index.ts +1 -0
  211. package/dist/dashboard/routes/pipelines/utils/pipeline-conversion.ts +261 -0
  212. package/dist/dashboard/routes/queues/ConsumersTable.tsx +134 -0
  213. package/dist/dashboard/routes/queues/DeadLettersTable.tsx +118 -0
  214. package/dist/dashboard/routes/queues/FailedRunsTable.tsx +74 -0
  215. package/dist/dashboard/routes/queues/QueuesPage.tsx +290 -0
  216. package/dist/dashboard/routes/queues/index.ts +1 -0
  217. package/dist/dashboard/routes/queues/types.ts +22 -0
  218. package/dist/dashboard/routes/secrets/SecretDetail.tsx +278 -0
  219. package/dist/dashboard/routes/secrets/SecretsList.tsx +34 -0
  220. package/dist/dashboard/routes/secrets/index.ts +2 -0
  221. package/dist/dashboard/routes/settings/Settings.tsx +343 -0
  222. package/dist/dashboard/routes/settings/index.ts +1 -0
  223. package/dist/dashboard/types/index.ts +89 -0
  224. package/dist/dashboard/types/pipeline.ts +51 -0
  225. package/dist/dashboard/types/ui-types.ts +400 -0
  226. package/dist/dashboard/types/wizard.ts +235 -0
  227. package/dist/dashboard/utils/adapter-grouping.ts +43 -0
  228. package/dist/dashboard/utils/column-analysis.ts +11 -0
  229. package/dist/dashboard/utils/field-preparation.ts +31 -0
  230. package/dist/dashboard/utils/form-validation.ts +373 -0
  231. package/dist/dashboard/utils/formatters.ts +92 -0
  232. package/dist/dashboard/utils/icon-resolver.ts +35 -0
  233. package/dist/dashboard/utils/index.ts +60 -0
  234. package/dist/dashboard/utils/query-key-factory.ts +54 -0
  235. package/dist/dashboard/utils/step-helpers.ts +32 -0
  236. package/dist/dashboard/utils/string-helpers.ts +4 -0
  237. package/dist/dashboard/utils/template-helpers.ts +26 -0
  238. package/dist/dashboard/utils/trigger-sync.ts +138 -0
  239. package/dist/dashboard/utils/wizard-to-pipeline.ts +569 -0
  240. package/dist/shared/types/adapter-config.types.d.ts +254 -11
  241. package/dist/shared/types/adapter-config.types.d.ts.map +1 -1
  242. package/dist/shared/types/index.d.ts +1 -1
  243. package/dist/shared/types/index.d.ts.map +1 -1
  244. package/dist/shared/types/index.js.map +1 -1
  245. package/dist/shared/utils/error.d.ts +5 -0
  246. package/dist/shared/utils/error.d.ts.map +1 -1
  247. package/dist/shared/utils/error.js +11 -0
  248. package/dist/shared/utils/error.js.map +1 -1
  249. package/dist/src/api/schema/pipeline.schema.d.ts +1 -1
  250. package/dist/src/api/schema/pipeline.schema.d.ts.map +1 -1
  251. package/dist/src/api/schema/pipeline.schema.js +2 -0
  252. package/dist/src/api/schema/pipeline.schema.js.map +1 -1
  253. package/dist/src/bootstrap/initialization.d.ts.map +1 -1
  254. package/dist/src/bootstrap/initialization.js +6 -0
  255. package/dist/src/bootstrap/initialization.js.map +1 -1
  256. package/dist/src/entities/data/error-record.entity.d.ts +1 -0
  257. package/dist/src/entities/data/error-record.entity.d.ts.map +1 -1
  258. package/dist/src/entities/data/error-record.entity.js +4 -0
  259. package/dist/src/entities/data/error-record.entity.js.map +1 -1
  260. package/dist/src/gql/generated.d.ts +5 -0
  261. package/dist/src/gql/generated.d.ts.map +1 -1
  262. package/dist/src/gql/generated.js.map +1 -1
  263. package/dist/src/loaders/inventory/inventory.loader.d.ts.map +1 -1
  264. package/dist/src/loaders/inventory/inventory.loader.js +1 -2
  265. package/dist/src/loaders/inventory/inventory.loader.js.map +1 -1
  266. package/dist/src/runtime/executor-types.d.ts +3 -2
  267. package/dist/src/runtime/executor-types.d.ts.map +1 -1
  268. package/dist/src/runtime/executors/loaders/asset-handler.js +1 -1
  269. package/dist/src/runtime/executors/loaders/asset-handler.js.map +1 -1
  270. package/dist/src/runtime/executors/loaders/asset-import-handler.js +1 -1
  271. package/dist/src/runtime/executors/loaders/asset-import-handler.js.map +1 -1
  272. package/dist/src/runtime/executors/loaders/channel-handler.d.ts.map +1 -1
  273. package/dist/src/runtime/executors/loaders/channel-handler.js +14 -1
  274. package/dist/src/runtime/executors/loaders/channel-handler.js.map +1 -1
  275. package/dist/src/runtime/executors/loaders/collection-handler.d.ts.map +1 -1
  276. package/dist/src/runtime/executors/loaders/collection-handler.js +22 -3
  277. package/dist/src/runtime/executors/loaders/collection-handler.js.map +1 -1
  278. package/dist/src/runtime/executors/loaders/customer-group-handler.d.ts.map +1 -1
  279. package/dist/src/runtime/executors/loaders/customer-group-handler.js +8 -1
  280. package/dist/src/runtime/executors/loaders/customer-group-handler.js.map +1 -1
  281. package/dist/src/runtime/executors/loaders/customer-handler.d.ts.map +1 -1
  282. package/dist/src/runtime/executors/loaders/customer-handler.js +33 -2
  283. package/dist/src/runtime/executors/loaders/customer-handler.js.map +1 -1
  284. package/dist/src/runtime/executors/loaders/facet-handler.d.ts.map +1 -1
  285. package/dist/src/runtime/executors/loaders/facet-handler.js +34 -2
  286. package/dist/src/runtime/executors/loaders/facet-handler.js.map +1 -1
  287. package/dist/src/runtime/executors/loaders/graphql-mutation-handler.js +1 -1
  288. package/dist/src/runtime/executors/loaders/graphql-mutation-handler.js.map +1 -1
  289. package/dist/src/runtime/executors/loaders/inventory-adjust-handler.d.ts.map +1 -1
  290. package/dist/src/runtime/executors/loaders/inventory-adjust-handler.js +8 -1
  291. package/dist/src/runtime/executors/loaders/inventory-adjust-handler.js.map +1 -1
  292. package/dist/src/runtime/executors/loaders/inventory-handler.js +3 -3
  293. package/dist/src/runtime/executors/loaders/inventory-handler.js.map +1 -1
  294. package/dist/src/runtime/executors/loaders/loader-handler-registry.d.ts.map +1 -1
  295. package/dist/src/runtime/executors/loaders/loader-handler-registry.js +35 -10
  296. package/dist/src/runtime/executors/loaders/loader-handler-registry.js.map +1 -1
  297. package/dist/src/runtime/executors/loaders/order-handler.d.ts +1 -1
  298. package/dist/src/runtime/executors/loaders/order-handler.d.ts.map +1 -1
  299. package/dist/src/runtime/executors/loaders/order-handler.js +7 -4
  300. package/dist/src/runtime/executors/loaders/order-handler.js.map +1 -1
  301. package/dist/src/runtime/executors/loaders/payment-method-handler.d.ts.map +1 -1
  302. package/dist/src/runtime/executors/loaders/payment-method-handler.js +14 -1
  303. package/dist/src/runtime/executors/loaders/payment-method-handler.js.map +1 -1
  304. package/dist/src/runtime/executors/loaders/product-handler.d.ts +6 -0
  305. package/dist/src/runtime/executors/loaders/product-handler.d.ts.map +1 -1
  306. package/dist/src/runtime/executors/loaders/product-handler.js +31 -13
  307. package/dist/src/runtime/executors/loaders/product-handler.js.map +1 -1
  308. package/dist/src/runtime/executors/loaders/promotion-handler.d.ts.map +1 -1
  309. package/dist/src/runtime/executors/loaders/promotion-handler.js +21 -2
  310. package/dist/src/runtime/executors/loaders/promotion-handler.js.map +1 -1
  311. package/dist/src/runtime/executors/loaders/rest-handler.js +1 -1
  312. package/dist/src/runtime/executors/loaders/rest-handler.js.map +1 -1
  313. package/dist/src/runtime/executors/loaders/shared-lookups.d.ts +28 -1
  314. package/dist/src/runtime/executors/loaders/shared-lookups.d.ts.map +1 -1
  315. package/dist/src/runtime/executors/loaders/shared-lookups.js +136 -0
  316. package/dist/src/runtime/executors/loaders/shared-lookups.js.map +1 -1
  317. package/dist/src/runtime/executors/loaders/shipping-method-handler.d.ts.map +1 -1
  318. package/dist/src/runtime/executors/loaders/shipping-method-handler.js +8 -1
  319. package/dist/src/runtime/executors/loaders/shipping-method-handler.js.map +1 -1
  320. package/dist/src/runtime/executors/loaders/stock-location-handler.d.ts.map +1 -1
  321. package/dist/src/runtime/executors/loaders/stock-location-handler.js +8 -1
  322. package/dist/src/runtime/executors/loaders/stock-location-handler.js.map +1 -1
  323. package/dist/src/runtime/executors/loaders/tax-rate-handler.d.ts.map +1 -1
  324. package/dist/src/runtime/executors/loaders/tax-rate-handler.js +14 -1
  325. package/dist/src/runtime/executors/loaders/tax-rate-handler.js.map +1 -1
  326. package/dist/src/runtime/executors/loaders/types.d.ts +2 -0
  327. package/dist/src/runtime/executors/loaders/types.d.ts.map +1 -1
  328. package/dist/src/runtime/executors/loaders/variant-handler.d.ts +24 -2
  329. package/dist/src/runtime/executors/loaders/variant-handler.d.ts.map +1 -1
  330. package/dist/src/runtime/executors/loaders/variant-handler.js +190 -44
  331. package/dist/src/runtime/executors/loaders/variant-handler.js.map +1 -1
  332. package/dist/src/runtime/executors/sink-handler-registry.js +2 -2
  333. package/dist/src/runtime/executors/sink-handler-registry.js.map +1 -1
  334. package/dist/src/services/data/record-error.service.d.ts +1 -1
  335. package/dist/src/services/data/record-error.service.d.ts.map +1 -1
  336. package/dist/src/services/data/record-error.service.js +4 -1
  337. package/dist/src/services/data/record-error.service.js.map +1 -1
  338. package/dist/src/services/logger/execution-logger.d.ts +1 -1
  339. package/dist/src/services/logger/execution-logger.d.ts.map +1 -1
  340. package/dist/src/services/logger/execution-logger.js +8 -4
  341. package/dist/src/services/logger/execution-logger.js.map +1 -1
  342. package/dist/src/services/pipeline/pipeline-runner.service.d.ts.map +1 -1
  343. package/dist/src/services/pipeline/pipeline-runner.service.js +3 -3
  344. package/dist/src/services/pipeline/pipeline-runner.service.js.map +1 -1
  345. package/dist/src/utils/error.utils.d.ts +1 -1
  346. package/dist/src/utils/error.utils.d.ts.map +1 -1
  347. package/dist/src/utils/error.utils.js +2 -1
  348. package/dist/src/utils/error.utils.js.map +1 -1
  349. package/dist/src/utils/url-security.utils.d.ts +5 -3
  350. package/dist/src/utils/url-security.utils.d.ts.map +1 -1
  351. package/dist/src/utils/url-security.utils.js +20 -4
  352. package/dist/src/utils/url-security.utils.js.map +1 -1
  353. package/docs/reference/loaders.md +39 -2
  354. package/package.json +2 -2
  355. package/shared/types/adapter-config.types.ts +278 -9
  356. package/shared/types/index.ts +13 -0
  357. package/shared/utils/error.ts +11 -0
@@ -0,0 +1,221 @@
1
+ import * as React from 'react';
2
+ import { Download } from 'lucide-react';
3
+ import { toast } from 'sonner';
4
+ import {
5
+ Card,
6
+ CardContent,
7
+ CardHeader,
8
+ CardTitle,
9
+ } from '@vendure/dashboard';
10
+ import { VENDURE_ENTITY_SCHEMAS } from '../../../../shared';
11
+ import { WIZARD_STEPS, EXPORT_STEP_ID, DEFAULT_EXPORT_OPTIONS } from './constants';
12
+ import { QUERY_LIMITS, TRIGGER_TYPE, EXPORT_FORMAT, TOAST_WIZARD } from '../../../constants';
13
+ import type { ExportWizardProps, ExportConfiguration, ExportField } from './types';
14
+ import { SourceStep } from './SourceStep';
15
+ import { FieldsStep } from './FieldsStep';
16
+ import { FormatStep } from './FormatStep';
17
+ import { DestinationStep } from './DestinationStep';
18
+ import { TriggerStep } from './TriggerStep';
19
+ import { ReviewStep } from './ReviewStep';
20
+ import { validateExportWizardStep } from '../../../utils';
21
+ import { WizardProgressBar, WizardFooter, ValidationErrorDisplay, SelectableCard, SelectableCardGrid } from '../../shared';
22
+ import { useExportTemplates } from '../../../hooks/use-export-templates';
23
+ import type { ExportTemplate } from '../../../hooks/use-export-templates';
24
+ import { useWizardNavigation } from '../../../hooks/use-wizard-navigation';
25
+ import { useEntityFieldSchemas } from '../../../hooks/api/use-entity-field-schemas';
26
+ import { useDestinationSchemas, useTriggerTypeSchemas } from '../../../hooks/api/use-config-options';
27
+
28
+ const QUICK_START_TEMPLATE_COUNT = 4;
29
+
30
+ function getSchemaFieldDefault(schemas: Array<{ type: string; fields: Array<{ key: string; defaultValue?: unknown }> }>, type: string, key: string, fallback: string): string {
31
+ const schema = schemas.find(s => s.type === type);
32
+ const field = schema?.fields.find(f => f.key === key);
33
+ return typeof field?.defaultValue === 'string' ? field.defaultValue : fallback;
34
+ }
35
+
36
+ export function ExportWizard({ onComplete, onCancel, initialConfig, isSubmitting }: ExportWizardProps) {
37
+ const [selectedTemplate, setSelectedTemplate] = React.useState<ExportTemplate | null>(null);
38
+ const { templates: exportTemplates } = useExportTemplates();
39
+ const { getFieldNames: getBackendFieldNames } = useEntityFieldSchemas();
40
+ const { schemas: destinationSchemas } = useDestinationSchemas();
41
+ const { schemas: triggerSchemas } = useTriggerTypeSchemas();
42
+
43
+ const fileDefaults = React.useMemo(() => ({
44
+ directory: getSchemaFieldDefault(destinationSchemas, 'FILE', 'directory', '/exports'),
45
+ filename: getSchemaFieldDefault(destinationSchemas, 'FILE', 'filename', 'export.csv'),
46
+ }), [destinationSchemas]);
47
+
48
+ const validateStep = React.useCallback((stepId: string, cfg: Partial<ExportConfiguration>) => {
49
+ return validateExportWizardStep(stepId, cfg, destinationSchemas, triggerSchemas);
50
+ }, [destinationSchemas, triggerSchemas]);
51
+
52
+ const {
53
+ config,
54
+ setConfig,
55
+ currentStep,
56
+ setCurrentStep,
57
+ stepErrors,
58
+ setStepErrors,
59
+ attemptedNext,
60
+ setAttemptedNext,
61
+ updateConfig,
62
+ handleNext,
63
+ handleBack,
64
+ handleStepClick,
65
+ handleComplete,
66
+ canProceed,
67
+ } = useWizardNavigation<Partial<ExportConfiguration>>({
68
+ steps: WIZARD_STEPS,
69
+ initialConfig: initialConfig ?? {
70
+ name: '',
71
+ sourceEntity: '',
72
+ sourceQuery: { type: 'all', limit: QUERY_LIMITS.EXPORT_DEFAULT, orderBy: 'id', orderDirection: 'ASC' },
73
+ filters: [],
74
+ fields: [],
75
+ format: { type: EXPORT_FORMAT.CSV, options: { delimiter: ',', includeHeaders: true } },
76
+ destination: { type: 'FILE', fileConfig: { directory: fileDefaults.directory, filename: fileDefaults.filename } },
77
+ trigger: { type: TRIGGER_TYPE.MANUAL },
78
+ options: { ...DEFAULT_EXPORT_OPTIONS },
79
+ },
80
+ validateStep,
81
+ onComplete: onComplete as (config: Partial<ExportConfiguration>) => void,
82
+ nameRequiredMessage: TOAST_WIZARD.EXPORT_NAME_REQUIRED,
83
+ isSubmitting,
84
+ });
85
+
86
+ const handleUseTemplate = React.useCallback((template: ExportTemplate) => {
87
+ setSelectedTemplate(template);
88
+ const def = template.definition;
89
+ setConfig(prev => ({
90
+ ...prev,
91
+ name: template.name,
92
+ ...(def?.sourceEntity ? { sourceEntity: def.sourceEntity } : {}),
93
+ ...(def?.format ? {
94
+ format: {
95
+ type: def.format as ExportConfiguration['format']['type'],
96
+ options: {
97
+ ...prev.format?.options,
98
+ ...(def.formatOptions ?? {}),
99
+ },
100
+ },
101
+ } : {}),
102
+ ...(def?.fields?.length ? {
103
+ fields: def.fields.map(f => ({
104
+ sourceField: f.sourceField,
105
+ outputName: f.outputName,
106
+ include: true,
107
+ })),
108
+ } : {}),
109
+ }));
110
+ setCurrentStep(0);
111
+ toast.success(TOAST_WIZARD.TEMPLATE_SELECTED);
112
+ }, [setConfig, setCurrentStep]);
113
+
114
+ // Track previous sourceEntity to detect changes and avoid re-running on same value
115
+ const prevSourceEntityRef = React.useRef<string | undefined>(undefined);
116
+
117
+ React.useEffect(() => {
118
+ // eslint-disable-next-line react-hooks/exhaustive-deps -- config.fields intentionally excluded: effect SETS fields, including it would cause infinite loop
119
+ // Only run when sourceEntity actually changes, not on every render
120
+ if (config.sourceEntity && config.sourceEntity !== prevSourceEntityRef.current) {
121
+ prevSourceEntityRef.current = config.sourceEntity;
122
+
123
+ // Use backend field names as primary source, fall back to static schemas during loading
124
+ const backendNames = getBackendFieldNames(config.sourceEntity);
125
+ const fieldNames = backendNames.length > 0
126
+ ? backendNames
127
+ : Object.keys(VENDURE_ENTITY_SCHEMAS[config.sourceEntity]?.fields ?? {});
128
+
129
+ if (fieldNames.length > 0) {
130
+ // If template fields are already set, don't override with auto-detected fields
131
+ if (config.fields && config.fields.length > 0 && selectedTemplate) {
132
+ return;
133
+ }
134
+ const fields: ExportField[] = fieldNames.map(name => ({
135
+ sourceField: name,
136
+ outputName: name,
137
+ include: true,
138
+ }));
139
+ // Use setConfig directly to avoid infinite loop from updateConfig in deps
140
+ setConfig(prev => ({ ...prev, fields }));
141
+ setStepErrors({});
142
+ setAttemptedNext(false);
143
+ }
144
+ }
145
+ }, [config.sourceEntity, selectedTemplate, getBackendFieldNames, setConfig, setStepErrors, setAttemptedNext]);
146
+
147
+ return (
148
+ <div className="flex flex-col h-full" data-testid="datahub-exportwizard-wizard">
149
+ <WizardProgressBar
150
+ steps={WIZARD_STEPS}
151
+ currentStep={currentStep}
152
+ onStepClick={handleStepClick}
153
+ />
154
+
155
+ {!selectedTemplate && currentStep === 0 && exportTemplates.length > 0 && (
156
+ <div className="px-6 pt-4">
157
+ <Card>
158
+ <CardHeader>
159
+ <CardTitle className="text-sm">Quick Start with a Template</CardTitle>
160
+ </CardHeader>
161
+ <CardContent>
162
+ <SelectableCardGrid columns={4}>
163
+ {exportTemplates.slice(0, QUICK_START_TEMPLATE_COUNT).map(template => (
164
+ <SelectableCard
165
+ key={template.id}
166
+ title={template.name}
167
+ description={template.description}
168
+ selected={false}
169
+ onClick={() => handleUseTemplate(template)}
170
+ data-testid={`datahub-export-template-${template.id}-btn`}
171
+ />
172
+ ))}
173
+ </SelectableCardGrid>
174
+ </CardContent>
175
+ </Card>
176
+ </div>
177
+ )}
178
+
179
+ <div className="flex-1 overflow-auto p-6" data-testid="datahub-exportwizard-steps">
180
+ <ValidationErrorDisplay errors={stepErrors} show={attemptedNext} />
181
+
182
+ {WIZARD_STEPS[currentStep].id === EXPORT_STEP_ID.SOURCE && (
183
+ <SourceStep config={config} updateConfig={updateConfig} errors={attemptedNext ? stepErrors : {}} />
184
+ )}
185
+
186
+ {WIZARD_STEPS[currentStep].id === EXPORT_STEP_ID.FIELDS && (
187
+ <FieldsStep config={config} updateConfig={updateConfig} errors={attemptedNext ? stepErrors : {}} />
188
+ )}
189
+
190
+ {WIZARD_STEPS[currentStep].id === EXPORT_STEP_ID.FORMAT && (
191
+ <FormatStep config={config} updateConfig={updateConfig} errors={attemptedNext ? stepErrors : {}} />
192
+ )}
193
+
194
+ {WIZARD_STEPS[currentStep].id === EXPORT_STEP_ID.DESTINATION && (
195
+ <DestinationStep config={config} updateConfig={updateConfig} errors={attemptedNext ? stepErrors : {}} />
196
+ )}
197
+
198
+ {WIZARD_STEPS[currentStep].id === EXPORT_STEP_ID.TRIGGER && (
199
+ <TriggerStep config={config} updateConfig={updateConfig} errors={attemptedNext ? stepErrors : {}} />
200
+ )}
201
+
202
+ {WIZARD_STEPS[currentStep].id === EXPORT_STEP_ID.REVIEW && (
203
+ <ReviewStep config={config} updateConfig={updateConfig} errors={attemptedNext ? stepErrors : {}} />
204
+ )}
205
+ </div>
206
+
207
+ <WizardFooter
208
+ currentStep={currentStep}
209
+ totalSteps={WIZARD_STEPS.length}
210
+ canProceed={canProceed}
211
+ onBack={handleBack}
212
+ onNext={handleNext}
213
+ onComplete={handleComplete}
214
+ onCancel={onCancel}
215
+ completeLabel="Create Export"
216
+ completeIcon={Download}
217
+ isSubmitting={isSubmitting}
218
+ />
219
+ </div>
220
+ );
221
+ }
@@ -0,0 +1,159 @@
1
+ import { useCallback } from 'react';
2
+ import {
3
+ Button,
4
+ Card,
5
+ CardContent,
6
+ Input,
7
+ Badge,
8
+ Switch,
9
+ Select,
10
+ SelectContent,
11
+ SelectItem,
12
+ SelectTrigger,
13
+ SelectValue,
14
+ ScrollArea,
15
+ } from '@vendure/dashboard';
16
+ import { WizardStepContainer } from '../shared';
17
+ import { STEP_CONTENT } from './constants';
18
+ import { COMPONENT_HEIGHTS, SENTINEL_VALUES } from '../../../constants';
19
+ import { useFieldTransformTypes } from '../../../hooks/api/use-config-options';
20
+ import type { ConfigOptionValue } from '../../../hooks/api/use-config-options';
21
+ import type { ExportConfiguration, ExportField } from './types';
22
+
23
+ interface FieldsStepProps {
24
+ config: Partial<ExportConfiguration>;
25
+ updateConfig: (updates: Partial<ExportConfiguration>) => void;
26
+ errors?: Record<string, string>;
27
+ }
28
+
29
+ export function FieldsStep({ config, updateConfig, errors = {} }: FieldsStepProps) {
30
+ const { options: transformTypes } = useFieldTransformTypes();
31
+ const fields = config.fields ?? [];
32
+
33
+ const toggleField = useCallback((index: number) => {
34
+ const currentFields = config.fields ?? [];
35
+ const newFields = [...currentFields];
36
+ newFields[index] = { ...newFields[index], include: !newFields[index].include };
37
+ updateConfig({ fields: newFields });
38
+ }, [config.fields, updateConfig]);
39
+
40
+ const updateField = useCallback((index: number, updates: Partial<ExportField>) => {
41
+ const currentFields = config.fields ?? [];
42
+ const newFields = [...currentFields];
43
+ newFields[index] = { ...newFields[index], ...updates };
44
+ updateConfig({ fields: newFields });
45
+ }, [config.fields, updateConfig]);
46
+
47
+ const selectAll = useCallback(() => {
48
+ const currentFields = config.fields ?? [];
49
+ updateConfig({
50
+ fields: currentFields.map(f => ({ ...f, include: true })),
51
+ });
52
+ }, [config.fields, updateConfig]);
53
+
54
+ const deselectAll = useCallback(() => {
55
+ const currentFields = config.fields ?? [];
56
+ updateConfig({
57
+ fields: currentFields.map(f => ({ ...f, include: false })),
58
+ });
59
+ }, [config.fields, updateConfig]);
60
+
61
+ const selectedCount = fields.filter(f => f.include).length;
62
+
63
+ return (
64
+ <WizardStepContainer
65
+ title={STEP_CONTENT.fields.title}
66
+ description={STEP_CONTENT.fields.description}
67
+ >
68
+ <div className="flex items-center justify-end gap-2">
69
+ <Badge variant="secondary">{selectedCount} of {fields.length} selected</Badge>
70
+ <Button variant="outline" size="sm" onClick={selectAll}>Select All</Button>
71
+ <Button variant="outline" size="sm" onClick={deselectAll}>Deselect All</Button>
72
+ </div>
73
+
74
+ <Card>
75
+ <CardContent className="p-0">
76
+ <div className="grid grid-cols-12 gap-4 p-4 bg-muted font-medium text-sm">
77
+ <div className="col-span-1">Include</div>
78
+ <div className="col-span-4">Source Field</div>
79
+ <div className="col-span-4">Output Name</div>
80
+ <div className="col-span-3">Transform</div>
81
+ </div>
82
+
83
+ <ScrollArea className={COMPONENT_HEIGHTS.WIZARD_PANE_MD}>
84
+ <div className="divide-y">
85
+ {fields.map((field, index) => (
86
+ <FieldRow
87
+ key={field.sourceField}
88
+ field={field}
89
+ index={index}
90
+ transformTypes={transformTypes}
91
+ onToggle={() => toggleField(index)}
92
+ onUpdate={(updates) => updateField(index, updates)}
93
+ />
94
+ ))}
95
+ </div>
96
+ </ScrollArea>
97
+ </CardContent>
98
+ </Card>
99
+ </WizardStepContainer>
100
+ );
101
+ }
102
+
103
+ interface FieldRowProps {
104
+ field: ExportField;
105
+ index: number;
106
+ transformTypes: ConfigOptionValue[];
107
+ onToggle: () => void;
108
+ onUpdate: (updates: Partial<ExportField>) => void;
109
+ }
110
+
111
+ function FieldRow({ field, index, transformTypes, onToggle, onUpdate }: FieldRowProps) {
112
+ return (
113
+ <div
114
+ className={`grid grid-cols-12 gap-4 p-4 items-center ${
115
+ !field.include ? 'opacity-50' : ''
116
+ }`}
117
+ >
118
+ <div className="col-span-1">
119
+ <Switch
120
+ checked={field.include}
121
+ onCheckedChange={onToggle}
122
+ />
123
+ </div>
124
+
125
+ <div className="col-span-4">
126
+ <code className="text-sm font-mono">{field.sourceField}</code>
127
+ </div>
128
+
129
+ <div className="col-span-4">
130
+ <Input
131
+ value={field.outputName}
132
+ onChange={e => onUpdate({ outputName: e.target.value })}
133
+ disabled={!field.include}
134
+ className="font-mono"
135
+ />
136
+ </div>
137
+
138
+ <div className="col-span-3">
139
+ <Select
140
+ value={field.transformation ?? SENTINEL_VALUES.NONE}
141
+ onValueChange={transformation => onUpdate({
142
+ transformation: transformation === SENTINEL_VALUES.NONE ? undefined : transformation,
143
+ })}
144
+ disabled={!field.include}
145
+ >
146
+ <SelectTrigger>
147
+ <SelectValue placeholder="None" />
148
+ </SelectTrigger>
149
+ <SelectContent>
150
+ <SelectItem value={SENTINEL_VALUES.NONE}>None</SelectItem>
151
+ {transformTypes.map(opt => (
152
+ <SelectItem key={opt.value} value={opt.value}>{opt.label}</SelectItem>
153
+ ))}
154
+ </SelectContent>
155
+ </Select>
156
+ </div>
157
+ </div>
158
+ );
159
+ }
@@ -0,0 +1,246 @@
1
+ import { useCallback, useMemo, memo } from 'react';
2
+ import {
3
+ Card,
4
+ CardContent,
5
+ CardHeader,
6
+ CardTitle,
7
+ } from '@vendure/dashboard';
8
+ import { FileText } from 'lucide-react';
9
+ import { resolveIconName } from '../../../utils/icon-resolver';
10
+ import { WizardStepContainer } from '../shared';
11
+ import { SelectableCard, SelectableCardGrid } from '../../shared/selectable-card';
12
+ import { SchemaFormRenderer } from '../../shared/schema-form';
13
+ import { STEP_CONTENT } from './constants';
14
+ import { useAdaptersByType } from '../../../hooks/api/use-adapters';
15
+ import type { AdapterSchemaField } from '../../../types';
16
+ import type { FeedTemplate } from '../../../types/wizard';
17
+ import type { ExportConfiguration } from './types';
18
+ import type { DataHubAdaptersApiQuery } from '../../../gql/graphql';
19
+
20
+ type AdapterEntry = DataHubAdaptersApiQuery['dataHubAdapters'][number];
21
+
22
+ /** Group identifier used on backend exporter schema fields that represent format options */
23
+ const FORMAT_OPTIONS_GROUP = 'format-options';
24
+
25
+ interface FormatStepProps {
26
+ config: Partial<ExportConfiguration>;
27
+ updateConfig: (updates: Partial<ExportConfiguration>) => void;
28
+ errors?: Record<string, string>;
29
+ }
30
+
31
+ function resolveBaseFormat(adapter: { code: string; formatType?: string | null; description?: string | null }): string {
32
+ // Prefer backend formatType metadata
33
+ if (adapter.formatType) return adapter.formatType;
34
+ // Infer from description as last resort
35
+ if (adapter.description && /\bxml\b/i.test(adapter.description)) return 'XML';
36
+ if (adapter.description && /\bjson\b/i.test(adapter.description)) return 'JSON';
37
+ return 'CSV';
38
+ }
39
+
40
+ /** Derive a wizard format ID from an adapter code */
41
+ function toFormatId(code: string): string {
42
+ return code.replace(/([a-z])([A-Z])/g, '$1_$2').toUpperCase();
43
+ }
44
+
45
+ export function FormatStep({ config, updateConfig, errors = {} }: FormatStepProps) {
46
+ const format = config.format ?? { type: 'CSV', options: {} };
47
+ const { data: exporters } = useAdaptersByType('EXPORTER');
48
+ const { data: feeds } = useAdaptersByType('FEED');
49
+
50
+ // Build format templates dynamically from backend adapter registry
51
+ const formatTemplates = useMemo(() => {
52
+ const templates: FeedTemplate[] = [];
53
+
54
+ // Add feed formats from backend (Google Shopping, Meta, Amazon, etc.)
55
+ if (feeds?.length) {
56
+ for (const feed of feeds) {
57
+ templates.push({
58
+ id: toFormatId(feed.code),
59
+ name: feed.name ?? feed.code,
60
+ icon: resolveIconName(feed.icon) ?? FileText,
61
+ description: feed.description ?? '',
62
+ format: resolveBaseFormat(feed),
63
+ requiredFields: [],
64
+ });
65
+ }
66
+ }
67
+
68
+ // Add standard export formats from backend (CSV, JSON, XML)
69
+ if (exporters?.length) {
70
+ for (const exp of exporters) {
71
+ const formatCode = exp.code.replace(/[Ee]xport/, '');
72
+ templates.push({
73
+ id: `custom-${formatCode.toLowerCase()}`,
74
+ name: exp.name ?? `Custom ${formatCode.toUpperCase()}`,
75
+ icon: resolveIconName(exp.icon) ?? FileText,
76
+ description: exp.description ?? '',
77
+ format: formatCode.toUpperCase(),
78
+ requiredFields: [],
79
+ });
80
+ }
81
+ }
82
+
83
+ return templates;
84
+ }, [exporters, feeds]);
85
+
86
+ return (
87
+ <WizardStepContainer
88
+ title={STEP_CONTENT.format.title}
89
+ description={STEP_CONTENT.format.description}
90
+ >
91
+ <FormatTemplateSelection format={format} updateConfig={updateConfig} templates={formatTemplates} />
92
+ <FormatOptionsCard format={format} updateConfig={updateConfig} templates={formatTemplates} exporters={exporters} />
93
+ </WizardStepContainer>
94
+ );
95
+ }
96
+
97
+ interface FormatTemplateSelectionProps {
98
+ format: ExportConfiguration['format'];
99
+ updateConfig: (updates: Partial<ExportConfiguration>) => void;
100
+ templates: FeedTemplate[];
101
+ }
102
+
103
+ function FormatTemplateSelection({ format, updateConfig, templates }: FormatTemplateSelectionProps) {
104
+ return (
105
+ <SelectableCardGrid columns={3}>
106
+ {templates.map(template => (
107
+ <FormatTemplateCard
108
+ key={template.id}
109
+ template={template}
110
+ format={format}
111
+ updateConfig={updateConfig}
112
+ />
113
+ ))}
114
+ </SelectableCardGrid>
115
+ );
116
+ }
117
+
118
+ interface FormatTemplateCardProps {
119
+ template: FeedTemplate;
120
+ format: ExportConfiguration['format'];
121
+ updateConfig: (updates: Partial<ExportConfiguration>) => void;
122
+ }
123
+
124
+ const FormatTemplateCard = memo(function FormatTemplateCard({
125
+ template,
126
+ format,
127
+ updateConfig,
128
+ }: FormatTemplateCardProps) {
129
+ const isSelected = format.type === template.id ||
130
+ (template.id.startsWith('custom-') && format.type === template.format);
131
+
132
+ const handleClick = useCallback(() => {
133
+ const formatType = template.id.startsWith('custom-')
134
+ ? template.id.replace('custom-', '').toUpperCase()
135
+ : template.id;
136
+ updateConfig({
137
+ format: {
138
+ type: formatType,
139
+ options: {
140
+ ...format.options,
141
+ feedTemplate: template.id.startsWith('custom-') ? undefined : template.id,
142
+ },
143
+ },
144
+ });
145
+ }, [template.id, format.options, updateConfig]);
146
+
147
+ return (
148
+ <SelectableCard
149
+ icon={template.icon}
150
+ title={template.name}
151
+ description={template.description}
152
+ selected={isSelected}
153
+ onClick={handleClick}
154
+ data-testid={`datahub-export-format-${template.id}-btn`}
155
+ />
156
+ );
157
+ });
158
+
159
+ interface FormatOptionsCardProps {
160
+ format: ExportConfiguration['format'];
161
+ updateConfig: (updates: Partial<ExportConfiguration>) => void;
162
+ templates: FeedTemplate[];
163
+ exporters: AdapterEntry[] | undefined;
164
+ }
165
+
166
+ function FormatOptionsCard({ format, updateConfig, templates, exporters }: FormatOptionsCardProps) {
167
+ const selectedTemplate = templates.find(t => t.id === format.type);
168
+ const baseFormat = selectedTemplate?.format ?? format.type;
169
+
170
+ // Schema-driven: find the exporter adapter matching the base format
171
+ // and extract its format-options fields. Strip the group so SchemaFormRenderer
172
+ // does not render a redundant sub-heading (the Card title already says "Format Options").
173
+ // Map GraphQL `defaultValue` to shared `default` so SchemaFormRenderer resolves defaults correctly.
174
+ const formatOptionsSchema = useMemo(() => {
175
+ if (!exporters?.length) return null;
176
+ const matchingExporter = exporters.find(e => e.formatType === baseFormat);
177
+ if (!matchingExporter) return null;
178
+ const formatFields: AdapterSchemaField[] = matchingExporter.schema.fields
179
+ .filter(f => f.group === FORMAT_OPTIONS_GROUP)
180
+ .map(f => ({
181
+ key: f.key,
182
+ label: f.label ?? undefined,
183
+ description: f.description ?? undefined,
184
+ type: f.type as AdapterSchemaField['type'],
185
+ required: f.required ?? undefined,
186
+ default: f.defaultValue ?? undefined,
187
+ options: f.options?.map(o => ({ value: o.value, label: o.label })) ?? undefined,
188
+ placeholder: f.placeholder ?? undefined,
189
+ validation: f.validation ? {
190
+ min: f.validation.min ?? undefined,
191
+ max: f.validation.max ?? undefined,
192
+ minLength: f.validation.minLength ?? undefined,
193
+ maxLength: f.validation.maxLength ?? undefined,
194
+ pattern: f.validation.pattern ?? undefined,
195
+ patternMessage: f.validation.patternMessage ?? undefined,
196
+ } : undefined,
197
+ dependsOn: f.dependsOn ? {
198
+ field: f.dependsOn.field,
199
+ value: f.dependsOn.value ?? undefined,
200
+ operator: f.dependsOn.operator as NonNullable<AdapterSchemaField['dependsOn']>['operator'],
201
+ } : undefined,
202
+ }));
203
+ if (formatFields.length === 0) return null;
204
+ return { fields: formatFields };
205
+ }, [exporters, baseFormat]);
206
+
207
+ const handleSchemaChange = useCallback((values: Record<string, unknown>) => {
208
+ updateConfig({
209
+ format: { ...format, options: { ...format.options, ...values } },
210
+ });
211
+ }, [format, updateConfig]);
212
+
213
+ // Build current values from format.options for the schema fields,
214
+ // falling back to the schema field's defaultValue when no user value exists.
215
+ const schemaValues = useMemo(() => {
216
+ if (!formatOptionsSchema) return {};
217
+ const values: Record<string, unknown> = {};
218
+ for (const field of formatOptionsSchema.fields) {
219
+ const val = (format.options as Record<string, unknown>)[field.key];
220
+ values[field.key] = val ?? field.default;
221
+ }
222
+ return values;
223
+ }, [formatOptionsSchema, format.options]);
224
+
225
+ return (
226
+ <Card>
227
+ <CardHeader>
228
+ <CardTitle>Format Options</CardTitle>
229
+ </CardHeader>
230
+ <CardContent className="space-y-4">
231
+ {formatOptionsSchema ? (
232
+ <SchemaFormRenderer
233
+ schema={formatOptionsSchema}
234
+ values={schemaValues}
235
+ onChange={handleSchemaChange}
236
+ compact
237
+ />
238
+ ) : (
239
+ <p className="text-sm text-muted-foreground">
240
+ No format-specific options available for this export type.
241
+ </p>
242
+ )}
243
+ </CardContent>
244
+ </Card>
245
+ );
246
+ }