@oronts/vendure-data-hub-plugin 0.1.1 → 0.1.2
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/CHANGELOG.md +5 -0
- package/dist/dashboard/components/common/ConnectionConfigEditor.tsx +589 -0
- package/dist/dashboard/components/common/HeadersEditor.tsx +90 -0
- package/dist/dashboard/components/common/ValidationFeedback.tsx +17 -0
- package/dist/dashboard/components/common/index.ts +10 -0
- package/dist/dashboard/components/pipelines/PipelineEditor.tsx +504 -0
- package/dist/dashboard/components/pipelines/PipelineExport.tsx +63 -0
- package/dist/dashboard/components/pipelines/PipelineImport.tsx +87 -0
- package/dist/dashboard/components/pipelines/ReactFlowPipelineEditor.tsx +539 -0
- package/dist/dashboard/components/pipelines/shared/NodePropertiesPanel.tsx +146 -0
- package/dist/dashboard/components/pipelines/shared/PipelineNode.tsx +155 -0
- package/dist/dashboard/components/pipelines/shared/PipelineSettingsPanel.tsx +392 -0
- package/dist/dashboard/components/pipelines/shared/StepListItem.tsx +144 -0
- package/dist/dashboard/components/pipelines/shared/index.ts +33 -0
- package/dist/dashboard/components/pipelines/shared/visual-node-config.ts +169 -0
- package/dist/dashboard/components/shared/LoadMoreButton.tsx +18 -0
- package/dist/dashboard/components/shared/entity-selector/EntitySelector.tsx +59 -0
- package/dist/dashboard/components/shared/entity-selector/index.ts +1 -0
- package/dist/dashboard/components/shared/error-boundary/ErrorBoundary.tsx +90 -0
- package/dist/dashboard/components/shared/error-boundary/index.ts +1 -0
- package/dist/dashboard/components/shared/feedback/EmptyState.tsx +36 -0
- package/dist/dashboard/components/shared/feedback/ErrorState.tsx +69 -0
- package/dist/dashboard/components/shared/feedback/LoadingState.tsx +104 -0
- package/dist/dashboard/components/shared/feedback/ValidationErrorDisplay.tsx +29 -0
- package/dist/dashboard/components/shared/feedback/index.ts +4 -0
- package/dist/dashboard/components/shared/file-dropzone/FileDropzone.tsx +167 -0
- package/dist/dashboard/components/shared/file-dropzone/index.ts +1 -0
- package/dist/dashboard/components/shared/filter-conditions-editor/FilterConditionsEditor.tsx +226 -0
- package/dist/dashboard/components/shared/filter-conditions-editor/index.ts +1 -0
- package/dist/dashboard/components/shared/index.ts +45 -0
- package/dist/dashboard/components/shared/schema-form/SchemaFormRenderer.tsx +248 -0
- package/dist/dashboard/components/shared/schema-form/fields/BooleanField.tsx +26 -0
- package/dist/dashboard/components/shared/schema-form/fields/FieldWrapper.tsx +28 -0
- package/dist/dashboard/components/shared/schema-form/fields/FileUploadField.tsx +171 -0
- package/dist/dashboard/components/shared/schema-form/fields/JsonField.tsx +132 -0
- package/dist/dashboard/components/shared/schema-form/fields/NumberField.tsx +33 -0
- package/dist/dashboard/components/shared/schema-form/fields/SelectField.tsx +70 -0
- package/dist/dashboard/components/shared/schema-form/fields/StringField.tsx +36 -0
- package/dist/dashboard/components/shared/schema-form/fields/TextareaField.tsx +31 -0
- package/dist/dashboard/components/shared/schema-form/fields/index.ts +23 -0
- package/dist/dashboard/components/shared/schema-form/index.ts +2 -0
- package/dist/dashboard/components/shared/schema-form/utils.ts +3 -0
- package/dist/dashboard/components/shared/selectable-card/SelectableCard.tsx +65 -0
- package/dist/dashboard/components/shared/selectable-card/index.ts +1 -0
- package/dist/dashboard/components/shared/stat-card/StatCard.tsx +121 -0
- package/dist/dashboard/components/shared/stat-card/index.ts +1 -0
- package/dist/dashboard/components/shared/step-config/AdapterRequiredWarning.tsx +25 -0
- package/dist/dashboard/components/shared/step-config/AdapterSelector.tsx +109 -0
- package/dist/dashboard/components/shared/step-config/AdvancedEditors.tsx +634 -0
- package/dist/dashboard/components/shared/step-config/EnrichConfigComponent.tsx +295 -0
- package/dist/dashboard/components/shared/step-config/ExtractTestResults.tsx +143 -0
- package/dist/dashboard/components/shared/step-config/GateConfigComponent.tsx +127 -0
- package/dist/dashboard/components/shared/step-config/LoadTestResults.tsx +104 -0
- package/dist/dashboard/components/shared/step-config/OperatorCard.tsx +266 -0
- package/dist/dashboard/components/shared/step-config/OperatorCheatSheetButton.tsx +54 -0
- package/dist/dashboard/components/shared/step-config/OperatorFieldInput.tsx +209 -0
- package/dist/dashboard/components/shared/step-config/RetrySettingsComponent.tsx +111 -0
- package/dist/dashboard/components/shared/step-config/RouteConfigComponent.tsx +125 -0
- package/dist/dashboard/components/shared/step-config/StepConfigPanel.tsx +564 -0
- package/dist/dashboard/components/shared/step-config/StepTester.tsx +165 -0
- package/dist/dashboard/components/shared/step-config/TestResultContainer.tsx +57 -0
- package/dist/dashboard/components/shared/step-config/TransformTestResults.tsx +130 -0
- package/dist/dashboard/components/shared/step-config/ValidateConfigComponent.tsx +334 -0
- package/dist/dashboard/components/shared/step-config/index.ts +29 -0
- package/dist/dashboard/components/shared/step-config/step-test-handlers.ts +297 -0
- package/dist/dashboard/components/shared/trigger-config/TriggerForm.tsx +478 -0
- package/dist/dashboard/components/shared/trigger-config/index.ts +1 -0
- package/dist/dashboard/components/shared/triggers-panel/TriggersPanel.tsx +281 -0
- package/dist/dashboard/components/shared/triggers-panel/index.ts +1 -0
- package/dist/dashboard/components/shared/wizard/ConfigurationNameCard.tsx +59 -0
- package/dist/dashboard/components/shared/wizard/SummaryCard.tsx +53 -0
- package/dist/dashboard/components/shared/wizard/WizardFooter.tsx +47 -0
- package/dist/dashboard/components/shared/wizard/WizardProgressBar.tsx +78 -0
- package/dist/dashboard/components/shared/wizard/index.ts +4 -0
- package/dist/dashboard/components/shared/wizard-trigger/TriggerSchemaFields.tsx +128 -0
- package/dist/dashboard/components/shared/wizard-trigger/TriggerSelector.tsx +33 -0
- package/dist/dashboard/components/shared/wizard-trigger/index.ts +2 -0
- package/dist/dashboard/components/templates/TemplateGallery.tsx +210 -0
- package/dist/dashboard/components/templates/TemplatePreview.tsx +214 -0
- package/dist/dashboard/components/templates/index.ts +4 -0
- package/dist/dashboard/components/wizards/export-wizard/DestinationStep.tsx +207 -0
- package/dist/dashboard/components/wizards/export-wizard/ExportWizard.tsx +221 -0
- package/dist/dashboard/components/wizards/export-wizard/FieldsStep.tsx +159 -0
- package/dist/dashboard/components/wizards/export-wizard/FormatStep.tsx +246 -0
- package/dist/dashboard/components/wizards/export-wizard/ReviewStep.tsx +231 -0
- package/dist/dashboard/components/wizards/export-wizard/SourceStep.tsx +154 -0
- package/dist/dashboard/components/wizards/export-wizard/TriggerStep.tsx +234 -0
- package/dist/dashboard/components/wizards/export-wizard/constants.ts +73 -0
- package/dist/dashboard/components/wizards/export-wizard/index.ts +2 -0
- package/dist/dashboard/components/wizards/export-wizard/types.ts +39 -0
- package/dist/dashboard/components/wizards/import-wizard/ImportWizard.tsx +350 -0
- package/dist/dashboard/components/wizards/import-wizard/MappingStep.tsx +286 -0
- package/dist/dashboard/components/wizards/import-wizard/PreviewStep.tsx +79 -0
- package/dist/dashboard/components/wizards/import-wizard/ReviewStep.tsx +266 -0
- package/dist/dashboard/components/wizards/import-wizard/SourceStep.tsx +537 -0
- package/dist/dashboard/components/wizards/import-wizard/StrategyStep.tsx +328 -0
- package/dist/dashboard/components/wizards/import-wizard/TargetStep.tsx +76 -0
- package/dist/dashboard/components/wizards/import-wizard/TemplateStep.tsx +116 -0
- package/dist/dashboard/components/wizards/import-wizard/TransformStep.tsx +666 -0
- package/dist/dashboard/components/wizards/import-wizard/TriggerStep.tsx +51 -0
- package/dist/dashboard/components/wizards/import-wizard/constants.ts +104 -0
- package/dist/dashboard/components/wizards/import-wizard/index.ts +3 -0
- package/dist/dashboard/components/wizards/import-wizard/types.ts +35 -0
- package/dist/dashboard/components/wizards/index.ts +7 -0
- package/dist/dashboard/components/wizards/shared/WizardStepContainer.tsx +27 -0
- package/dist/dashboard/components/wizards/shared/constants.ts +16 -0
- package/dist/dashboard/components/wizards/shared/index.ts +10 -0
- package/dist/dashboard/constants/colors.ts +25 -0
- package/dist/dashboard/constants/connection-defaults.ts +7 -0
- package/dist/dashboard/constants/connection-types.ts +1 -0
- package/dist/dashboard/constants/defaults.ts +18 -0
- package/dist/dashboard/constants/editor.ts +69 -0
- package/dist/dashboard/constants/enum-maps.ts +18 -0
- package/dist/dashboard/constants/fallbacks.ts +44 -0
- package/dist/dashboard/constants/file-format-registry.ts +206 -0
- package/dist/dashboard/constants/index.ts +24 -0
- package/dist/dashboard/constants/navigation.ts +29 -0
- package/dist/dashboard/constants/permissions.ts +41 -0
- package/dist/dashboard/constants/placeholders.ts +77 -0
- package/dist/dashboard/constants/routes.ts +12 -0
- package/dist/dashboard/constants/run-status.ts +1 -0
- package/dist/dashboard/constants/sentinel-values.ts +12 -0
- package/dist/dashboard/constants/step-configs.ts +9 -0
- package/dist/dashboard/constants/step-mappings.ts +170 -0
- package/dist/dashboard/constants/steps.ts +37 -0
- package/dist/dashboard/constants/toast-messages.ts +149 -0
- package/dist/dashboard/constants/triggers.ts +5 -0
- package/dist/dashboard/constants/ui-config.ts +139 -0
- package/dist/dashboard/constants/ui-dimensions.ts +145 -0
- package/dist/dashboard/constants/ui-states.ts +28 -0
- package/dist/dashboard/constants/ui-types.ts +85 -0
- package/dist/dashboard/constants/validation-patterns.ts +26 -0
- package/dist/dashboard/gql/gql.ts +370 -0
- package/dist/dashboard/gql/graphql.ts +10378 -0
- package/dist/dashboard/gql/index.ts +1 -0
- package/dist/dashboard/hooks/api/index.ts +115 -0
- package/dist/dashboard/hooks/api/mutation-helpers.ts +34 -0
- package/dist/dashboard/hooks/api/use-adapters.ts +92 -0
- package/dist/dashboard/hooks/api/use-config-options.ts +513 -0
- package/dist/dashboard/hooks/api/use-connections.ts +84 -0
- package/dist/dashboard/hooks/api/use-entity-field-schemas.ts +99 -0
- package/dist/dashboard/hooks/api/use-entity-loaders.ts +45 -0
- package/dist/dashboard/hooks/api/use-hooks.ts +68 -0
- package/dist/dashboard/hooks/api/use-logs.ts +102 -0
- package/dist/dashboard/hooks/api/use-pipeline-runs.ts +221 -0
- package/dist/dashboard/hooks/api/use-pipelines.ts +279 -0
- package/dist/dashboard/hooks/api/use-queues.ts +141 -0
- package/dist/dashboard/hooks/api/use-secrets.ts +75 -0
- package/dist/dashboard/hooks/api/use-settings.ts +55 -0
- package/dist/dashboard/hooks/api/use-step-tester.ts +79 -0
- package/dist/dashboard/hooks/index.ts +13 -0
- package/dist/dashboard/hooks/use-adapter-catalog.ts +253 -0
- package/dist/dashboard/hooks/use-export-templates.ts +80 -0
- package/dist/dashboard/hooks/use-import-templates.ts +139 -0
- package/dist/dashboard/hooks/use-load-more.ts +29 -0
- package/dist/dashboard/hooks/use-stable-keys.ts +54 -0
- package/dist/dashboard/hooks/use-trigger-types.ts +100 -0
- package/dist/dashboard/hooks/use-wizard-navigation.ts +128 -0
- package/dist/dashboard/index.tsx +55 -0
- package/dist/dashboard/routes/adapters/AdapterCard.tsx +102 -0
- package/dist/dashboard/routes/adapters/AdapterConstants.tsx +20 -0
- package/dist/dashboard/routes/adapters/AdapterDetail.tsx +208 -0
- package/dist/dashboard/routes/adapters/AdapterTypeSection.tsx +105 -0
- package/dist/dashboard/routes/adapters/AdaptersPage.tsx +276 -0
- package/dist/dashboard/routes/adapters/AdaptersTable.tsx +107 -0
- package/dist/dashboard/routes/adapters/index.ts +1 -0
- package/dist/dashboard/routes/connections/ConnectionDetail.tsx +218 -0
- package/dist/dashboard/routes/connections/ConnectionsList.tsx +34 -0
- package/dist/dashboard/routes/connections/index.ts +2 -0
- package/dist/dashboard/routes/hooks/Hooks.tsx +425 -0
- package/dist/dashboard/routes/hooks/hook-stages.ts +52 -0
- package/dist/dashboard/routes/hooks/index.ts +1 -0
- package/dist/dashboard/routes/index.ts +8 -0
- package/dist/dashboard/routes/logs/Logs.tsx +93 -0
- package/dist/dashboard/routes/logs/components/LogDetailDrawer.tsx +118 -0
- package/dist/dashboard/routes/logs/components/LogExplorerTab.tsx +367 -0
- package/dist/dashboard/routes/logs/components/LogLevelBadge.tsx +34 -0
- package/dist/dashboard/routes/logs/components/LogTableRow.tsx +70 -0
- package/dist/dashboard/routes/logs/components/LogsOverviewTab.tsx +178 -0
- package/dist/dashboard/routes/logs/components/RealtimeLogTab.tsx +122 -0
- package/dist/dashboard/routes/logs/index.ts +1 -0
- package/dist/dashboard/routes/pipelines/ErrorAuditList.tsx +39 -0
- package/dist/dashboard/routes/pipelines/ExportWizardPage.tsx +96 -0
- package/dist/dashboard/routes/pipelines/ImportWizardPage.tsx +104 -0
- package/dist/dashboard/routes/pipelines/PipelineDetail.tsx +211 -0
- package/dist/dashboard/routes/pipelines/PipelineRunsBlock.tsx +377 -0
- package/dist/dashboard/routes/pipelines/PipelinesList.tsx +87 -0
- package/dist/dashboard/routes/pipelines/RetryPatchHelper.tsx +51 -0
- package/dist/dashboard/routes/pipelines/RunDetailsPanel.tsx +238 -0
- package/dist/dashboard/routes/pipelines/RunErrorsList.tsx +116 -0
- package/dist/dashboard/routes/pipelines/StepCounters.tsx +24 -0
- package/dist/dashboard/routes/pipelines/StepSummaryTable.tsx +36 -0
- package/dist/dashboard/routes/pipelines/components/DryRunDialog.tsx +341 -0
- package/dist/dashboard/routes/pipelines/components/PipelineActionButtons.tsx +201 -0
- package/dist/dashboard/routes/pipelines/components/PipelineEditorToggle.tsx +116 -0
- package/dist/dashboard/routes/pipelines/components/PipelineFormFields.tsx +156 -0
- package/dist/dashboard/routes/pipelines/components/PipelineWebhookInfo.tsx +111 -0
- package/dist/dashboard/routes/pipelines/components/ReviewActionsPanel.tsx +342 -0
- package/dist/dashboard/routes/pipelines/components/ValidationPanel.tsx +121 -0
- package/dist/dashboard/routes/pipelines/components/VersionHistoryDialog.tsx +131 -0
- package/dist/dashboard/routes/pipelines/components/index.ts +25 -0
- package/dist/dashboard/routes/pipelines/hooks/index.ts +1 -0
- package/dist/dashboard/routes/pipelines/hooks/use-pipeline-validation.ts +114 -0
- package/dist/dashboard/routes/pipelines/index.ts +4 -0
- package/dist/dashboard/routes/pipelines/utils/index.ts +1 -0
- package/dist/dashboard/routes/pipelines/utils/pipeline-conversion.ts +261 -0
- package/dist/dashboard/routes/queues/ConsumersTable.tsx +134 -0
- package/dist/dashboard/routes/queues/DeadLettersTable.tsx +118 -0
- package/dist/dashboard/routes/queues/FailedRunsTable.tsx +74 -0
- package/dist/dashboard/routes/queues/QueuesPage.tsx +290 -0
- package/dist/dashboard/routes/queues/index.ts +1 -0
- package/dist/dashboard/routes/queues/types.ts +22 -0
- package/dist/dashboard/routes/secrets/SecretDetail.tsx +278 -0
- package/dist/dashboard/routes/secrets/SecretsList.tsx +34 -0
- package/dist/dashboard/routes/secrets/index.ts +2 -0
- package/dist/dashboard/routes/settings/Settings.tsx +343 -0
- package/dist/dashboard/routes/settings/index.ts +1 -0
- package/dist/dashboard/types/index.ts +89 -0
- package/dist/dashboard/types/pipeline.ts +51 -0
- package/dist/dashboard/types/ui-types.ts +400 -0
- package/dist/dashboard/types/wizard.ts +235 -0
- package/dist/dashboard/utils/adapter-grouping.ts +43 -0
- package/dist/dashboard/utils/column-analysis.ts +11 -0
- package/dist/dashboard/utils/field-preparation.ts +31 -0
- package/dist/dashboard/utils/form-validation.ts +373 -0
- package/dist/dashboard/utils/formatters.ts +92 -0
- package/dist/dashboard/utils/icon-resolver.ts +35 -0
- package/dist/dashboard/utils/index.ts +60 -0
- package/dist/dashboard/utils/query-key-factory.ts +54 -0
- package/dist/dashboard/utils/step-helpers.ts +32 -0
- package/dist/dashboard/utils/string-helpers.ts +4 -0
- package/dist/dashboard/utils/template-helpers.ts +26 -0
- package/dist/dashboard/utils/trigger-sync.ts +138 -0
- package/dist/dashboard/utils/wizard-to-pipeline.ts +569 -0
- package/package.json +2 -2
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import type { ImportConfiguration } from './types';
|
|
2
|
+
import { TRIGGER_TYPE, LOADING_STATE_TYPE } from '../../../constants';
|
|
3
|
+
import { useTriggerTypes } from '../../../hooks';
|
|
4
|
+
import { WizardStepContainer } from '../shared';
|
|
5
|
+
import { TriggerSelector, TriggerSchemaFields } from '../../shared/wizard-trigger';
|
|
6
|
+
import { LoadingState } from '../../shared/feedback';
|
|
7
|
+
import { STEP_CONTENT } from './constants';
|
|
8
|
+
|
|
9
|
+
interface TriggerStepProps {
|
|
10
|
+
config: Partial<ImportConfiguration>;
|
|
11
|
+
updateConfig: (updates: Partial<ImportConfiguration>) => void;
|
|
12
|
+
errors?: Record<string, string>;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function TriggerStep({ config, updateConfig, errors = {} }: TriggerStepProps) {
|
|
16
|
+
const trigger = config.trigger ?? { type: TRIGGER_TYPE.MANUAL };
|
|
17
|
+
const { importWizardTriggers, triggerSchemas, isLoading } = useTriggerTypes();
|
|
18
|
+
|
|
19
|
+
const currentSchema = triggerSchemas.find(s => s.value === trigger.type);
|
|
20
|
+
|
|
21
|
+
const handleTriggerTypeChange = (type: string) => {
|
|
22
|
+
updateConfig({ trigger: { ...trigger, type: type as typeof trigger.type } });
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
const handleFieldChange = (key: string, value: unknown) => {
|
|
26
|
+
updateConfig({ trigger: { ...trigger, [key]: value } });
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
return (
|
|
30
|
+
<WizardStepContainer
|
|
31
|
+
title={STEP_CONTENT.trigger.title}
|
|
32
|
+
description={STEP_CONTENT.trigger.description}
|
|
33
|
+
>
|
|
34
|
+
<TriggerSelector
|
|
35
|
+
options={importWizardTriggers}
|
|
36
|
+
value={trigger.type}
|
|
37
|
+
onChange={handleTriggerTypeChange}
|
|
38
|
+
/>
|
|
39
|
+
|
|
40
|
+
{currentSchema && currentSchema.fields.length > 0 ? (
|
|
41
|
+
<TriggerSchemaFields
|
|
42
|
+
fields={currentSchema.fields}
|
|
43
|
+
values={trigger as Record<string, unknown>}
|
|
44
|
+
onChange={handleFieldChange}
|
|
45
|
+
/>
|
|
46
|
+
) : isLoading && trigger.type !== TRIGGER_TYPE.MANUAL ? (
|
|
47
|
+
<LoadingState type={LOADING_STATE_TYPE.FORM} rows={2} message="" />
|
|
48
|
+
) : null}
|
|
49
|
+
</WizardStepContainer>
|
|
50
|
+
);
|
|
51
|
+
}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Database,
|
|
3
|
+
Eye,
|
|
4
|
+
Table,
|
|
5
|
+
Columns,
|
|
6
|
+
Zap,
|
|
7
|
+
Settings,
|
|
8
|
+
Clock,
|
|
9
|
+
Check,
|
|
10
|
+
LayoutTemplate,
|
|
11
|
+
} from 'lucide-react';
|
|
12
|
+
import type { WizardStep, ImportStrategies } from '../../../types/wizard';
|
|
13
|
+
import { CLEANUP_STRATEGY, BATCH_SIZES, UI_DEFAULTS } from '../../../constants';
|
|
14
|
+
|
|
15
|
+
export const IMPORT_STEP_ID = {
|
|
16
|
+
TEMPLATE: 'template',
|
|
17
|
+
SOURCE: 'source',
|
|
18
|
+
PREVIEW: 'preview',
|
|
19
|
+
TARGET: 'target',
|
|
20
|
+
MAPPING: 'mapping',
|
|
21
|
+
TRANSFORM: 'transform',
|
|
22
|
+
STRATEGY: 'strategy',
|
|
23
|
+
TRIGGER: 'trigger',
|
|
24
|
+
REVIEW: 'review',
|
|
25
|
+
} as const;
|
|
26
|
+
|
|
27
|
+
export type {
|
|
28
|
+
TransformTypeOption,
|
|
29
|
+
} from '../shared';
|
|
30
|
+
|
|
31
|
+
export const WIZARD_STEPS: WizardStep[] = [
|
|
32
|
+
{ id: 'template', label: 'Choose Template', icon: LayoutTemplate },
|
|
33
|
+
{ id: 'source', label: 'Data Source', icon: Database },
|
|
34
|
+
{ id: 'preview', label: 'Preview Data', icon: Eye },
|
|
35
|
+
{ id: 'target', label: 'Target Entity', icon: Table },
|
|
36
|
+
{ id: 'mapping', label: 'Field Mapping', icon: Columns },
|
|
37
|
+
{ id: 'transform', label: 'Transformations', icon: Zap },
|
|
38
|
+
{ id: 'strategy', label: 'Import Strategy', icon: Settings },
|
|
39
|
+
{ id: 'trigger', label: 'Trigger & Schedule', icon: Clock },
|
|
40
|
+
{ id: 'review', label: 'Review & Create', icon: Check },
|
|
41
|
+
];
|
|
42
|
+
|
|
43
|
+
/** Steps to show when using a template (skips template selection) */
|
|
44
|
+
export const WIZARD_STEPS_FROM_TEMPLATE: WizardStep[] = WIZARD_STEPS.slice(1);
|
|
45
|
+
|
|
46
|
+
export const STEP_CONTENT = {
|
|
47
|
+
template: {
|
|
48
|
+
title: 'Choose a Template',
|
|
49
|
+
description: 'Start with a pre-built template or create your own custom import',
|
|
50
|
+
},
|
|
51
|
+
source: {
|
|
52
|
+
title: 'Select Data Source',
|
|
53
|
+
description: 'Choose where your data will come from',
|
|
54
|
+
},
|
|
55
|
+
preview: {
|
|
56
|
+
title: 'Data Preview',
|
|
57
|
+
emptyTitle: 'No data to preview',
|
|
58
|
+
emptyDescription: 'Please upload a file first.',
|
|
59
|
+
},
|
|
60
|
+
target: {
|
|
61
|
+
title: 'Select Target Entity',
|
|
62
|
+
description: 'Choose which Vendure entity to import data into',
|
|
63
|
+
},
|
|
64
|
+
mapping: {
|
|
65
|
+
title: 'Field Mapping',
|
|
66
|
+
description: 'Map source fields to target entity fields',
|
|
67
|
+
},
|
|
68
|
+
transform: {
|
|
69
|
+
title: 'Data Transformations',
|
|
70
|
+
description: 'Add transformations to process data before import (optional)',
|
|
71
|
+
emptyTitle: 'No transformations added',
|
|
72
|
+
emptyDescription: 'Click a transformation type above to add it to the pipeline',
|
|
73
|
+
},
|
|
74
|
+
strategy: {
|
|
75
|
+
title: 'Import Strategy',
|
|
76
|
+
description: 'Configure how to handle existing and new records',
|
|
77
|
+
},
|
|
78
|
+
trigger: {
|
|
79
|
+
title: 'Trigger & Schedule',
|
|
80
|
+
description: 'Configure when and how the import should run',
|
|
81
|
+
},
|
|
82
|
+
review: {
|
|
83
|
+
title: 'Review & Create',
|
|
84
|
+
description: 'Review your import configuration before creating',
|
|
85
|
+
cardTitle: 'Import Configuration',
|
|
86
|
+
},
|
|
87
|
+
} as const;
|
|
88
|
+
|
|
89
|
+
export const IMPORT_PLACEHOLDERS = {
|
|
90
|
+
apiUrl: 'https://api.example.com/data',
|
|
91
|
+
configName: 'My Product Import',
|
|
92
|
+
} as const;
|
|
93
|
+
|
|
94
|
+
export const DEFAULT_IMPORT_STRATEGIES: ImportStrategies = {
|
|
95
|
+
existingRecords: 'UPDATE',
|
|
96
|
+
lookupFields: [],
|
|
97
|
+
newRecords: 'CREATE',
|
|
98
|
+
publishAfterImport: false,
|
|
99
|
+
cleanupStrategy: CLEANUP_STRATEGY.NONE,
|
|
100
|
+
batchSize: BATCH_SIZES.IMPORT_DEFAULT,
|
|
101
|
+
parallelBatches: 1,
|
|
102
|
+
errorThreshold: UI_DEFAULTS.DEFAULT_ERROR_THRESHOLD_PERCENT,
|
|
103
|
+
continueOnError: true,
|
|
104
|
+
};
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { EnhancedSchemaDefinition, TransformationType } from '../../../types';
|
|
2
|
+
import type {
|
|
3
|
+
ImportFieldMapping,
|
|
4
|
+
ImportStrategies,
|
|
5
|
+
ImportSourceConfig,
|
|
6
|
+
ImportTriggerConfig,
|
|
7
|
+
WizardTransformationStep,
|
|
8
|
+
} from '../../../types/wizard';
|
|
9
|
+
|
|
10
|
+
export type SourceType = ImportSourceConfig['type'];
|
|
11
|
+
export type FileFormat = NonNullable<ImportSourceConfig['fileConfig']>['format'];
|
|
12
|
+
export type ApiMethod = NonNullable<ImportSourceConfig['apiConfig']>['method'];
|
|
13
|
+
|
|
14
|
+
export interface ImportWizardProps {
|
|
15
|
+
onComplete: (config: ImportConfiguration) => void;
|
|
16
|
+
onCancel: () => void;
|
|
17
|
+
initialConfig?: Partial<ImportConfiguration>;
|
|
18
|
+
isSubmitting?: boolean;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export interface ImportConfiguration {
|
|
22
|
+
name: string;
|
|
23
|
+
description?: string;
|
|
24
|
+
source: ImportSourceConfig;
|
|
25
|
+
targetEntity: string;
|
|
26
|
+
targetSchema?: EnhancedSchemaDefinition;
|
|
27
|
+
mappings: ImportFieldMapping[];
|
|
28
|
+
strategies: ImportStrategies;
|
|
29
|
+
trigger: ImportTriggerConfig;
|
|
30
|
+
transformations: WizardTransformationStep[];
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export type { ImportFieldMapping as FieldMapping };
|
|
34
|
+
export type { ImportStrategies };
|
|
35
|
+
export type { TransformationType };
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export { ImportWizard, TemplateStep } from './import-wizard';
|
|
2
|
+
export type { ImportConfiguration } from './import-wizard';
|
|
3
|
+
|
|
4
|
+
export { ExportWizard } from './export-wizard';
|
|
5
|
+
export type { ExportConfiguration } from './export-wizard';
|
|
6
|
+
|
|
7
|
+
export { WizardStepContainer } from './shared';
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
|
|
3
|
+
export interface WizardStepContainerProps {
|
|
4
|
+
title: string;
|
|
5
|
+
description?: string;
|
|
6
|
+
children: React.ReactNode;
|
|
7
|
+
className?: string;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export function WizardStepContainer({
|
|
11
|
+
title,
|
|
12
|
+
description,
|
|
13
|
+
children,
|
|
14
|
+
className = '',
|
|
15
|
+
}: WizardStepContainerProps) {
|
|
16
|
+
return (
|
|
17
|
+
<div className={`max-w-4xl mx-auto space-y-4 ${className}`}>
|
|
18
|
+
<div>
|
|
19
|
+
<h2 className="text-lg font-semibold mb-1">{title}</h2>
|
|
20
|
+
{description && (
|
|
21
|
+
<p className="text-sm text-muted-foreground">{description}</p>
|
|
22
|
+
)}
|
|
23
|
+
</div>
|
|
24
|
+
{children}
|
|
25
|
+
</div>
|
|
26
|
+
);
|
|
27
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared constants for import/export wizards.
|
|
3
|
+
*
|
|
4
|
+
* Icon mappings for source types and file formats have been removed.
|
|
5
|
+
* Source type icons (DATABASE, WEBHOOK, CDC, etc.) now come from backend
|
|
6
|
+
* adapter metadata via resolveIconName(). Smart-source icons (FILE, API)
|
|
7
|
+
* live in SourceStep.tsx since they are hand-built UI types, not adapters.
|
|
8
|
+
* File format icons now come from backend config options (fileFormats.icon).
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
export {
|
|
12
|
+
FILE_FORMAT,
|
|
13
|
+
SOURCE_TYPE,
|
|
14
|
+
} from '../../../constants';
|
|
15
|
+
|
|
16
|
+
export type { TransformTypeOption } from '../../../constants/fallbacks';
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
const LOG_LEVEL_COLORS = {
|
|
2
|
+
debug: 'bg-gray-100 dark:bg-gray-800 text-gray-600 dark:text-gray-300',
|
|
3
|
+
info: 'bg-blue-100 dark:bg-blue-900/40 text-blue-600 dark:text-blue-400',
|
|
4
|
+
warn: 'bg-amber-100 dark:bg-amber-900/40 text-amber-600 dark:text-amber-400',
|
|
5
|
+
error: 'bg-red-100 dark:bg-red-900/40 text-red-600 dark:text-red-400',
|
|
6
|
+
} as const;
|
|
7
|
+
|
|
8
|
+
export const FALLBACK_COLORS = {
|
|
9
|
+
MUTED: '#6b7280',
|
|
10
|
+
BORDER: '#e5e7eb',
|
|
11
|
+
UNKNOWN_STEP_COLOR: '#666666',
|
|
12
|
+
UNKNOWN_STEP_BG: '#f5f5f5',
|
|
13
|
+
UNKNOWN_STEP_BORDER: '#cccccc',
|
|
14
|
+
} as const;
|
|
15
|
+
|
|
16
|
+
export const BRANCH_COLORS = {
|
|
17
|
+
TRUE: '#22c55e',
|
|
18
|
+
FALSE: '#ef4444',
|
|
19
|
+
} as const;
|
|
20
|
+
|
|
21
|
+
export function getLogLevelColor(level: string): string {
|
|
22
|
+
const key = level.toLowerCase() as keyof typeof LOG_LEVEL_COLORS;
|
|
23
|
+
return LOG_LEVEL_COLORS[key] ?? LOG_LEVEL_COLORS.info;
|
|
24
|
+
}
|
|
25
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { CONNECTION_TYPE } from '../../shared/constants';
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dashboard constants - imports shared constants to avoid duplication.
|
|
3
|
+
* The shared folder can be used by both dashboard and backend.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Shared constants - re-exported from shared folder
|
|
8
|
+
* These are used by both dashboard and backend for consistency
|
|
9
|
+
*/
|
|
10
|
+
export {
|
|
11
|
+
TIME_UNITS,
|
|
12
|
+
PORTS,
|
|
13
|
+
HTTP,
|
|
14
|
+
BATCH,
|
|
15
|
+
RETENTION,
|
|
16
|
+
UI_TIMEOUTS,
|
|
17
|
+
} from '../../shared/constants';
|
|
18
|
+
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { PORTS, HTTP, BATCH, UI_TIMEOUTS, TIME_UNITS } from './defaults';
|
|
2
|
+
|
|
3
|
+
export const NODE_LAYOUT = {
|
|
4
|
+
INITIAL_X: 120,
|
|
5
|
+
INITIAL_Y: 120,
|
|
6
|
+
SPACING_X: 280,
|
|
7
|
+
SPACING_Y: 140,
|
|
8
|
+
} as const;
|
|
9
|
+
|
|
10
|
+
export const UI_DEFAULTS = {
|
|
11
|
+
PAGE_SIZE: 100,
|
|
12
|
+
LOG_EXPLORER_PAGE_SIZE: 50,
|
|
13
|
+
PIPELINE_STATS_DISPLAY_COUNT: 6,
|
|
14
|
+
EVENT_DISPLAY_LIMIT: 20,
|
|
15
|
+
RECENT_LOGS_LIMIT: 50,
|
|
16
|
+
RECENT_ACTIVITY_LIMIT: 10,
|
|
17
|
+
EVENTS_LIMIT: 50,
|
|
18
|
+
AUTO_REFRESH_INTERVAL_MS: 10_000,
|
|
19
|
+
COPY_FEEDBACK_TIMEOUT_MS: UI_TIMEOUTS.COPY_FEEDBACK_MS,
|
|
20
|
+
PREVIEW_ROWS: 10,
|
|
21
|
+
IMPORT_PREVIEW_ROWS: 100,
|
|
22
|
+
EXPORT_BATCH_SIZE: BATCH.EXPORT_BATCH_SIZE,
|
|
23
|
+
IMPORT_BATCH_SIZE: BATCH.SIZE,
|
|
24
|
+
DEFAULT_MAX_RETRIES: HTTP.MAX_RETRIES,
|
|
25
|
+
DEFAULT_ERROR_THRESHOLD_PERCENT: 10,
|
|
26
|
+
DEFAULT_SFTP_PORT: PORTS.SFTP,
|
|
27
|
+
DEFAULT_CACHE_TTL_SECONDS: 3600,
|
|
28
|
+
WEBHOOK_PATH_PREFIX: '/webhooks/data-hub/',
|
|
29
|
+
CRON_PLACEHOLDER: '0 0 * * *',
|
|
30
|
+
} as const;
|
|
31
|
+
|
|
32
|
+
export const PIPELINE_RETRY_DEFAULTS = {
|
|
33
|
+
DELAY_MS: TIME_UNITS.SECOND,
|
|
34
|
+
MAX_DELAY_MS: HTTP.RETRY_MAX_DELAY_MS,
|
|
35
|
+
MIN_DELAY_MS: TIME_UNITS.SECOND,
|
|
36
|
+
} as const;
|
|
37
|
+
|
|
38
|
+
export const PIPELINE_CHECKPOINT_DEFAULTS = {
|
|
39
|
+
INTERVAL_RECORDS: 1000,
|
|
40
|
+
INTERVAL_MS: TIME_UNITS.MINUTE,
|
|
41
|
+
MIN_INTERVAL_MS: TIME_UNITS.SECOND,
|
|
42
|
+
} as const;
|
|
43
|
+
|
|
44
|
+
export const STEP_CONFIG_DEFAULTS = {
|
|
45
|
+
THROUGHPUT_BATCH_SIZE: 50,
|
|
46
|
+
THROUGHPUT_CONCURRENCY: 10,
|
|
47
|
+
RETRY_MAX_ATTEMPTS: 3,
|
|
48
|
+
RETRY_DELAY_MS: 1000,
|
|
49
|
+
GATE_TIMEOUT_SECONDS: 300,
|
|
50
|
+
GATE_MIN_APPROVERS: 5,
|
|
51
|
+
GATE_THRESHOLD_PERCENT: 10,
|
|
52
|
+
GATE_PREVIEW_COUNT: 10,
|
|
53
|
+
} as const;
|
|
54
|
+
|
|
55
|
+
export const RETENTION_DEFAULTS = {
|
|
56
|
+
RUNS_DAYS: 7,
|
|
57
|
+
ERROR_DAYS: 30,
|
|
58
|
+
LOGS_DAYS: 30,
|
|
59
|
+
} as const;
|
|
60
|
+
|
|
61
|
+
/** Default edge style for ReactFlow pipeline connections */
|
|
62
|
+
export const EDGE_STYLE = {
|
|
63
|
+
STROKE_WIDTH: 2,
|
|
64
|
+
} as const;
|
|
65
|
+
|
|
66
|
+
/** Canvas CSS class for the ReactFlow editor background */
|
|
67
|
+
export const CANVAS_BG_CLASS = 'bg-gray-50 dark:bg-gray-900' as const;
|
|
68
|
+
|
|
69
|
+
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Enum map constants for type-safe comparisons in wizard components
|
|
3
|
+
* and across the dashboard. These are NOT option arrays for dropdowns
|
|
4
|
+
* (which come from the backend via useOptionValues), but rather
|
|
5
|
+
* constant maps used as type guards in switch/if statements.
|
|
6
|
+
*
|
|
7
|
+
* Shared constants are re-exported from shared/constants/enums.ts
|
|
8
|
+
* to eliminate duplication between dashboard and backend.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
export {
|
|
12
|
+
FILE_FORMAT,
|
|
13
|
+
SOURCE_TYPE,
|
|
14
|
+
EXPORT_FORMAT,
|
|
15
|
+
CLEANUP_STRATEGY,
|
|
16
|
+
COMPRESSION_TYPE,
|
|
17
|
+
} from '../../shared/constants';
|
|
18
|
+
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Minimal loading-state fallbacks for page-structural elements only.
|
|
3
|
+
*
|
|
4
|
+
* Most option lists (run statuses, log levels, HTTP methods, etc.) no longer
|
|
5
|
+
* have frontend fallbacks. Their consumers use the backend data directly via
|
|
6
|
+
* `useOptionValues()` and render loading states (disabled selects, skeletons)
|
|
7
|
+
* while the GraphQL config query resolves.
|
|
8
|
+
*
|
|
9
|
+
* Only two fallbacks remain:
|
|
10
|
+
* - FALLBACK_ADAPTER_TYPE_TABS: defines page tab structure (empty tabs = broken page)
|
|
11
|
+
* - FALLBACK_STAGE_CATEGORIES: defines hook stage category layout (empty = broken grid)
|
|
12
|
+
*
|
|
13
|
+
* These are intentionally kept because their consumers need structural data
|
|
14
|
+
* before the page can render at all, and the values change very rarely.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import type { ConfigOptionValue, HookStageCategoryConfig } from '../hooks/api/use-config-options';
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Shape of a selectable transformation type in the wizard UI.
|
|
21
|
+
*/
|
|
22
|
+
export interface TransformTypeOption {
|
|
23
|
+
id: string;
|
|
24
|
+
label: string;
|
|
25
|
+
description: string;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/** Fallback adapter type tabs used while backend data is loading.
|
|
29
|
+
* Must stay in sync with ADAPTER_TYPE_METADATA in src/constants/enum-metadata.ts. */
|
|
30
|
+
export const FALLBACK_ADAPTER_TYPE_TABS: ConfigOptionValue[] = [
|
|
31
|
+
{ value: 'EXTRACTOR', label: 'Extractors', icon: 'database' },
|
|
32
|
+
{ value: 'OPERATOR', label: 'Operators', icon: 'cog' },
|
|
33
|
+
{ value: 'LOADER', label: 'Loaders', icon: 'upload' },
|
|
34
|
+
{ value: 'EXPORTER', label: 'Exporters', icon: 'download' },
|
|
35
|
+
{ value: 'FEED', label: 'Feeds', icon: 'rss' },
|
|
36
|
+
{ value: 'SINK', label: 'Sinks', icon: 'send' },
|
|
37
|
+
];
|
|
38
|
+
|
|
39
|
+
/** Fallback hook stage categories used while backend metadata is loading */
|
|
40
|
+
export const FALLBACK_STAGE_CATEGORIES: HookStageCategoryConfig[] = [
|
|
41
|
+
{ key: 'lifecycle', label: 'Lifecycle', color: 'bg-blue-100 dark:bg-blue-900/30 text-blue-800 dark:text-blue-400', description: 'Track pipeline start, completion, and failure', gridClass: 'grid-cols-3', order: 1 },
|
|
42
|
+
{ key: 'data', label: 'Data Processing', color: 'bg-green-100 dark:bg-green-900/30 text-green-800 dark:text-green-400', description: 'Intercept data at each processing step', gridClass: 'grid-cols-4', order: 2 },
|
|
43
|
+
{ key: 'error', label: 'Error Handling', color: 'bg-red-100 dark:bg-red-900/30 text-red-800 dark:text-red-400', description: 'Handle errors and retries', gridClass: 'grid-cols-3', order: 3 },
|
|
44
|
+
];
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
import { useConfigOptions } from '../hooks/api';
|
|
2
|
+
import { parseCSVLine } from '../../shared/utils/csv-parse';
|
|
3
|
+
import type { FileType } from '../utils/column-analysis';
|
|
4
|
+
|
|
5
|
+
export interface FileParseResult {
|
|
6
|
+
headers: string[];
|
|
7
|
+
rows: Record<string, unknown>[];
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export interface FileParseOptions {
|
|
11
|
+
delimiter?: string;
|
|
12
|
+
hasHeaders?: boolean;
|
|
13
|
+
maxRows?: number;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export interface FileFormatEntry {
|
|
17
|
+
value: string;
|
|
18
|
+
label: string;
|
|
19
|
+
extensions: string[];
|
|
20
|
+
mimeTypes: string[];
|
|
21
|
+
supportsPreview: boolean;
|
|
22
|
+
description?: string;
|
|
23
|
+
parse: (file: File, options?: FileParseOptions) => Promise<FileParseResult>;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// ---------------------------------------------------------------------------
|
|
27
|
+
// Client-side parsers (ONLY formats that need browser preview)
|
|
28
|
+
// ---------------------------------------------------------------------------
|
|
29
|
+
|
|
30
|
+
const DEFAULT_MAX_ROWS = 100;
|
|
31
|
+
|
|
32
|
+
async function parseCsvFile(file: File, options?: FileParseOptions): Promise<FileParseResult> {
|
|
33
|
+
const text = await file.text();
|
|
34
|
+
const lines = text.split('\n').filter(line => line.trim());
|
|
35
|
+
const delimiter = options?.delimiter ?? ',';
|
|
36
|
+
const hasHeaders = options?.hasHeaders ?? true;
|
|
37
|
+
const maxRows = options?.maxRows ?? DEFAULT_MAX_ROWS;
|
|
38
|
+
|
|
39
|
+
const headers = hasHeaders
|
|
40
|
+
? parseCSVLine(lines[0], delimiter).map(h => h.replace(/^["']|["']$/g, ''))
|
|
41
|
+
: parseCSVLine(lines[0], delimiter).map((_, i) => `column_${i + 1}`);
|
|
42
|
+
|
|
43
|
+
const dataLines = hasHeaders ? lines.slice(1) : lines;
|
|
44
|
+
const rows = dataLines.slice(0, maxRows).map(line => {
|
|
45
|
+
const values = parseCSVLine(line, delimiter).map(v => v.replace(/^["']|["']$/g, ''));
|
|
46
|
+
const row: Record<string, unknown> = {};
|
|
47
|
+
headers.forEach((header, i) => {
|
|
48
|
+
row[header] = values[i] ?? '';
|
|
49
|
+
});
|
|
50
|
+
return row;
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
return { headers, rows };
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
async function parseJsonFile(file: File, options?: FileParseOptions): Promise<FileParseResult> {
|
|
57
|
+
const text = await file.text();
|
|
58
|
+
const json = JSON.parse(text);
|
|
59
|
+
const items: Record<string, unknown>[] = Array.isArray(json) ? json : json.data ?? [json];
|
|
60
|
+
const maxRows = options?.maxRows ?? DEFAULT_MAX_ROWS;
|
|
61
|
+
const sampleItems = items.slice(0, maxRows);
|
|
62
|
+
const headers = [...new Set(sampleItems.flatMap(item => Object.keys(item)))];
|
|
63
|
+
return { headers, rows: sampleItems };
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
async function parseXlsxFile(file: File, options?: FileParseOptions): Promise<FileParseResult> {
|
|
67
|
+
const { read, utils } = await import('xlsx');
|
|
68
|
+
const buffer = await file.arrayBuffer();
|
|
69
|
+
const workbook = read(buffer, { type: 'array' });
|
|
70
|
+
const sheetName = workbook.SheetNames[0];
|
|
71
|
+
if (!sheetName) throw new Error('Excel file has no sheets');
|
|
72
|
+
const sheet = workbook.Sheets[sheetName];
|
|
73
|
+
const jsonRows = utils.sheet_to_json<Record<string, unknown>>(sheet, { defval: '' });
|
|
74
|
+
const maxRows = options?.maxRows ?? DEFAULT_MAX_ROWS;
|
|
75
|
+
const sampleItems = jsonRows.slice(0, maxRows);
|
|
76
|
+
const headers = [...new Set(sampleItems.flatMap(item => Object.keys(item)))];
|
|
77
|
+
return { headers, rows: sampleItems };
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
async function parseXmlFile(file: File, _options?: FileParseOptions): Promise<FileParseResult> {
|
|
81
|
+
void file;
|
|
82
|
+
return { headers: [], rows: [] };
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
async function parseNdjsonFile(file: File, options?: FileParseOptions): Promise<FileParseResult> {
|
|
86
|
+
const text = await file.text();
|
|
87
|
+
const maxRows = options?.maxRows ?? DEFAULT_MAX_ROWS;
|
|
88
|
+
const lines = text.split('\n').filter(line => line.trim());
|
|
89
|
+
const items: Record<string, unknown>[] = [];
|
|
90
|
+
for (const line of lines) {
|
|
91
|
+
if (items.length >= maxRows) break;
|
|
92
|
+
items.push(JSON.parse(line) as Record<string, unknown>);
|
|
93
|
+
}
|
|
94
|
+
const headers = [...new Set(items.flatMap(item => Object.keys(item)))];
|
|
95
|
+
return { headers, rows: items };
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
const PARSERS: Record<string, (file: File, options?: FileParseOptions) => Promise<FileParseResult>> = {
|
|
99
|
+
CSV: parseCsvFile,
|
|
100
|
+
TSV: parseCsvFile,
|
|
101
|
+
JSON: parseJsonFile,
|
|
102
|
+
XLSX: parseXlsxFile,
|
|
103
|
+
XML: parseXmlFile,
|
|
104
|
+
NDJSON: parseNdjsonFile,
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
function buildFileFormatRegistry(
|
|
108
|
+
backendFormats: Array<{
|
|
109
|
+
value: string;
|
|
110
|
+
label: string;
|
|
111
|
+
extensions: string[];
|
|
112
|
+
mimeTypes: string[];
|
|
113
|
+
supportsPreview: boolean;
|
|
114
|
+
requiresClientParser: boolean;
|
|
115
|
+
description?: string;
|
|
116
|
+
}>
|
|
117
|
+
): Map<string, FileFormatEntry> {
|
|
118
|
+
const registry = new Map<string, FileFormatEntry>();
|
|
119
|
+
|
|
120
|
+
for (const format of backendFormats) {
|
|
121
|
+
if (format.requiresClientParser && PARSERS[format.value]) {
|
|
122
|
+
registry.set(format.value, {
|
|
123
|
+
...format,
|
|
124
|
+
parse: PARSERS[format.value],
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
return registry;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
export function useFileFormatRegistry(): Map<string, FileFormatEntry> {
|
|
133
|
+
const { fileFormats } = useConfigOptions();
|
|
134
|
+
return buildFileFormatRegistry(fileFormats);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
export const FILE_FORMAT_REGISTRY = new Map<string, FileFormatEntry>([
|
|
138
|
+
['CSV', {
|
|
139
|
+
value: 'CSV',
|
|
140
|
+
label: 'CSV',
|
|
141
|
+
extensions: ['.csv', '.tsv'],
|
|
142
|
+
mimeTypes: ['text/csv', 'text/tab-separated-values'],
|
|
143
|
+
supportsPreview: true,
|
|
144
|
+
parse: parseCsvFile,
|
|
145
|
+
}],
|
|
146
|
+
['JSON', {
|
|
147
|
+
value: 'JSON',
|
|
148
|
+
label: 'JSON',
|
|
149
|
+
extensions: ['.json'],
|
|
150
|
+
mimeTypes: ['application/json'],
|
|
151
|
+
supportsPreview: true,
|
|
152
|
+
parse: parseJsonFile,
|
|
153
|
+
}],
|
|
154
|
+
['XML', {
|
|
155
|
+
value: 'XML',
|
|
156
|
+
label: 'XML',
|
|
157
|
+
extensions: ['.xml'],
|
|
158
|
+
mimeTypes: ['text/xml', 'application/xml'],
|
|
159
|
+
supportsPreview: false,
|
|
160
|
+
parse: parseXmlFile,
|
|
161
|
+
}],
|
|
162
|
+
['XLSX', {
|
|
163
|
+
value: 'XLSX',
|
|
164
|
+
label: 'Excel',
|
|
165
|
+
extensions: ['.xlsx', '.xls'],
|
|
166
|
+
mimeTypes: ['application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', 'application/vnd.ms-excel'],
|
|
167
|
+
supportsPreview: true,
|
|
168
|
+
parse: parseXlsxFile,
|
|
169
|
+
}],
|
|
170
|
+
['NDJSON', {
|
|
171
|
+
value: 'NDJSON',
|
|
172
|
+
label: 'NDJSON',
|
|
173
|
+
extensions: ['.ndjson', '.jsonl'],
|
|
174
|
+
mimeTypes: ['application/x-ndjson'],
|
|
175
|
+
supportsPreview: true,
|
|
176
|
+
parse: parseNdjsonFile,
|
|
177
|
+
}],
|
|
178
|
+
]);
|
|
179
|
+
|
|
180
|
+
export function buildAcceptString(
|
|
181
|
+
allowedTypes?: string[],
|
|
182
|
+
registry: Map<string, FileFormatEntry> = FILE_FORMAT_REGISTRY
|
|
183
|
+
): string {
|
|
184
|
+
if (!allowedTypes || allowedTypes.length === 0) return '*';
|
|
185
|
+
const extensions: string[] = [];
|
|
186
|
+
for (const type of allowedTypes) {
|
|
187
|
+
const entry = registry.get(type);
|
|
188
|
+
if (entry) {
|
|
189
|
+
extensions.push(...entry.extensions);
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
return extensions.length > 0 ? extensions.join(',') : '*';
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
export function detectFileFormat(
|
|
196
|
+
fileName: string,
|
|
197
|
+
registry: Map<string, FileFormatEntry> = FILE_FORMAT_REGISTRY
|
|
198
|
+
): FileType {
|
|
199
|
+
const ext = '.' + (fileName.split('.').pop()?.toLowerCase() ?? '');
|
|
200
|
+
for (const [format, entry] of registry) {
|
|
201
|
+
if (entry.extensions.includes(ext)) {
|
|
202
|
+
return format as NonNullable<FileType>;
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
return null;
|
|
206
|
+
}
|