@oronts/vendure-data-hub-plugin 0.1.0 → 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 +10 -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 +4 -4
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import React, { useCallback } from 'react';
|
|
2
|
+
import { Plus, Trash2, AlertTriangle } from 'lucide-react';
|
|
3
|
+
import { Button, Input, Label } from '@vendure/dashboard';
|
|
4
|
+
import { ROUTE_BRANCH_DEFAULTS, ERROR_MESSAGES } from '../../../constants';
|
|
5
|
+
import { useStableKeys } from '../../../hooks';
|
|
6
|
+
|
|
7
|
+
export interface RouteConfigComponentProps {
|
|
8
|
+
readonly config: Record<string, unknown>;
|
|
9
|
+
readonly onChange: (config: Record<string, unknown>) => void;
|
|
10
|
+
readonly showDuplicateWarning?: boolean;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
interface Branch {
|
|
14
|
+
name: string;
|
|
15
|
+
conditions?: unknown[];
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export function RouteConfigComponent({
|
|
19
|
+
config,
|
|
20
|
+
onChange,
|
|
21
|
+
showDuplicateWarning = true,
|
|
22
|
+
}: RouteConfigComponentProps) {
|
|
23
|
+
const branches = (config.branches as Branch[]) ?? [];
|
|
24
|
+
const branchKeys = useStableKeys(branches, 'branch');
|
|
25
|
+
|
|
26
|
+
const getDuplicateBranches = React.useCallback((branchList: Branch[]) => {
|
|
27
|
+
const names = branchList.map((b) => b.name.trim().toLowerCase());
|
|
28
|
+
const duplicates = new Set<string>();
|
|
29
|
+
const seen = new Set<string>();
|
|
30
|
+
for (const name of names) {
|
|
31
|
+
if (name && seen.has(name)) {
|
|
32
|
+
duplicates.add(name);
|
|
33
|
+
}
|
|
34
|
+
seen.add(name);
|
|
35
|
+
}
|
|
36
|
+
return duplicates;
|
|
37
|
+
}, []);
|
|
38
|
+
|
|
39
|
+
const duplicates = getDuplicateBranches(branches);
|
|
40
|
+
const hasDuplicates = duplicates.size > 0;
|
|
41
|
+
|
|
42
|
+
const addBranch = useCallback(() => {
|
|
43
|
+
let branchNum = branches.length + 1;
|
|
44
|
+
let newName = `${ROUTE_BRANCH_DEFAULTS.namePrefix}${branchNum}`;
|
|
45
|
+
const existingNames = new Set(branches.map((b) => b.name.toLowerCase()));
|
|
46
|
+
while (existingNames.has(newName.toLowerCase())) {
|
|
47
|
+
branchNum++;
|
|
48
|
+
newName = `${ROUTE_BRANCH_DEFAULTS.namePrefix}${branchNum}`;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
onChange({
|
|
52
|
+
...config,
|
|
53
|
+
branches: [...branches, { name: newName, conditions: [] }],
|
|
54
|
+
});
|
|
55
|
+
}, [branches, config, onChange]);
|
|
56
|
+
|
|
57
|
+
const updateBranch = useCallback((index: number, patch: Record<string, unknown>) => {
|
|
58
|
+
const newBranches = [...branches];
|
|
59
|
+
newBranches[index] = { ...newBranches[index], ...patch };
|
|
60
|
+
onChange({ ...config, branches: newBranches });
|
|
61
|
+
}, [branches, config, onChange]);
|
|
62
|
+
|
|
63
|
+
const removeBranch = useCallback((index: number) => {
|
|
64
|
+
onChange({ ...config, branches: branches.filter((_, i) => i !== index) });
|
|
65
|
+
}, [branches, config, onChange]);
|
|
66
|
+
|
|
67
|
+
const isBranchDuplicate = useCallback((branchName: string) => {
|
|
68
|
+
return duplicates.has(branchName.trim().toLowerCase());
|
|
69
|
+
}, [duplicates]);
|
|
70
|
+
|
|
71
|
+
return (
|
|
72
|
+
<div className="space-y-3">
|
|
73
|
+
<div className="flex items-center justify-between">
|
|
74
|
+
<Label className="text-sm font-medium">Routing Branches</Label>
|
|
75
|
+
<Button variant="outline" size="sm" onClick={addBranch}>
|
|
76
|
+
<Plus className="h-3 w-3 mr-1" />
|
|
77
|
+
Add Branch
|
|
78
|
+
</Button>
|
|
79
|
+
</div>
|
|
80
|
+
|
|
81
|
+
{showDuplicateWarning && hasDuplicates && (
|
|
82
|
+
<div className="p-3 bg-amber-50 dark:bg-amber-950/30 border border-amber-200 dark:border-amber-800 rounded-md">
|
|
83
|
+
<div className="flex items-center gap-2 text-amber-800 dark:text-amber-400">
|
|
84
|
+
<AlertTriangle className="h-4 w-4" />
|
|
85
|
+
<span className="text-sm font-medium">Duplicate branch names detected</span>
|
|
86
|
+
</div>
|
|
87
|
+
<p className="text-xs text-amber-700 mt-1">
|
|
88
|
+
{ERROR_MESSAGES.DUPLICATE_BRANCH_NAMES}. Duplicate: {Array.from(duplicates).join(', ')}
|
|
89
|
+
</p>
|
|
90
|
+
</div>
|
|
91
|
+
)}
|
|
92
|
+
|
|
93
|
+
{branches.map((branch, i) => (
|
|
94
|
+
<div key={branchKeys[i]} className="flex items-center gap-2 p-2 border rounded">
|
|
95
|
+
<div className="flex-1">
|
|
96
|
+
<Input
|
|
97
|
+
value={branch.name}
|
|
98
|
+
onChange={(e) => updateBranch(i, { name: e.target.value })}
|
|
99
|
+
placeholder="Branch name"
|
|
100
|
+
className={isBranchDuplicate(branch.name) ? 'border-amber-300 focus:border-amber-500' : ''}
|
|
101
|
+
/>
|
|
102
|
+
{!branch.name.trim() && (
|
|
103
|
+
<p className="text-xs text-destructive mt-1">{ERROR_MESSAGES.BRANCH_NAME_EMPTY}</p>
|
|
104
|
+
)}
|
|
105
|
+
</div>
|
|
106
|
+
<Button
|
|
107
|
+
variant="ghost"
|
|
108
|
+
size="sm"
|
|
109
|
+
onClick={() => removeBranch(i)}
|
|
110
|
+
className="text-destructive"
|
|
111
|
+
aria-label={`Remove branch ${branch.name || i + 1}`}
|
|
112
|
+
>
|
|
113
|
+
<Trash2 className="h-4 w-4" />
|
|
114
|
+
</Button>
|
|
115
|
+
</div>
|
|
116
|
+
))}
|
|
117
|
+
|
|
118
|
+
{branches.length === 0 && (
|
|
119
|
+
<p className="text-sm text-muted-foreground">
|
|
120
|
+
Add branches to route records based on conditions.
|
|
121
|
+
</p>
|
|
122
|
+
)}
|
|
123
|
+
</div>
|
|
124
|
+
);
|
|
125
|
+
}
|
|
@@ -0,0 +1,564 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { useMemo, useCallback } from 'react';
|
|
3
|
+
import {
|
|
4
|
+
Button,
|
|
5
|
+
Input,
|
|
6
|
+
Card,
|
|
7
|
+
CardContent,
|
|
8
|
+
CardHeader,
|
|
9
|
+
CardTitle,
|
|
10
|
+
Label,
|
|
11
|
+
Separator,
|
|
12
|
+
} from '@vendure/dashboard';
|
|
13
|
+
import { Trash2, Settings2 } from 'lucide-react';
|
|
14
|
+
|
|
15
|
+
import { SchemaFormRenderer } from '../schema-form';
|
|
16
|
+
import {
|
|
17
|
+
AdapterSelector,
|
|
18
|
+
AdapterRequiredWarning,
|
|
19
|
+
ValidateConfigComponent,
|
|
20
|
+
RouteConfigComponent,
|
|
21
|
+
EnrichConfigComponent,
|
|
22
|
+
GateConfigComponent,
|
|
23
|
+
} from './index';
|
|
24
|
+
import { TriggerForm } from '../trigger-config';
|
|
25
|
+
import { OperatorCheatSheetButton } from './OperatorCheatSheetButton';
|
|
26
|
+
import {
|
|
27
|
+
AdvancedMapEditor,
|
|
28
|
+
AdvancedTemplateEditor,
|
|
29
|
+
AdvancedWhenEditor,
|
|
30
|
+
MultiOperatorEditor,
|
|
31
|
+
} from './AdvancedEditors';
|
|
32
|
+
import { StepTester } from './StepTester';
|
|
33
|
+
import { RetrySettingsComponent } from './RetrySettingsComponent';
|
|
34
|
+
import type { RetrySettings } from './RetrySettingsComponent';
|
|
35
|
+
import { useAdapterCatalog, useStepConfigs, AdapterMetadata } from '../../../hooks';
|
|
36
|
+
import { getAdapterTypeLabel, prepareDynamicFields, normalizeStepType, getAdapterTypeForStep } from '../../../utils';
|
|
37
|
+
import {
|
|
38
|
+
STEP_TYPE,
|
|
39
|
+
ADAPTER_TYPES,
|
|
40
|
+
NODE_CATEGORIES,
|
|
41
|
+
PANEL_VARIANT,
|
|
42
|
+
FALLBACK_COLORS,
|
|
43
|
+
} from '../../../constants';
|
|
44
|
+
import type {
|
|
45
|
+
StepType,
|
|
46
|
+
PipelineStepDefinition,
|
|
47
|
+
PipelineTrigger,
|
|
48
|
+
TriggerType,
|
|
49
|
+
AdapterSchemaField,
|
|
50
|
+
} from '../../../types';
|
|
51
|
+
|
|
52
|
+
/** Common props shared by all special config editors (Route, Validate, Enrich, Gate). */
|
|
53
|
+
interface SpecialConfigProps {
|
|
54
|
+
readonly config: Record<string, unknown>;
|
|
55
|
+
readonly onChange: (config: Record<string, unknown>) => void;
|
|
56
|
+
readonly showErrorHandling?: boolean;
|
|
57
|
+
readonly showValidationMode?: boolean;
|
|
58
|
+
readonly showRulesEditor?: boolean;
|
|
59
|
+
readonly showDuplicateWarning?: boolean;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Registry mapping step types to their dedicated config editor component.
|
|
64
|
+
* Used both as a guard (`stepType in SPECIAL_CONFIG_EDITORS`) and for
|
|
65
|
+
* table-driven dispatch in `renderSpecialConfigs`.
|
|
66
|
+
*/
|
|
67
|
+
const SPECIAL_CONFIG_EDITORS: Record<string, React.ComponentType<SpecialConfigProps>> = {
|
|
68
|
+
[STEP_TYPE.ROUTE]: RouteConfigComponent as React.ComponentType<SpecialConfigProps>,
|
|
69
|
+
[STEP_TYPE.VALIDATE]: ValidateConfigComponent as React.ComponentType<SpecialConfigProps>,
|
|
70
|
+
[STEP_TYPE.ENRICH]: EnrichConfigComponent as React.ComponentType<SpecialConfigProps>,
|
|
71
|
+
[STEP_TYPE.GATE]: GateConfigComponent as React.ComponentType<SpecialConfigProps>,
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
/** Props shared by all advanced operator editors (map, template, filter). */
|
|
75
|
+
interface AdvancedEditorProps {
|
|
76
|
+
readonly config: Record<string, unknown>;
|
|
77
|
+
readonly onChange: (values: Record<string, unknown>) => void;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Registry mapping operator editor types to their advanced editor component.
|
|
82
|
+
* Keyed by the canonical lowercase adapter code.
|
|
83
|
+
*/
|
|
84
|
+
const ADVANCED_EDITORS: Record<string, React.ComponentType<AdvancedEditorProps>> = {
|
|
85
|
+
map: AdvancedMapEditor,
|
|
86
|
+
template: AdvancedTemplateEditor,
|
|
87
|
+
filter: AdvancedWhenEditor,
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
export interface StepConfigData {
|
|
91
|
+
key: string;
|
|
92
|
+
type: StepType | string;
|
|
93
|
+
config: Record<string, unknown>;
|
|
94
|
+
adapterCode?: string;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
export interface StepConfigPanelProps {
|
|
98
|
+
data: StepConfigData;
|
|
99
|
+
onChange: (data: StepConfigData) => void;
|
|
100
|
+
onDelete?: () => void;
|
|
101
|
+
catalog?: AdapterMetadata[];
|
|
102
|
+
connectionCodes?: string[];
|
|
103
|
+
secretOptions?: Array<{ code: string; provider?: string }>;
|
|
104
|
+
variant?: 'panel' | 'inline';
|
|
105
|
+
showKeyInput?: boolean;
|
|
106
|
+
showHeader?: boolean;
|
|
107
|
+
showDeleteButton?: boolean;
|
|
108
|
+
showCheatSheet?: boolean;
|
|
109
|
+
showStepTester?: boolean;
|
|
110
|
+
showAdvancedEditors?: boolean;
|
|
111
|
+
compact?: boolean;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
export function StepConfigPanel({
|
|
115
|
+
data,
|
|
116
|
+
onChange,
|
|
117
|
+
onDelete,
|
|
118
|
+
catalog: externalCatalog,
|
|
119
|
+
connectionCodes: externalConnectionCodes,
|
|
120
|
+
secretOptions: externalSecretOptions,
|
|
121
|
+
variant = 'inline',
|
|
122
|
+
showKeyInput = true,
|
|
123
|
+
showHeader = true,
|
|
124
|
+
showDeleteButton = true,
|
|
125
|
+
showCheatSheet = true,
|
|
126
|
+
showStepTester = true,
|
|
127
|
+
showAdvancedEditors = true,
|
|
128
|
+
compact = false,
|
|
129
|
+
}: StepConfigPanelProps) {
|
|
130
|
+
const hookResult = useAdapterCatalog();
|
|
131
|
+
const { getStepConfig } = useStepConfigs();
|
|
132
|
+
const catalog = externalCatalog ?? hookResult.adapters;
|
|
133
|
+
const connectionCodes = externalConnectionCodes ?? hookResult.connectionCodes;
|
|
134
|
+
const secretOptions = externalSecretOptions ?? hookResult.secretOptions;
|
|
135
|
+
const isLoadingCatalog = !externalCatalog && hookResult.isLoading;
|
|
136
|
+
|
|
137
|
+
const stepType = normalizeStepType(data.type);
|
|
138
|
+
const config = getStepConfig(stepType);
|
|
139
|
+
const adapterType = getAdapterTypeForStep(data.type);
|
|
140
|
+
|
|
141
|
+
const availableAdapters = useMemo(
|
|
142
|
+
() => (adapterType ? catalog.filter((a) => a.type === adapterType) : []),
|
|
143
|
+
[catalog, adapterType]
|
|
144
|
+
);
|
|
145
|
+
|
|
146
|
+
const adapterCode = data.adapterCode ?? (data.config?.adapterCode as string);
|
|
147
|
+
|
|
148
|
+
const selectedAdapter = useMemo(
|
|
149
|
+
() => availableAdapters.find((a) => a.code === adapterCode),
|
|
150
|
+
[availableAdapters, adapterCode]
|
|
151
|
+
);
|
|
152
|
+
|
|
153
|
+
const hasMultiOperatorConfig = useMemo(
|
|
154
|
+
() =>
|
|
155
|
+
stepType === STEP_TYPE.TRANSFORM &&
|
|
156
|
+
Array.isArray(data.config?.operators) &&
|
|
157
|
+
data.config.operators.length > 0,
|
|
158
|
+
[stepType, data.config?.operators]
|
|
159
|
+
);
|
|
160
|
+
|
|
161
|
+
const needsAdapterSelection = useMemo(
|
|
162
|
+
() => !adapterCode && !hasMultiOperatorConfig && stepType !== STEP_TYPE.TRIGGER,
|
|
163
|
+
[adapterCode, hasMultiOperatorConfig, stepType]
|
|
164
|
+
);
|
|
165
|
+
|
|
166
|
+
const dynamicFields = React.useMemo<AdapterSchemaField[]>(
|
|
167
|
+
() =>
|
|
168
|
+
prepareDynamicFields({
|
|
169
|
+
baseFields: selectedAdapter?.schema?.fields ?? [],
|
|
170
|
+
connectionCodes,
|
|
171
|
+
}),
|
|
172
|
+
[selectedAdapter, connectionCodes]
|
|
173
|
+
);
|
|
174
|
+
|
|
175
|
+
const updateKey = useCallback((key: string) => {
|
|
176
|
+
onChange({ ...data, key });
|
|
177
|
+
}, [onChange, data]);
|
|
178
|
+
|
|
179
|
+
const updateConfig = useCallback((key: string, value: unknown) => {
|
|
180
|
+
onChange({
|
|
181
|
+
...data,
|
|
182
|
+
config: { ...data.config, [key]: value },
|
|
183
|
+
});
|
|
184
|
+
}, [onChange, data]);
|
|
185
|
+
|
|
186
|
+
const updateConfigBatch = useCallback((values: Record<string, unknown>) => {
|
|
187
|
+
onChange({
|
|
188
|
+
...data,
|
|
189
|
+
config: { ...data.config, ...values },
|
|
190
|
+
});
|
|
191
|
+
}, [onChange, data]);
|
|
192
|
+
|
|
193
|
+
const updateAdapterCode = useCallback((code: string) => {
|
|
194
|
+
onChange({
|
|
195
|
+
...data,
|
|
196
|
+
adapterCode: code,
|
|
197
|
+
config: { ...data.config, adapterCode: code },
|
|
198
|
+
});
|
|
199
|
+
}, [onChange, data]);
|
|
200
|
+
|
|
201
|
+
const updateOperators = useCallback((operators: Array<{ op: string; args?: Record<string, unknown> }>) => {
|
|
202
|
+
onChange({
|
|
203
|
+
...data,
|
|
204
|
+
config: { ...data.config, operators },
|
|
205
|
+
});
|
|
206
|
+
}, [onChange, data]);
|
|
207
|
+
|
|
208
|
+
const handleKeyChange = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {
|
|
209
|
+
updateKey(e.target.value);
|
|
210
|
+
}, [updateKey]);
|
|
211
|
+
|
|
212
|
+
const handleAdapterCodeChange = useCallback((code: string) => {
|
|
213
|
+
if (code !== adapterCode) {
|
|
214
|
+
updateAdapterCode(code);
|
|
215
|
+
}
|
|
216
|
+
}, [adapterCode, updateAdapterCode]);
|
|
217
|
+
|
|
218
|
+
const handleResetDefaults = useCallback(() => {
|
|
219
|
+
const defaults: Record<string, unknown> = {};
|
|
220
|
+
for (const f of dynamicFields) {
|
|
221
|
+
if (f.defaultValue !== undefined) {
|
|
222
|
+
defaults[f.key] = f.defaultValue;
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
updateConfigBatch(defaults);
|
|
226
|
+
}, [dynamicFields, updateConfigBatch]);
|
|
227
|
+
|
|
228
|
+
const handleTriggerChange = useCallback((trigger: PipelineTrigger) => {
|
|
229
|
+
updateConfigBatch({
|
|
230
|
+
type: trigger.type,
|
|
231
|
+
enabled: trigger.enabled,
|
|
232
|
+
cron: trigger.cron,
|
|
233
|
+
timezone: trigger.timezone,
|
|
234
|
+
webhookCode: trigger.webhookCode,
|
|
235
|
+
authentication: trigger.authentication,
|
|
236
|
+
secretCode: trigger.secretCode,
|
|
237
|
+
event: trigger.eventType,
|
|
238
|
+
eventType: trigger.eventType,
|
|
239
|
+
});
|
|
240
|
+
}, [updateConfigBatch]);
|
|
241
|
+
|
|
242
|
+
const triggerValue = useMemo(() => ({
|
|
243
|
+
type: (data.config?.type as TriggerType) || 'MANUAL',
|
|
244
|
+
enabled: data.config?.enabled !== false,
|
|
245
|
+
cron: data.config?.cron as string,
|
|
246
|
+
timezone: data.config?.timezone as string,
|
|
247
|
+
webhookCode: data.config?.webhookCode as string,
|
|
248
|
+
authentication: data.config?.authentication as PipelineTrigger['authentication'],
|
|
249
|
+
secretCode: data.config?.secretCode as string,
|
|
250
|
+
eventType: (data.config?.event as string) || (data.config?.eventType as string),
|
|
251
|
+
}), [data.config?.type, data.config?.enabled, data.config?.cron, data.config?.timezone, data.config?.webhookCode, data.config?.authentication, data.config?.secretCode, data.config?.event, data.config?.eventType]);
|
|
252
|
+
|
|
253
|
+
const renderHeader = () => {
|
|
254
|
+
if (!showHeader) return null;
|
|
255
|
+
|
|
256
|
+
return (
|
|
257
|
+
<div
|
|
258
|
+
className={compact ? 'p-3 rounded-lg mb-3' : 'p-4 rounded-lg mb-4'}
|
|
259
|
+
style={{ backgroundColor: config?.bgColor ?? FALLBACK_COLORS.UNKNOWN_STEP_BG }}
|
|
260
|
+
>
|
|
261
|
+
<div className="flex items-center justify-between">
|
|
262
|
+
<div className="flex items-center gap-3">
|
|
263
|
+
{selectedAdapter ? (
|
|
264
|
+
<div
|
|
265
|
+
className="w-8 h-8 rounded-full flex items-center justify-center text-white"
|
|
266
|
+
style={{ backgroundColor: selectedAdapter.color }}
|
|
267
|
+
>
|
|
268
|
+
<selectedAdapter.icon className="h-4 w-4" />
|
|
269
|
+
</div>
|
|
270
|
+
) : (
|
|
271
|
+
<div
|
|
272
|
+
className="w-8 h-8 rounded-full flex items-center justify-center text-white"
|
|
273
|
+
style={{ backgroundColor: config?.color ?? FALLBACK_COLORS.UNKNOWN_STEP_COLOR }}
|
|
274
|
+
>
|
|
275
|
+
{stepType.charAt(0)}
|
|
276
|
+
</div>
|
|
277
|
+
)}
|
|
278
|
+
<div>
|
|
279
|
+
<h3
|
|
280
|
+
className={compact ? 'font-medium text-sm' : 'font-semibold'}
|
|
281
|
+
style={{ color: config?.color }}
|
|
282
|
+
>
|
|
283
|
+
{config?.label ?? stepType} Step
|
|
284
|
+
</h3>
|
|
285
|
+
{!compact && (
|
|
286
|
+
<p className="text-sm text-muted-foreground">{config?.description}</p>
|
|
287
|
+
)}
|
|
288
|
+
</div>
|
|
289
|
+
</div>
|
|
290
|
+
<div className="flex items-center gap-1">
|
|
291
|
+
{showCheatSheet && adapterType === ADAPTER_TYPES.OPERATOR && (
|
|
292
|
+
<OperatorCheatSheetButton label={compact ? undefined : 'Help'} />
|
|
293
|
+
)}
|
|
294
|
+
{showDeleteButton && onDelete && (
|
|
295
|
+
<Button
|
|
296
|
+
variant="ghost"
|
|
297
|
+
size="sm"
|
|
298
|
+
className="text-destructive hover:text-destructive"
|
|
299
|
+
onClick={onDelete}
|
|
300
|
+
aria-label="Remove step"
|
|
301
|
+
>
|
|
302
|
+
<Trash2 className="h-4 w-4" />
|
|
303
|
+
</Button>
|
|
304
|
+
)}
|
|
305
|
+
</div>
|
|
306
|
+
</div>
|
|
307
|
+
</div>
|
|
308
|
+
);
|
|
309
|
+
};
|
|
310
|
+
|
|
311
|
+
const renderKeyInput = () => {
|
|
312
|
+
if (!showKeyInput) return null;
|
|
313
|
+
|
|
314
|
+
return (
|
|
315
|
+
<div className={compact ? 'space-y-1' : 'space-y-2'}>
|
|
316
|
+
<Label className={compact ? 'text-xs' : 'text-sm'}>
|
|
317
|
+
{variant === PANEL_VARIANT.PANEL ? 'Node Label' : 'Step Key'}
|
|
318
|
+
</Label>
|
|
319
|
+
<Input
|
|
320
|
+
value={data.key}
|
|
321
|
+
onChange={handleKeyChange}
|
|
322
|
+
placeholder="unique-step-key"
|
|
323
|
+
className={compact ? 'h-8 font-mono' : 'font-mono'}
|
|
324
|
+
/>
|
|
325
|
+
{!compact && (
|
|
326
|
+
<p className="text-xs text-muted-foreground">
|
|
327
|
+
Unique identifier for this step in the pipeline
|
|
328
|
+
</p>
|
|
329
|
+
)}
|
|
330
|
+
</div>
|
|
331
|
+
);
|
|
332
|
+
};
|
|
333
|
+
|
|
334
|
+
const renderTriggerConfig = () => {
|
|
335
|
+
if (stepType !== STEP_TYPE.TRIGGER) return null;
|
|
336
|
+
|
|
337
|
+
return (
|
|
338
|
+
<TriggerForm
|
|
339
|
+
trigger={triggerValue}
|
|
340
|
+
onChange={handleTriggerChange}
|
|
341
|
+
compact={compact}
|
|
342
|
+
/>
|
|
343
|
+
);
|
|
344
|
+
};
|
|
345
|
+
|
|
346
|
+
const renderAdapterSelection = () => {
|
|
347
|
+
if (!adapterType || stepType === STEP_TYPE.TRIGGER) return null;
|
|
348
|
+
|
|
349
|
+
if (stepType === STEP_TYPE.TRANSFORM) {
|
|
350
|
+
return (
|
|
351
|
+
<MultiOperatorEditor
|
|
352
|
+
operators={
|
|
353
|
+
Array.isArray(data.config?.operators) ? data.config.operators : []
|
|
354
|
+
}
|
|
355
|
+
availableOperators={availableAdapters.map((a) => ({
|
|
356
|
+
code: a.code,
|
|
357
|
+
name: a.name,
|
|
358
|
+
description: a.description,
|
|
359
|
+
schema: a.schema,
|
|
360
|
+
}))}
|
|
361
|
+
onChange={updateOperators}
|
|
362
|
+
/>
|
|
363
|
+
);
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
// Steps with built-in config editors don't need the adapter selector empty state
|
|
367
|
+
const hasBuiltInConfig = stepType in SPECIAL_CONFIG_EDITORS;
|
|
368
|
+
if (hasBuiltInConfig && availableAdapters.length === 0) return null;
|
|
369
|
+
|
|
370
|
+
return (
|
|
371
|
+
<div className={compact ? 'space-y-2' : 'space-y-3'}>
|
|
372
|
+
<div className="flex items-center justify-between">
|
|
373
|
+
<Label className={compact ? 'text-xs' : 'text-sm'}>
|
|
374
|
+
{getAdapterTypeLabel(adapterType)}
|
|
375
|
+
</Label>
|
|
376
|
+
{showCheatSheet && adapterType === ADAPTER_TYPES.OPERATOR && !showHeader && (
|
|
377
|
+
<OperatorCheatSheetButton />
|
|
378
|
+
)}
|
|
379
|
+
</div>
|
|
380
|
+
|
|
381
|
+
{availableAdapters.length === 0 && isLoadingCatalog && (
|
|
382
|
+
<div className="p-3 bg-muted rounded-md">
|
|
383
|
+
<p className="text-sm text-muted-foreground">
|
|
384
|
+
Loading {getAdapterTypeLabel(adapterType).toLowerCase()}s...
|
|
385
|
+
</p>
|
|
386
|
+
</div>
|
|
387
|
+
)}
|
|
388
|
+
|
|
389
|
+
{availableAdapters.length > 0 && needsAdapterSelection && (
|
|
390
|
+
<AdapterRequiredWarning
|
|
391
|
+
adapterTypeLabel={getAdapterTypeLabel(adapterType).toLowerCase()}
|
|
392
|
+
compact={compact}
|
|
393
|
+
/>
|
|
394
|
+
)}
|
|
395
|
+
|
|
396
|
+
{availableAdapters.length > 0 && (
|
|
397
|
+
<AdapterSelector
|
|
398
|
+
stepType={stepType}
|
|
399
|
+
value={adapterCode}
|
|
400
|
+
onChange={handleAdapterCodeChange}
|
|
401
|
+
placeholder={`Select ${getAdapterTypeLabel(adapterType).toLowerCase()}...`}
|
|
402
|
+
adapters={availableAdapters}
|
|
403
|
+
/>
|
|
404
|
+
)}
|
|
405
|
+
|
|
406
|
+
{selectedAdapter && (
|
|
407
|
+
<div className="flex items-center gap-2 p-2 bg-muted/50 rounded border">
|
|
408
|
+
<div
|
|
409
|
+
className="w-7 h-7 rounded flex items-center justify-center text-white shrink-0"
|
|
410
|
+
style={{ backgroundColor: selectedAdapter.color }}
|
|
411
|
+
>
|
|
412
|
+
<selectedAdapter.icon className="w-3.5 h-3.5" />
|
|
413
|
+
</div>
|
|
414
|
+
<div className="min-w-0">
|
|
415
|
+
<div className="font-medium text-sm truncate">{selectedAdapter.name}</div>
|
|
416
|
+
<div className="text-xs text-muted-foreground truncate">
|
|
417
|
+
{selectedAdapter.description}
|
|
418
|
+
</div>
|
|
419
|
+
</div>
|
|
420
|
+
</div>
|
|
421
|
+
)}
|
|
422
|
+
</div>
|
|
423
|
+
);
|
|
424
|
+
};
|
|
425
|
+
|
|
426
|
+
const renderSchemaForm = () => {
|
|
427
|
+
if (!selectedAdapter?.schema?.fields?.length) return null;
|
|
428
|
+
|
|
429
|
+
const content = (
|
|
430
|
+
<SchemaFormRenderer
|
|
431
|
+
schema={{ fields: dynamicFields }}
|
|
432
|
+
values={data.config}
|
|
433
|
+
onChange={updateConfigBatch}
|
|
434
|
+
secretCodes={secretOptions.map((s) => s.code)}
|
|
435
|
+
compact={compact}
|
|
436
|
+
/>
|
|
437
|
+
);
|
|
438
|
+
|
|
439
|
+
if (variant === PANEL_VARIANT.PANEL) {
|
|
440
|
+
return (
|
|
441
|
+
<>
|
|
442
|
+
<Separator />
|
|
443
|
+
<div className={compact ? 'space-y-2' : 'space-y-3'}>
|
|
444
|
+
<div className="flex items-center justify-between">
|
|
445
|
+
<h4 className="font-medium text-sm text-muted-foreground uppercase tracking-wide">
|
|
446
|
+
Configuration
|
|
447
|
+
</h4>
|
|
448
|
+
<Button
|
|
449
|
+
variant="ghost"
|
|
450
|
+
size="sm"
|
|
451
|
+
className="h-6 text-xs"
|
|
452
|
+
onClick={handleResetDefaults}
|
|
453
|
+
>
|
|
454
|
+
Reset defaults
|
|
455
|
+
</Button>
|
|
456
|
+
</div>
|
|
457
|
+
{content}
|
|
458
|
+
</div>
|
|
459
|
+
</>
|
|
460
|
+
);
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
return (
|
|
464
|
+
<Card>
|
|
465
|
+
<CardHeader className="py-3">
|
|
466
|
+
<CardTitle className="text-sm">Configuration</CardTitle>
|
|
467
|
+
</CardHeader>
|
|
468
|
+
<CardContent>{content}</CardContent>
|
|
469
|
+
</Card>
|
|
470
|
+
);
|
|
471
|
+
};
|
|
472
|
+
|
|
473
|
+
const renderAdvancedEditors = () => {
|
|
474
|
+
if (!showAdvancedEditors || adapterType !== ADAPTER_TYPES.OPERATOR) return null;
|
|
475
|
+
|
|
476
|
+
const editorType = selectedAdapter?.editorType ?? selectedAdapter?.code;
|
|
477
|
+
if (!editorType) return null;
|
|
478
|
+
|
|
479
|
+
const AdvancedEditor = ADVANCED_EDITORS[editorType];
|
|
480
|
+
return AdvancedEditor ? <AdvancedEditor config={data.config} onChange={updateConfigBatch} /> : null;
|
|
481
|
+
};
|
|
482
|
+
|
|
483
|
+
const renderSpecialConfigs = () => {
|
|
484
|
+
const SpecialEditor = SPECIAL_CONFIG_EDITORS[stepType];
|
|
485
|
+
if (!SpecialEditor) return null;
|
|
486
|
+
|
|
487
|
+
return (
|
|
488
|
+
<SpecialEditor
|
|
489
|
+
config={data.config}
|
|
490
|
+
onChange={updateConfigBatch}
|
|
491
|
+
showErrorHandling={variant === PANEL_VARIANT.PANEL}
|
|
492
|
+
showValidationMode={true}
|
|
493
|
+
showRulesEditor={true}
|
|
494
|
+
/>
|
|
495
|
+
);
|
|
496
|
+
};
|
|
497
|
+
|
|
498
|
+
const handleRetryChange = useCallback((retrySettings: RetrySettings | undefined) => {
|
|
499
|
+
onChange({
|
|
500
|
+
...data,
|
|
501
|
+
config: {
|
|
502
|
+
...data.config,
|
|
503
|
+
retryMaxRetries: retrySettings?.maxRetries,
|
|
504
|
+
retryDelayMs: retrySettings?.retryDelayMs,
|
|
505
|
+
retryBackoff: retrySettings?.backoff,
|
|
506
|
+
},
|
|
507
|
+
});
|
|
508
|
+
}, [onChange, data]);
|
|
509
|
+
|
|
510
|
+
const renderRetrySettings = () => {
|
|
511
|
+
if (stepType !== STEP_TYPE.TRANSFORM) return null;
|
|
512
|
+
|
|
513
|
+
const retrySettings: RetrySettings = {
|
|
514
|
+
maxRetries: data.config?.retryMaxRetries as number | undefined,
|
|
515
|
+
retryDelayMs: data.config?.retryDelayMs as number | undefined,
|
|
516
|
+
backoff: data.config?.retryBackoff as RetrySettings['backoff'],
|
|
517
|
+
};
|
|
518
|
+
|
|
519
|
+
return (
|
|
520
|
+
<RetrySettingsComponent
|
|
521
|
+
retrySettings={retrySettings}
|
|
522
|
+
onChange={handleRetryChange}
|
|
523
|
+
/>
|
|
524
|
+
);
|
|
525
|
+
};
|
|
526
|
+
|
|
527
|
+
const renderStepTester = () => {
|
|
528
|
+
if (
|
|
529
|
+
!showStepTester ||
|
|
530
|
+
stepType === STEP_TYPE.TRIGGER ||
|
|
531
|
+
!adapterType ||
|
|
532
|
+
!selectedAdapter
|
|
533
|
+
) {
|
|
534
|
+
return null;
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
return (
|
|
538
|
+
<>
|
|
539
|
+
{variant === PANEL_VARIANT.PANEL && <Separator />}
|
|
540
|
+
<StepTester
|
|
541
|
+
stepType={stepType}
|
|
542
|
+
adapterType={adapterType}
|
|
543
|
+
config={{ adapterCode: data.adapterCode, ...(data.config || {}) }}
|
|
544
|
+
/>
|
|
545
|
+
</>
|
|
546
|
+
);
|
|
547
|
+
};
|
|
548
|
+
|
|
549
|
+
const spacing = compact ? 'space-y-3' : 'space-y-4';
|
|
550
|
+
|
|
551
|
+
return (
|
|
552
|
+
<div className={spacing}>
|
|
553
|
+
{renderHeader()}
|
|
554
|
+
{renderKeyInput()}
|
|
555
|
+
{renderTriggerConfig()}
|
|
556
|
+
{renderAdapterSelection()}
|
|
557
|
+
{renderSchemaForm()}
|
|
558
|
+
{renderSpecialConfigs()}
|
|
559
|
+
{renderAdvancedEditors()}
|
|
560
|
+
{renderRetrySettings()}
|
|
561
|
+
{renderStepTester()}
|
|
562
|
+
</div>
|
|
563
|
+
);
|
|
564
|
+
}
|