payload-wordpress-migrator 0.0.22
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/LICENSE +21 -0
- package/README.md +586 -0
- package/dist/components/BeforeDashboardClient.d.ts +14 -0
- package/dist/components/BeforeDashboardClient.js +225 -0
- package/dist/components/BeforeDashboardClient.js.map +1 -0
- package/dist/components/BeforeDashboardClient.module.css +175 -0
- package/dist/components/BeforeDashboardServer.d.ts +1 -0
- package/dist/components/BeforeDashboardServer.js +29 -0
- package/dist/components/BeforeDashboardServer.js.map +1 -0
- package/dist/components/ContentTypeSelect.d.ts +4 -0
- package/dist/components/ContentTypeSelect.js +147 -0
- package/dist/components/ContentTypeSelect.js.map +1 -0
- package/dist/components/FieldMappingConfiguration.d.ts +5 -0
- package/dist/components/FieldMappingConfiguration.js +361 -0
- package/dist/components/FieldMappingConfiguration.js.map +1 -0
- package/dist/components/FieldMappingConfiguration.module.css +75 -0
- package/dist/components/MigrationDashboardClient.d.ts +6 -0
- package/dist/components/MigrationDashboardClient.js +49 -0
- package/dist/components/MigrationDashboardClient.js.map +1 -0
- package/dist/components/MigrationDashboardClient.module.css +749 -0
- package/dist/components/SimpleFieldMapping.d.ts +5 -0
- package/dist/components/SimpleFieldMapping.js +437 -0
- package/dist/components/SimpleFieldMapping.js.map +1 -0
- package/dist/components/dashboard/JobActionButtons.d.ts +8 -0
- package/dist/components/dashboard/JobActionButtons.js +91 -0
- package/dist/components/dashboard/JobActionButtons.js.map +1 -0
- package/dist/components/dashboard/JobsTable.d.ts +6 -0
- package/dist/components/dashboard/JobsTable.js +86 -0
- package/dist/components/dashboard/JobsTable.js.map +1 -0
- package/dist/components/dashboard/LogViewer.d.ts +3 -0
- package/dist/components/dashboard/LogViewer.js +35 -0
- package/dist/components/dashboard/LogViewer.js.map +1 -0
- package/dist/components/dashboard/SiteConfigPanel.d.ts +12 -0
- package/dist/components/dashboard/SiteConfigPanel.js +205 -0
- package/dist/components/dashboard/SiteConfigPanel.js.map +1 -0
- package/dist/components/dashboard/StatsOverview.d.ts +5 -0
- package/dist/components/dashboard/StatsOverview.js +72 -0
- package/dist/components/dashboard/StatsOverview.js.map +1 -0
- package/dist/components/dashboard/index.d.ts +7 -0
- package/dist/components/dashboard/index.js +7 -0
- package/dist/components/dashboard/index.js.map +1 -0
- package/dist/components/dashboard/types.d.ts +46 -0
- package/dist/components/dashboard/types.js +2 -0
- package/dist/components/dashboard/types.js.map +1 -0
- package/dist/components/dashboard/useMigrationDashboard.d.ts +15 -0
- package/dist/components/dashboard/useMigrationDashboard.js +584 -0
- package/dist/components/dashboard/useMigrationDashboard.js.map +1 -0
- package/dist/exports/client.d.ts +4 -0
- package/dist/exports/client.js +5 -0
- package/dist/exports/client.js.map +1 -0
- package/dist/exports/rsc.d.ts +1 -0
- package/dist/exports/rsc.js +2 -0
- package/dist/exports/rsc.js.map +1 -0
- package/dist/index.d.ts +101 -0
- package/dist/index.js +443 -0
- package/dist/index.js.map +1 -0
- package/dist/utils/content/blocks.d.ts +6 -0
- package/dist/utils/content/blocks.js +93 -0
- package/dist/utils/content/blocks.js.map +1 -0
- package/dist/utils/content/fieldMapping.d.ts +9 -0
- package/dist/utils/content/fieldMapping.js +218 -0
- package/dist/utils/content/fieldMapping.js.map +1 -0
- package/dist/utils/content/index.d.ts +4 -0
- package/dist/utils/content/index.js +4 -0
- package/dist/utils/content/index.js.map +1 -0
- package/dist/utils/content/transformer.d.ts +5 -0
- package/dist/utils/content/transformer.js +323 -0
- package/dist/utils/content/transformer.js.map +1 -0
- package/dist/utils/endpoints/handlers.d.ts +9 -0
- package/dist/utils/endpoints/handlers.js +201 -0
- package/dist/utils/endpoints/handlers.js.map +1 -0
- package/dist/utils/endpoints/index.d.ts +2 -0
- package/dist/utils/endpoints/index.js +2 -0
- package/dist/utils/endpoints/index.js.map +1 -0
- package/dist/utils/fields/analyzer.d.ts +7 -0
- package/dist/utils/fields/analyzer.js +502 -0
- package/dist/utils/fields/analyzer.js.map +1 -0
- package/dist/utils/fields/index.d.ts +2 -0
- package/dist/utils/fields/index.js +2 -0
- package/dist/utils/fields/index.js.map +1 -0
- package/dist/utils/helpers/auth.d.ts +9 -0
- package/dist/utils/helpers/auth.js +50 -0
- package/dist/utils/helpers/auth.js.map +1 -0
- package/dist/utils/helpers/cache.d.ts +11 -0
- package/dist/utils/helpers/cache.js +47 -0
- package/dist/utils/helpers/cache.js.map +1 -0
- package/dist/utils/helpers/concurrency.d.ts +2 -0
- package/dist/utils/helpers/concurrency.js +26 -0
- package/dist/utils/helpers/concurrency.js.map +1 -0
- package/dist/utils/helpers/index.d.ts +8 -0
- package/dist/utils/helpers/index.js +8 -0
- package/dist/utils/helpers/index.js.map +1 -0
- package/dist/utils/helpers/objectHelpers.d.ts +3 -0
- package/dist/utils/helpers/objectHelpers.js +22 -0
- package/dist/utils/helpers/objectHelpers.js.map +1 -0
- package/dist/utils/helpers/rateLimiter.d.ts +10 -0
- package/dist/utils/helpers/rateLimiter.js +29 -0
- package/dist/utils/helpers/rateLimiter.js.map +1 -0
- package/dist/utils/helpers/responses.d.ts +3 -0
- package/dist/utils/helpers/responses.js +23 -0
- package/dist/utils/helpers/responses.js.map +1 -0
- package/dist/utils/helpers/wpHelpers.d.ts +6 -0
- package/dist/utils/helpers/wpHelpers.js +29 -0
- package/dist/utils/helpers/wpHelpers.js.map +1 -0
- package/dist/utils/lexical/constants.d.ts +37 -0
- package/dist/utils/lexical/constants.js +58 -0
- package/dist/utils/lexical/constants.js.map +1 -0
- package/dist/utils/lexical/htmlParser.d.ts +20 -0
- package/dist/utils/lexical/htmlParser.js +253 -0
- package/dist/utils/lexical/htmlParser.js.map +1 -0
- package/dist/utils/lexical/htmlToLexicalConverter.d.ts +55 -0
- package/dist/utils/lexical/htmlToLexicalConverter.js +999 -0
- package/dist/utils/lexical/htmlToLexicalConverter.js.map +1 -0
- package/dist/utils/lexical/index.d.ts +5 -0
- package/dist/utils/lexical/index.js +4 -0
- package/dist/utils/lexical/index.js.map +1 -0
- package/dist/utils/lexical/nodeFactories.d.ts +21 -0
- package/dist/utils/lexical/nodeFactories.js +91 -0
- package/dist/utils/lexical/nodeFactories.js.map +1 -0
- package/dist/utils/lexical/preprocessor.d.ts +4 -0
- package/dist/utils/lexical/preprocessor.js +302 -0
- package/dist/utils/lexical/preprocessor.js.map +1 -0
- package/dist/utils/media/download.d.ts +7 -0
- package/dist/utils/media/download.js +85 -0
- package/dist/utils/media/download.js.map +1 -0
- package/dist/utils/media/extraction.d.ts +12 -0
- package/dist/utils/media/extraction.js +58 -0
- package/dist/utils/media/extraction.js.map +1 -0
- package/dist/utils/media/import.d.ts +7 -0
- package/dist/utils/media/import.js +146 -0
- package/dist/utils/media/import.js.map +1 -0
- package/dist/utils/media/index.d.ts +6 -0
- package/dist/utils/media/index.js +6 -0
- package/dist/utils/media/index.js.map +1 -0
- package/dist/utils/media/upload.d.ts +4 -0
- package/dist/utils/media/upload.js +46 -0
- package/dist/utils/media/upload.js.map +1 -0
- package/dist/utils/media/validation.d.ts +8 -0
- package/dist/utils/media/validation.js +60 -0
- package/dist/utils/media/validation.js.map +1 -0
- package/dist/utils/migration/index.d.ts +3 -0
- package/dist/utils/migration/index.js +3 -0
- package/dist/utils/migration/index.js.map +1 -0
- package/dist/utils/migration/jobCrud.d.ts +4 -0
- package/dist/utils/migration/jobCrud.js +380 -0
- package/dist/utils/migration/jobCrud.js.map +1 -0
- package/dist/utils/migration/orchestrator.d.ts +5 -0
- package/dist/utils/migration/orchestrator.js +756 -0
- package/dist/utils/migration/orchestrator.js.map +1 -0
- package/dist/utils/types.d.ts +201 -0
- package/dist/utils/types.js +14 -0
- package/dist/utils/types.js.map +1 -0
- package/dist/utils/wordpress/client.d.ts +61 -0
- package/dist/utils/wordpress/client.js +365 -0
- package/dist/utils/wordpress/client.js.map +1 -0
- package/dist/utils/wordpress/index.d.ts +2 -0
- package/dist/utils/wordpress/index.js +2 -0
- package/dist/utils/wordpress/index.js.map +1 -0
- package/dist/utils/wordpressApi.d.ts +11 -0
- package/dist/utils/wordpressApi.js +25 -0
- package/dist/utils/wordpressApi.js.map +1 -0
- package/package.json +155 -0
|
@@ -0,0 +1,437 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
|
|
3
|
+
import { useField } from '@payloadcms/ui';
|
|
4
|
+
import { useRef, useState, useEffect } from 'react';
|
|
5
|
+
|
|
6
|
+
const SimpleFieldMapping = ({ path })=>{
|
|
7
|
+
const { setValue, value } = useField({
|
|
8
|
+
path
|
|
9
|
+
});
|
|
10
|
+
const { value: contentTypeValue } = useField({
|
|
11
|
+
path: 'contentType'
|
|
12
|
+
});
|
|
13
|
+
const { value: targetCollectionValue } = useField({
|
|
14
|
+
path: 'targetCollection'
|
|
15
|
+
});
|
|
16
|
+
// Use ref to prevent infinite loops - change to any type to handle different value types
|
|
17
|
+
const isUpdatingRef = useRef(false);
|
|
18
|
+
const lastValueRef = useRef('');
|
|
19
|
+
// Dynamic field options from API
|
|
20
|
+
const [sourceFields, setSourceFields] = useState([]);
|
|
21
|
+
const [destinationFields, setDestinationFields] = useState([]);
|
|
22
|
+
const [fieldMappings, setFieldMappings] = useState([
|
|
23
|
+
{
|
|
24
|
+
destinationField: '',
|
|
25
|
+
sourceField: ''
|
|
26
|
+
}
|
|
27
|
+
]);
|
|
28
|
+
const [loading, setLoading] = useState(false);
|
|
29
|
+
const [error, setError] = useState('');
|
|
30
|
+
// Fetch WordPress content fields
|
|
31
|
+
const fetchWordPressFields = async (contentType)=>{
|
|
32
|
+
try {
|
|
33
|
+
setLoading(true);
|
|
34
|
+
setError('');
|
|
35
|
+
const savedConfig = localStorage.getItem('wp-site-config');
|
|
36
|
+
if (!savedConfig) {
|
|
37
|
+
throw new Error('WordPress site configuration not found');
|
|
38
|
+
}
|
|
39
|
+
const config = JSON.parse(savedConfig);
|
|
40
|
+
const requestBody = {
|
|
41
|
+
contentType,
|
|
42
|
+
wpPassword: config.wpPassword,
|
|
43
|
+
wpSiteUrl: config.wpSiteUrl,
|
|
44
|
+
wpUsername: config.wpUsername
|
|
45
|
+
};
|
|
46
|
+
const response = await fetch('/api/wordpress/content-fields', {
|
|
47
|
+
body: JSON.stringify(requestBody),
|
|
48
|
+
headers: {
|
|
49
|
+
'Content-Type': 'application/json'
|
|
50
|
+
},
|
|
51
|
+
method: 'POST'
|
|
52
|
+
});
|
|
53
|
+
const result = await response.json();
|
|
54
|
+
if (response.ok && result.success) {
|
|
55
|
+
const wpFieldOptions = (result.fields || []).map((field)=>({
|
|
56
|
+
type: field.type,
|
|
57
|
+
label: `${field.label} (${field.type})${field.custom ? ' *' : ''}`,
|
|
58
|
+
path: field.path || field.name,
|
|
59
|
+
value: field.path || field.name
|
|
60
|
+
}));
|
|
61
|
+
setSourceFields(wpFieldOptions);
|
|
62
|
+
} else {
|
|
63
|
+
console.error('API returned error:', result);
|
|
64
|
+
throw new Error(result.error || 'Failed to fetch WordPress fields');
|
|
65
|
+
}
|
|
66
|
+
} catch (error) {
|
|
67
|
+
console.error('Error fetching WordPress fields:', error);
|
|
68
|
+
setError(error instanceof Error ? error.message : 'Failed to fetch WordPress fields');
|
|
69
|
+
setSourceFields([]);
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
// Fetch PayloadCMS collection fields
|
|
73
|
+
const fetchPayloadFields = async (collectionSlug)=>{
|
|
74
|
+
try {
|
|
75
|
+
const response = await fetch(`/api/collections/${collectionSlug}/fields`);
|
|
76
|
+
const result = await response.json();
|
|
77
|
+
if (response.ok && result.success) {
|
|
78
|
+
const payloadFieldOptions = (result.fields || []).map((field)=>({
|
|
79
|
+
type: field.type,
|
|
80
|
+
label: `${field.label} (${field.type})`,
|
|
81
|
+
path: field.path || field.name,
|
|
82
|
+
value: field.path || field.name
|
|
83
|
+
}));
|
|
84
|
+
setDestinationFields(payloadFieldOptions);
|
|
85
|
+
} else {
|
|
86
|
+
console.error('Payload API returned error:', result);
|
|
87
|
+
throw new Error(result.error || 'Failed to fetch Payload collection fields');
|
|
88
|
+
}
|
|
89
|
+
} catch (error) {
|
|
90
|
+
console.error('Error fetching Payload fields:', error);
|
|
91
|
+
setDestinationFields([]);
|
|
92
|
+
}
|
|
93
|
+
};
|
|
94
|
+
// Fetch fields when both content type and target collection are selected
|
|
95
|
+
useEffect(()=>{
|
|
96
|
+
const fetchFields = async ()=>{
|
|
97
|
+
if (contentTypeValue && targetCollectionValue) {
|
|
98
|
+
setLoading(true);
|
|
99
|
+
try {
|
|
100
|
+
await Promise.all([
|
|
101
|
+
fetchWordPressFields(contentTypeValue),
|
|
102
|
+
fetchPayloadFields(targetCollectionValue)
|
|
103
|
+
]);
|
|
104
|
+
} catch (error) {
|
|
105
|
+
console.error('Error fetching fields:', error);
|
|
106
|
+
} finally{
|
|
107
|
+
setLoading(false);
|
|
108
|
+
}
|
|
109
|
+
} else {
|
|
110
|
+
setSourceFields([]);
|
|
111
|
+
setDestinationFields([]);
|
|
112
|
+
setFieldMappings([
|
|
113
|
+
{
|
|
114
|
+
destinationField: '',
|
|
115
|
+
sourceField: ''
|
|
116
|
+
}
|
|
117
|
+
]);
|
|
118
|
+
setError('');
|
|
119
|
+
}
|
|
120
|
+
};
|
|
121
|
+
void fetchFields();
|
|
122
|
+
}, [
|
|
123
|
+
contentTypeValue,
|
|
124
|
+
targetCollectionValue
|
|
125
|
+
]);
|
|
126
|
+
// Parse existing field mappings from JSON value - only when value actually changes
|
|
127
|
+
useEffect(()=>{
|
|
128
|
+
if (isUpdatingRef.current) {
|
|
129
|
+
return;
|
|
130
|
+
} // Prevent processing our own updates
|
|
131
|
+
// Convert value to string for comparison
|
|
132
|
+
const currentValue = typeof value === 'string' ? value : JSON.stringify(value || '');
|
|
133
|
+
if (value && currentValue !== lastValueRef.current) {
|
|
134
|
+
try {
|
|
135
|
+
const parsed = typeof value === 'string' ? JSON.parse(value) : value;
|
|
136
|
+
if (parsed && Array.isArray(parsed.fieldMappings)) {
|
|
137
|
+
setFieldMappings(parsed.fieldMappings);
|
|
138
|
+
}
|
|
139
|
+
lastValueRef.current = currentValue;
|
|
140
|
+
} catch (error) {
|
|
141
|
+
console.warn('Failed to parse field mappings:', error);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}, [
|
|
145
|
+
value
|
|
146
|
+
]);
|
|
147
|
+
// Function to update parent value without causing loops
|
|
148
|
+
const updateParentValue = (mappings)=>{
|
|
149
|
+
const newValue = JSON.stringify({
|
|
150
|
+
contentType: contentTypeValue,
|
|
151
|
+
fieldMappings: mappings,
|
|
152
|
+
targetCollection: targetCollectionValue
|
|
153
|
+
});
|
|
154
|
+
// Prevent infinite loops
|
|
155
|
+
if (newValue !== lastValueRef.current && !isUpdatingRef.current) {
|
|
156
|
+
isUpdatingRef.current = true;
|
|
157
|
+
setValue(newValue);
|
|
158
|
+
lastValueRef.current = newValue;
|
|
159
|
+
// Reset the flag after a short delay
|
|
160
|
+
setTimeout(()=>{
|
|
161
|
+
isUpdatingRef.current = false;
|
|
162
|
+
}, 100);
|
|
163
|
+
}
|
|
164
|
+
};
|
|
165
|
+
// Add new mapping row
|
|
166
|
+
const handleAddMapping = ()=>{
|
|
167
|
+
const newMappings = [
|
|
168
|
+
...fieldMappings,
|
|
169
|
+
{
|
|
170
|
+
destinationField: '',
|
|
171
|
+
sourceField: ''
|
|
172
|
+
}
|
|
173
|
+
];
|
|
174
|
+
setFieldMappings(newMappings);
|
|
175
|
+
updateParentValue(newMappings);
|
|
176
|
+
};
|
|
177
|
+
// Remove mapping row
|
|
178
|
+
const handleRemoveMapping = (idx)=>{
|
|
179
|
+
if (fieldMappings.length <= 1) {
|
|
180
|
+
return;
|
|
181
|
+
} // Keep at least one mapping
|
|
182
|
+
const newMappings = fieldMappings.filter((_, i)=>i !== idx);
|
|
183
|
+
setFieldMappings(newMappings);
|
|
184
|
+
updateParentValue(newMappings);
|
|
185
|
+
};
|
|
186
|
+
// Update mapping
|
|
187
|
+
const handleChange = (idx, field, newValue)=>{
|
|
188
|
+
const newMappings = fieldMappings.map((mapping, i)=>i === idx ? {
|
|
189
|
+
...mapping,
|
|
190
|
+
[field]: newValue
|
|
191
|
+
} : mapping);
|
|
192
|
+
setFieldMappings(newMappings);
|
|
193
|
+
updateParentValue(newMappings);
|
|
194
|
+
};
|
|
195
|
+
// Filter dropdown options to exclude already-mapped fields (except for current row)
|
|
196
|
+
const getFilteredOptions = (options, field, idx)=>{
|
|
197
|
+
const used = fieldMappings.map((m, i)=>i !== idx ? m[field] : null).filter(Boolean);
|
|
198
|
+
return options.filter((opt)=>!used.includes(opt.value));
|
|
199
|
+
};
|
|
200
|
+
if (!contentTypeValue || !targetCollectionValue) {
|
|
201
|
+
return /*#__PURE__*/ jsxs("div", {
|
|
202
|
+
style: {
|
|
203
|
+
display: 'flex',
|
|
204
|
+
flexDirection: 'column',
|
|
205
|
+
gap: '1rem'
|
|
206
|
+
},
|
|
207
|
+
children: [
|
|
208
|
+
/*#__PURE__*/ jsx("label", {
|
|
209
|
+
style: {
|
|
210
|
+
color: 'var(--theme-elevation-700)',
|
|
211
|
+
fontSize: '14px',
|
|
212
|
+
fontWeight: '600'
|
|
213
|
+
},
|
|
214
|
+
children: "Field Mapping Configuration"
|
|
215
|
+
}),
|
|
216
|
+
/*#__PURE__*/ jsx("div", {
|
|
217
|
+
style: {
|
|
218
|
+
backgroundColor: 'var(--theme-elevation-50)',
|
|
219
|
+
border: '1px solid var(--theme-elevation-200)',
|
|
220
|
+
borderRadius: '4px',
|
|
221
|
+
color: 'var(--theme-elevation-600)',
|
|
222
|
+
padding: '1rem',
|
|
223
|
+
textAlign: 'center'
|
|
224
|
+
},
|
|
225
|
+
children: 'Please select both "Content Type to Migrate" and "Target Payload Collection" to configure field mappings.'
|
|
226
|
+
})
|
|
227
|
+
]
|
|
228
|
+
});
|
|
229
|
+
}
|
|
230
|
+
return /*#__PURE__*/ jsxs("div", {
|
|
231
|
+
style: {
|
|
232
|
+
display: 'flex',
|
|
233
|
+
flexDirection: 'column',
|
|
234
|
+
gap: '1rem'
|
|
235
|
+
},
|
|
236
|
+
children: [
|
|
237
|
+
/*#__PURE__*/ jsxs("div", {
|
|
238
|
+
style: {
|
|
239
|
+
alignItems: 'center',
|
|
240
|
+
display: 'flex',
|
|
241
|
+
justifyContent: 'space-between'
|
|
242
|
+
},
|
|
243
|
+
children: [
|
|
244
|
+
/*#__PURE__*/ jsx("label", {
|
|
245
|
+
style: {
|
|
246
|
+
color: 'var(--theme-elevation-700)',
|
|
247
|
+
fontSize: '14px',
|
|
248
|
+
fontWeight: '600'
|
|
249
|
+
},
|
|
250
|
+
children: "Field Mapping Configuration"
|
|
251
|
+
}),
|
|
252
|
+
/*#__PURE__*/ jsx("button", {
|
|
253
|
+
disabled: loading,
|
|
254
|
+
onClick: handleAddMapping,
|
|
255
|
+
style: {
|
|
256
|
+
backgroundColor: loading ? 'var(--theme-elevation-200)' : 'var(--theme-success-600)',
|
|
257
|
+
border: 'none',
|
|
258
|
+
borderRadius: '4px',
|
|
259
|
+
color: loading ? 'var(--theme-elevation-500)' : 'white',
|
|
260
|
+
cursor: loading ? 'not-allowed' : 'pointer',
|
|
261
|
+
fontSize: '12px',
|
|
262
|
+
fontWeight: '500',
|
|
263
|
+
padding: '0.5rem 1rem'
|
|
264
|
+
},
|
|
265
|
+
type: "button",
|
|
266
|
+
children: "Add Mapping"
|
|
267
|
+
})
|
|
268
|
+
]
|
|
269
|
+
}),
|
|
270
|
+
loading && /*#__PURE__*/ jsx("div", {
|
|
271
|
+
style: {
|
|
272
|
+
backgroundColor: 'var(--theme-elevation-50)',
|
|
273
|
+
border: '1px solid var(--theme-elevation-200)',
|
|
274
|
+
borderRadius: '4px',
|
|
275
|
+
color: 'var(--theme-elevation-600)',
|
|
276
|
+
padding: '1rem',
|
|
277
|
+
textAlign: 'center'
|
|
278
|
+
},
|
|
279
|
+
children: "Loading field schemas from WordPress and PayloadCMS..."
|
|
280
|
+
}),
|
|
281
|
+
error && /*#__PURE__*/ jsxs("div", {
|
|
282
|
+
style: {
|
|
283
|
+
backgroundColor: 'var(--theme-error-50)',
|
|
284
|
+
border: '1px solid var(--theme-error-200)',
|
|
285
|
+
borderRadius: '4px',
|
|
286
|
+
color: 'var(--theme-error-700)',
|
|
287
|
+
padding: '1rem'
|
|
288
|
+
},
|
|
289
|
+
children: [
|
|
290
|
+
/*#__PURE__*/ jsx("strong", {
|
|
291
|
+
children: "Error:"
|
|
292
|
+
}),
|
|
293
|
+
" ",
|
|
294
|
+
error
|
|
295
|
+
]
|
|
296
|
+
}),
|
|
297
|
+
!loading && !error && sourceFields.length === 0 && destinationFields.length === 0 && /*#__PURE__*/ jsx("div", {
|
|
298
|
+
style: {
|
|
299
|
+
backgroundColor: 'var(--theme-elevation-50)',
|
|
300
|
+
border: '1px solid var(--theme-elevation-200)',
|
|
301
|
+
borderRadius: '4px',
|
|
302
|
+
color: 'var(--theme-elevation-600)',
|
|
303
|
+
padding: '1rem',
|
|
304
|
+
textAlign: 'center'
|
|
305
|
+
},
|
|
306
|
+
children: "No fields found. Please check your WordPress connection and selected content type."
|
|
307
|
+
}),
|
|
308
|
+
!loading && !error && (sourceFields.length > 0 || destinationFields.length > 0) && /*#__PURE__*/ jsxs(Fragment, {
|
|
309
|
+
children: [
|
|
310
|
+
fieldMappings.length === 0 && /*#__PURE__*/ jsx("div", {
|
|
311
|
+
style: {
|
|
312
|
+
backgroundColor: 'var(--theme-elevation-50)',
|
|
313
|
+
border: '1px solid var(--theme-elevation-200)',
|
|
314
|
+
borderRadius: '4px',
|
|
315
|
+
color: 'var(--theme-elevation-600)',
|
|
316
|
+
padding: '1rem',
|
|
317
|
+
textAlign: 'center'
|
|
318
|
+
},
|
|
319
|
+
children: 'No field mappings configured. Click "Add Mapping" to start.'
|
|
320
|
+
}),
|
|
321
|
+
fieldMappings.map((mapping, idx)=>/*#__PURE__*/ jsxs("div", {
|
|
322
|
+
style: {
|
|
323
|
+
alignItems: 'center',
|
|
324
|
+
backgroundColor: 'var(--theme-elevation-0)',
|
|
325
|
+
border: '1px solid var(--theme-elevation-200)',
|
|
326
|
+
borderRadius: '4px',
|
|
327
|
+
display: 'grid',
|
|
328
|
+
gap: '0.75rem',
|
|
329
|
+
gridTemplateColumns: '1fr auto 1fr auto',
|
|
330
|
+
padding: '1rem'
|
|
331
|
+
},
|
|
332
|
+
children: [
|
|
333
|
+
/*#__PURE__*/ jsxs("select", {
|
|
334
|
+
onChange: (e)=>handleChange(idx, 'sourceField', e.target.value),
|
|
335
|
+
style: {
|
|
336
|
+
backgroundColor: 'var(--theme-elevation-0)',
|
|
337
|
+
border: '1px solid var(--theme-elevation-200)',
|
|
338
|
+
borderRadius: '4px',
|
|
339
|
+
fontSize: '14px',
|
|
340
|
+
padding: '0.5rem'
|
|
341
|
+
},
|
|
342
|
+
value: mapping.sourceField,
|
|
343
|
+
children: [
|
|
344
|
+
/*#__PURE__*/ jsx("option", {
|
|
345
|
+
value: "",
|
|
346
|
+
children: "Select WordPress field..."
|
|
347
|
+
}),
|
|
348
|
+
getFilteredOptions(sourceFields, 'sourceField', idx).map((opt, optIdx)=>/*#__PURE__*/ jsx("option", {
|
|
349
|
+
value: opt.value,
|
|
350
|
+
children: opt.label
|
|
351
|
+
}, `source-${idx}-${opt.value}-${optIdx}`))
|
|
352
|
+
]
|
|
353
|
+
}),
|
|
354
|
+
/*#__PURE__*/ jsx("span", {
|
|
355
|
+
style: {
|
|
356
|
+
color: 'var(--theme-elevation-400)',
|
|
357
|
+
fontSize: '18px',
|
|
358
|
+
fontWeight: 'bold'
|
|
359
|
+
},
|
|
360
|
+
children: "→"
|
|
361
|
+
}),
|
|
362
|
+
/*#__PURE__*/ jsxs("select", {
|
|
363
|
+
onChange: (e)=>handleChange(idx, 'destinationField', e.target.value),
|
|
364
|
+
style: {
|
|
365
|
+
backgroundColor: 'var(--theme-elevation-0)',
|
|
366
|
+
border: '1px solid var(--theme-elevation-200)',
|
|
367
|
+
borderRadius: '4px',
|
|
368
|
+
fontSize: '14px',
|
|
369
|
+
padding: '0.5rem'
|
|
370
|
+
},
|
|
371
|
+
value: mapping.destinationField,
|
|
372
|
+
children: [
|
|
373
|
+
/*#__PURE__*/ jsx("option", {
|
|
374
|
+
value: "",
|
|
375
|
+
children: "Select Payload field..."
|
|
376
|
+
}),
|
|
377
|
+
getFilteredOptions(destinationFields, 'destinationField', idx).map((opt, optIdx)=>/*#__PURE__*/ jsx("option", {
|
|
378
|
+
value: opt.value,
|
|
379
|
+
children: opt.label
|
|
380
|
+
}, `dest-${idx}-${opt.value}-${optIdx}`))
|
|
381
|
+
]
|
|
382
|
+
}),
|
|
383
|
+
/*#__PURE__*/ jsx("button", {
|
|
384
|
+
disabled: fieldMappings.length <= 1,
|
|
385
|
+
onClick: ()=>handleRemoveMapping(idx),
|
|
386
|
+
style: {
|
|
387
|
+
backgroundColor: fieldMappings.length <= 1 ? 'var(--theme-elevation-200)' : 'var(--theme-error-600)',
|
|
388
|
+
border: 'none',
|
|
389
|
+
borderRadius: '4px',
|
|
390
|
+
color: fieldMappings.length <= 1 ? 'var(--theme-elevation-500)' : 'white',
|
|
391
|
+
cursor: fieldMappings.length <= 1 ? 'not-allowed' : 'pointer',
|
|
392
|
+
fontSize: '12px',
|
|
393
|
+
fontWeight: '500',
|
|
394
|
+
minWidth: '60px',
|
|
395
|
+
padding: '0.5rem'
|
|
396
|
+
},
|
|
397
|
+
type: "button",
|
|
398
|
+
children: "Remove"
|
|
399
|
+
})
|
|
400
|
+
]
|
|
401
|
+
}, idx))
|
|
402
|
+
]
|
|
403
|
+
}),
|
|
404
|
+
/*#__PURE__*/ jsxs("div", {
|
|
405
|
+
style: {
|
|
406
|
+
color: 'var(--theme-elevation-500)',
|
|
407
|
+
fontSize: '12px',
|
|
408
|
+
fontStyle: 'italic',
|
|
409
|
+
marginTop: '0.5rem'
|
|
410
|
+
},
|
|
411
|
+
children: [
|
|
412
|
+
"Map WordPress fields to their corresponding Payload fields. Each field can only be mapped once. Fields marked with * are custom fields (ACF/Meta).",
|
|
413
|
+
sourceFields.length > 0 && /*#__PURE__*/ jsxs(Fragment, {
|
|
414
|
+
children: [
|
|
415
|
+
/*#__PURE__*/ jsx("br", {}),
|
|
416
|
+
/*#__PURE__*/ jsx("strong", {
|
|
417
|
+
children: "Available WordPress fields:"
|
|
418
|
+
}),
|
|
419
|
+
" ",
|
|
420
|
+
sourceFields.length,
|
|
421
|
+
" |",
|
|
422
|
+
' ',
|
|
423
|
+
/*#__PURE__*/ jsx("strong", {
|
|
424
|
+
children: "Available Payload fields:"
|
|
425
|
+
}),
|
|
426
|
+
" ",
|
|
427
|
+
destinationFields.length
|
|
428
|
+
]
|
|
429
|
+
})
|
|
430
|
+
]
|
|
431
|
+
})
|
|
432
|
+
]
|
|
433
|
+
});
|
|
434
|
+
};
|
|
435
|
+
|
|
436
|
+
export { SimpleFieldMapping as default };
|
|
437
|
+
//# sourceMappingURL=SimpleFieldMapping.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SimpleFieldMapping.js","sources":["../../src/components/SimpleFieldMapping.tsx"],"sourcesContent":["'use client'\n\nimport { useField } from '@payloadcms/ui'\nimport React, { useEffect, useRef, useState } from 'react'\n\ntype FieldMapping = {\n destinationField: string\n sourceField: string\n}\n\ntype Option = {\n label: string\n path?: string\n type?: string\n value: string\n}\n\nconst SimpleFieldMapping: React.FC<{ path: string }> = ({ path }) => {\n const { setValue, value } = useField({ path })\n const { value: contentTypeValue } = useField({ path: 'contentType' })\n const { value: targetCollectionValue } = useField({ path: 'targetCollection' })\n\n // Use ref to prevent infinite loops - change to any type to handle different value types\n const isUpdatingRef = useRef(false)\n const lastValueRef = useRef<any>('')\n\n // Dynamic field options from API\n const [sourceFields, setSourceFields] = useState<Option[]>([])\n const [destinationFields, setDestinationFields] = useState<Option[]>([])\n const [fieldMappings, setFieldMappings] = useState<FieldMapping[]>([\n { destinationField: '', sourceField: '' },\n ])\n const [loading, setLoading] = useState(false)\n const [error, setError] = useState('')\n\n // Fetch WordPress content fields\n const fetchWordPressFields = async (contentType: string) => {\n try {\n setLoading(true)\n setError('')\n\n const savedConfig = localStorage.getItem('wp-site-config')\n if (!savedConfig) {\n throw new Error('WordPress site configuration not found')\n }\n\n const config = JSON.parse(savedConfig)\n\n const requestBody = {\n contentType,\n wpPassword: config.wpPassword,\n wpSiteUrl: config.wpSiteUrl,\n wpUsername: config.wpUsername,\n }\n\n const response = await fetch('/api/wordpress/content-fields', {\n body: JSON.stringify(requestBody),\n headers: {\n 'Content-Type': 'application/json',\n },\n method: 'POST',\n })\n const result = await response.json()\n\n if (response.ok && result.success) {\n const wpFieldOptions = (result.fields || []).map((field: any) => ({\n type: field.type,\n label: `${field.label} (${field.type})${field.custom ? ' *' : ''}`,\n path: field.path || field.name,\n value: field.path || field.name,\n }))\n setSourceFields(wpFieldOptions)\n } else {\n console.error('API returned error:', result)\n throw new Error(result.error || 'Failed to fetch WordPress fields')\n }\n } catch (error) {\n console.error('Error fetching WordPress fields:', error)\n setError(error instanceof Error ? error.message : 'Failed to fetch WordPress fields')\n setSourceFields([])\n }\n }\n\n // Fetch PayloadCMS collection fields\n const fetchPayloadFields = async (collectionSlug: string) => {\n try {\n const response = await fetch(`/api/collections/${collectionSlug}/fields`)\n\n const result = await response.json()\n\n if (response.ok && result.success) {\n const payloadFieldOptions = (result.fields || []).map((field: any) => ({\n type: field.type,\n label: `${field.label} (${field.type})`,\n path: field.path || field.name,\n value: field.path || field.name,\n }))\n setDestinationFields(payloadFieldOptions)\n } else {\n console.error('Payload API returned error:', result)\n throw new Error(result.error || 'Failed to fetch Payload collection fields')\n }\n } catch (error) {\n console.error('Error fetching Payload fields:', error)\n setDestinationFields([])\n }\n }\n\n // Fetch fields when both content type and target collection are selected\n useEffect(() => {\n const fetchFields = async () => {\n if (contentTypeValue && targetCollectionValue) {\n setLoading(true)\n try {\n await Promise.all([\n fetchWordPressFields(contentTypeValue as string),\n fetchPayloadFields(targetCollectionValue as string),\n ])\n } catch (error) {\n console.error('Error fetching fields:', error)\n } finally {\n setLoading(false)\n }\n } else {\n setSourceFields([])\n setDestinationFields([])\n setFieldMappings([{ destinationField: '', sourceField: '' }])\n setError('')\n }\n }\n\n void fetchFields()\n }, [contentTypeValue, targetCollectionValue])\n\n // Parse existing field mappings from JSON value - only when value actually changes\n useEffect(() => {\n if (isUpdatingRef.current) {\n return\n } // Prevent processing our own updates\n\n // Convert value to string for comparison\n const currentValue = typeof value === 'string' ? value : JSON.stringify(value || '')\n\n if (value && currentValue !== lastValueRef.current) {\n try {\n const parsed = typeof value === 'string' ? JSON.parse(value) : value\n if (parsed && Array.isArray(parsed.fieldMappings)) {\n setFieldMappings(parsed.fieldMappings)\n }\n lastValueRef.current = currentValue\n } catch (error) {\n console.warn('Failed to parse field mappings:', error)\n }\n }\n }, [value])\n\n // Function to update parent value without causing loops\n const updateParentValue = (mappings: FieldMapping[]) => {\n const newValue = JSON.stringify({\n contentType: contentTypeValue,\n fieldMappings: mappings,\n targetCollection: targetCollectionValue,\n })\n\n // Prevent infinite loops\n if (newValue !== lastValueRef.current && !isUpdatingRef.current) {\n isUpdatingRef.current = true\n setValue(newValue)\n lastValueRef.current = newValue\n\n // Reset the flag after a short delay\n setTimeout(() => {\n isUpdatingRef.current = false\n }, 100)\n }\n }\n\n // Add new mapping row\n const handleAddMapping = () => {\n const newMappings = [...fieldMappings, { destinationField: '', sourceField: '' }]\n setFieldMappings(newMappings)\n updateParentValue(newMappings)\n }\n\n // Remove mapping row\n const handleRemoveMapping = (idx: number) => {\n if (fieldMappings.length <= 1) {\n return\n } // Keep at least one mapping\n\n const newMappings = fieldMappings.filter((_, i) => i !== idx)\n setFieldMappings(newMappings)\n updateParentValue(newMappings)\n }\n\n // Update mapping\n const handleChange = (idx: number, field: keyof FieldMapping, newValue: string) => {\n const newMappings = fieldMappings.map((mapping, i) =>\n i === idx ? { ...mapping, [field]: newValue } : mapping,\n )\n setFieldMappings(newMappings)\n updateParentValue(newMappings)\n }\n\n // Filter dropdown options to exclude already-mapped fields (except for current row)\n const getFilteredOptions = (options: Option[], field: keyof FieldMapping, idx: number) => {\n const used = fieldMappings\n .map((m, i) => (i !== idx ? m[field] : null))\n .filter(Boolean) as string[]\n return options.filter((opt) => !used.includes(opt.value))\n }\n\n if (!contentTypeValue || !targetCollectionValue) {\n return (\n <div style={{ display: 'flex', flexDirection: 'column', gap: '1rem' }}>\n <label style={{ color: 'var(--theme-elevation-700)', fontSize: '14px', fontWeight: '600' }}>\n Field Mapping Configuration\n </label>\n <div\n style={{\n backgroundColor: 'var(--theme-elevation-50)',\n border: '1px solid var(--theme-elevation-200)',\n borderRadius: '4px',\n color: 'var(--theme-elevation-600)',\n padding: '1rem',\n textAlign: 'center',\n }}\n >\n Please select both \"Content Type to Migrate\" and \"Target Payload Collection\" to configure\n field mappings.\n </div>\n </div>\n )\n }\n\n return (\n <div style={{ display: 'flex', flexDirection: 'column', gap: '1rem' }}>\n <div style={{ alignItems: 'center', display: 'flex', justifyContent: 'space-between' }}>\n <label style={{ color: 'var(--theme-elevation-700)', fontSize: '14px', fontWeight: '600' }}>\n Field Mapping Configuration\n </label>\n <button\n disabled={loading}\n onClick={handleAddMapping}\n style={{\n backgroundColor: loading ? 'var(--theme-elevation-200)' : 'var(--theme-success-600)',\n border: 'none',\n borderRadius: '4px',\n color: loading ? 'var(--theme-elevation-500)' : 'white',\n cursor: loading ? 'not-allowed' : 'pointer',\n fontSize: '12px',\n fontWeight: '500',\n padding: '0.5rem 1rem',\n }}\n type=\"button\"\n >\n Add Mapping\n </button>\n </div>\n\n {loading && (\n <div\n style={{\n backgroundColor: 'var(--theme-elevation-50)',\n border: '1px solid var(--theme-elevation-200)',\n borderRadius: '4px',\n color: 'var(--theme-elevation-600)',\n padding: '1rem',\n textAlign: 'center',\n }}\n >\n Loading field schemas from WordPress and PayloadCMS...\n </div>\n )}\n\n {error && (\n <div\n style={{\n backgroundColor: 'var(--theme-error-50)',\n border: '1px solid var(--theme-error-200)',\n borderRadius: '4px',\n color: 'var(--theme-error-700)',\n padding: '1rem',\n }}\n >\n <strong>Error:</strong> {error}\n </div>\n )}\n\n {!loading && !error && sourceFields.length === 0 && destinationFields.length === 0 && (\n <div\n style={{\n backgroundColor: 'var(--theme-elevation-50)',\n border: '1px solid var(--theme-elevation-200)',\n borderRadius: '4px',\n color: 'var(--theme-elevation-600)',\n padding: '1rem',\n textAlign: 'center',\n }}\n >\n No fields found. Please check your WordPress connection and selected content type.\n </div>\n )}\n\n {!loading && !error && (sourceFields.length > 0 || destinationFields.length > 0) && (\n <>\n {fieldMappings.length === 0 && (\n <div\n style={{\n backgroundColor: 'var(--theme-elevation-50)',\n border: '1px solid var(--theme-elevation-200)',\n borderRadius: '4px',\n color: 'var(--theme-elevation-600)',\n padding: '1rem',\n textAlign: 'center',\n }}\n >\n No field mappings configured. Click \"Add Mapping\" to start.\n </div>\n )}\n\n {fieldMappings.map((mapping, idx) => (\n <div\n key={idx}\n style={{\n alignItems: 'center',\n backgroundColor: 'var(--theme-elevation-0)',\n border: '1px solid var(--theme-elevation-200)',\n borderRadius: '4px',\n display: 'grid',\n gap: '0.75rem',\n gridTemplateColumns: '1fr auto 1fr auto',\n padding: '1rem',\n }}\n >\n <select\n onChange={(e) => handleChange(idx, 'sourceField', e.target.value)}\n style={{\n backgroundColor: 'var(--theme-elevation-0)',\n border: '1px solid var(--theme-elevation-200)',\n borderRadius: '4px',\n fontSize: '14px',\n padding: '0.5rem',\n }}\n value={mapping.sourceField}\n >\n <option value=\"\">Select WordPress field...</option>\n {getFilteredOptions(sourceFields, 'sourceField', idx).map((opt, optIdx) => (\n <option key={`source-${idx}-${opt.value}-${optIdx}`} value={opt.value}>\n {opt.label}\n </option>\n ))}\n </select>\n\n <span\n style={{\n color: 'var(--theme-elevation-400)',\n fontSize: '18px',\n fontWeight: 'bold',\n }}\n >\n →\n </span>\n\n <select\n onChange={(e) => handleChange(idx, 'destinationField', e.target.value)}\n style={{\n backgroundColor: 'var(--theme-elevation-0)',\n border: '1px solid var(--theme-elevation-200)',\n borderRadius: '4px',\n fontSize: '14px',\n padding: '0.5rem',\n }}\n value={mapping.destinationField}\n >\n <option value=\"\">Select Payload field...</option>\n {getFilteredOptions(destinationFields, 'destinationField', idx).map(\n (opt, optIdx) => (\n <option key={`dest-${idx}-${opt.value}-${optIdx}`} value={opt.value}>\n {opt.label}\n </option>\n ),\n )}\n </select>\n\n <button\n disabled={fieldMappings.length <= 1}\n onClick={() => handleRemoveMapping(idx)}\n style={{\n backgroundColor:\n fieldMappings.length <= 1\n ? 'var(--theme-elevation-200)'\n : 'var(--theme-error-600)',\n border: 'none',\n borderRadius: '4px',\n color: fieldMappings.length <= 1 ? 'var(--theme-elevation-500)' : 'white',\n cursor: fieldMappings.length <= 1 ? 'not-allowed' : 'pointer',\n fontSize: '12px',\n fontWeight: '500',\n minWidth: '60px',\n padding: '0.5rem',\n }}\n type=\"button\"\n >\n Remove\n </button>\n </div>\n ))}\n </>\n )}\n\n <div\n style={{\n color: 'var(--theme-elevation-500)',\n fontSize: '12px',\n fontStyle: 'italic',\n marginTop: '0.5rem',\n }}\n >\n Map WordPress fields to their corresponding Payload fields. Each field can only be mapped\n once. Fields marked with * are custom fields (ACF/Meta).\n {sourceFields.length > 0 && (\n <>\n <br />\n <strong>Available WordPress fields:</strong> {sourceFields.length} |{' '}\n <strong>Available Payload fields:</strong> {destinationFields.length}\n </>\n )}\n </div>\n </div>\n )\n}\n\nexport default SimpleFieldMapping\n"],"names":["path","contentType","wpPassword","wpSiteUrl","wpUsername","type","label","value","setError","setSourceFields","setDestinationFields","contentTypeValue","targetCollectionValue","setFieldMappings","lastValueRef","isUpdatingRef","fieldMappings","backgroundColor","color","cursor","loading","error","opt","onClick","idx","sourceFields","destinationFields"],"mappings":";;;;;AAiBA;AACE;AAAuCA;AAAK;AAC5C;;AAAmE;AACnE;;AAA6E;;AAG7E;AACA;;AAGA;AACA;AACA;AACE;;;AAAwC;AACzC;AACD;AACA;;AAGA;;;;;AAMI;AACE;AACF;;AAIA;AACEC;AACAC;AACAC;AACAC;AACF;;;;;AAME;;AAEF;;AAGA;AACE;AACEC;AACAC;AACAN;AACAO;;;;;AAKF;AACF;AACF;;AAEEC;AACAC;AACF;AACF;;AAGA;;;;AAMI;AACE;AACEJ;;AAEAL;AACAO;;;;;AAKF;AACF;AACF;;AAEEG;AACF;AACF;;;AAIE;AACE;;;;;;AAMK;AACH;;;;AAIA;;AAEAD;AACAC;;AACkB;;;AAAwC;AAAE;;AAE9D;AACF;;;AAGEC;AAAkBC;AAAsB;;;;AAKxC;AACF;;;AAKA;;AAEI;AACA;AACEC;AACF;AACAC;AACF;;AAEA;AACF;;AACEP;AAAM;;AAGV;;;;;AAKE;;AAGA;AACEQ;;AAEAD;;;AAIEC;;AAEJ;AACF;;AAGA;AACE;AAAwBC;AAAe;;;AAAwC;AAAE;;;AAGnF;;AAGA;;AAEI;AACF;AAEA;;;AAGF;;;;AAKkB;AAAY;;;;AAI9B;;;AAIE;;AAIF;;AAGE;;;;;AACsE;;;;;;;AACuB;AAAG;;;;;;;;;;AAW1F;AACD;;;;AAMP;AAEA;;;;;AACsE;;;;;;;AACmB;;;;;;;AACM;AAAG;;;;;;AAOxFC;;;AAGAC;AACAC;;;;AAIF;;AAED;;;;AAKFC;;;;;;;;AASG;AACD;;AAKFC;;;;;;;AAQG;;;AAEQ;;AAAe;AAAEA;;;;;;;;;;;AAazB;AACD;;AAKF;;;;;;;;;;AAWO;AACD;;AAKFL;;;;;;;;;;AAYG;;;;;;;;;;AAUE;AACAT;;;;AAEiB;;;AAEsCA;AAClDe;;;;;;;;;AAUL;AACD;;;;;;;;;;AAYC;AACAf;;;;AAEiB;;;AAGsCA;AAChDe;;;;;;AAQPC;;AAEEN;;;AAMAC;AACAC;;;;;AAKF;;AAED;;;AAhFIK;;;;;;;;;AA8FX;;AACD;;;;;AAMa;;AAAoC;AAAEC;AAAoB;AAAG;;AAC7D;;AAAkC;AAAEC;;;;;;;AAMxD;;"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { JobActionType } from './types';
|
|
2
|
+
export declare const JobActionButtons: ({ jobId, loading, onAction, status, successRate, }: {
|
|
3
|
+
jobId: string;
|
|
4
|
+
loading: boolean;
|
|
5
|
+
onAction: (action: JobActionType, jobId: string) => Promise<void>;
|
|
6
|
+
status: string;
|
|
7
|
+
successRate: number;
|
|
8
|
+
}) => import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
|
|
3
|
+
import styles from '../MigrationDashboardClient.module.css';
|
|
4
|
+
|
|
5
|
+
const JobActionButtons = ({ jobId, loading, onAction, status, successRate })=>{
|
|
6
|
+
return /*#__PURE__*/ jsxs("div", {
|
|
7
|
+
className: styles.jobActions,
|
|
8
|
+
children: [
|
|
9
|
+
status === 'ready' && /*#__PURE__*/ jsx("button", {
|
|
10
|
+
className: styles.actionButton,
|
|
11
|
+
disabled: loading,
|
|
12
|
+
onClick: ()=>onAction('start', jobId),
|
|
13
|
+
children: "Start"
|
|
14
|
+
}),
|
|
15
|
+
status === 'running' && /*#__PURE__*/ jsx("button", {
|
|
16
|
+
className: styles.actionButton,
|
|
17
|
+
onClick: ()=>onAction('pause', jobId),
|
|
18
|
+
children: "Pause"
|
|
19
|
+
}),
|
|
20
|
+
status === 'paused' && /*#__PURE__*/ jsxs(Fragment, {
|
|
21
|
+
children: [
|
|
22
|
+
/*#__PURE__*/ jsx("button", {
|
|
23
|
+
className: styles.actionButton,
|
|
24
|
+
disabled: loading,
|
|
25
|
+
onClick: ()=>onAction('resume', jobId),
|
|
26
|
+
children: "Resume"
|
|
27
|
+
}),
|
|
28
|
+
/*#__PURE__*/ jsx("button", {
|
|
29
|
+
className: `${styles.actionButton} ${styles.restartButton}`,
|
|
30
|
+
disabled: loading,
|
|
31
|
+
onClick: ()=>onAction('restart', jobId),
|
|
32
|
+
title: "Restart entire migration from beginning",
|
|
33
|
+
children: "Restart"
|
|
34
|
+
})
|
|
35
|
+
]
|
|
36
|
+
}),
|
|
37
|
+
status === 'failed' && /*#__PURE__*/ jsxs(Fragment, {
|
|
38
|
+
children: [
|
|
39
|
+
/*#__PURE__*/ jsx("button", {
|
|
40
|
+
className: `${styles.actionButton} ${styles.retryButton}`,
|
|
41
|
+
disabled: loading,
|
|
42
|
+
onClick: ()=>onAction('retry', jobId),
|
|
43
|
+
children: "Retry"
|
|
44
|
+
}),
|
|
45
|
+
/*#__PURE__*/ jsx("button", {
|
|
46
|
+
className: `${styles.actionButton} ${styles.rollbackButton}`,
|
|
47
|
+
disabled: loading,
|
|
48
|
+
onClick: ()=>onAction('rollback', jobId),
|
|
49
|
+
title: "Delete all items created by this migration",
|
|
50
|
+
children: "Rollback"
|
|
51
|
+
})
|
|
52
|
+
]
|
|
53
|
+
}),
|
|
54
|
+
status === 'completed' && successRate < 100 && /*#__PURE__*/ jsx("button", {
|
|
55
|
+
className: `${styles.actionButton} ${styles.retryButton}`,
|
|
56
|
+
disabled: loading,
|
|
57
|
+
onClick: ()=>onAction('retry', jobId),
|
|
58
|
+
title: "Retry failed items",
|
|
59
|
+
children: "Retry Failed"
|
|
60
|
+
}),
|
|
61
|
+
status === 'completed' && /*#__PURE__*/ jsxs(Fragment, {
|
|
62
|
+
children: [
|
|
63
|
+
/*#__PURE__*/ jsx("button", {
|
|
64
|
+
className: `${styles.actionButton} ${styles.updateButton}`,
|
|
65
|
+
disabled: loading,
|
|
66
|
+
onClick: ()=>onAction('update', jobId),
|
|
67
|
+
title: "Update existing items with new field mappings",
|
|
68
|
+
children: "Update"
|
|
69
|
+
}),
|
|
70
|
+
/*#__PURE__*/ jsx("button", {
|
|
71
|
+
className: `${styles.actionButton} ${styles.restartButton}`,
|
|
72
|
+
disabled: loading,
|
|
73
|
+
onClick: ()=>onAction('restart', jobId),
|
|
74
|
+
title: "Restart entire migration from beginning",
|
|
75
|
+
children: "Restart"
|
|
76
|
+
}),
|
|
77
|
+
/*#__PURE__*/ jsx("button", {
|
|
78
|
+
className: `${styles.actionButton} ${styles.rollbackButton}`,
|
|
79
|
+
disabled: loading,
|
|
80
|
+
onClick: ()=>onAction('rollback', jobId),
|
|
81
|
+
title: "Delete all items created by this migration",
|
|
82
|
+
children: "Rollback"
|
|
83
|
+
})
|
|
84
|
+
]
|
|
85
|
+
})
|
|
86
|
+
]
|
|
87
|
+
});
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
export { JobActionButtons };
|
|
91
|
+
//# sourceMappingURL=JobActionButtons.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"JobActionButtons.js","sources":["../../../src/components/dashboard/JobActionButtons.tsx"],"sourcesContent":["'use client'\n\nimport type { JobActionType } from './types'\n\nimport styles from '../MigrationDashboardClient.module.css'\n\nexport const JobActionButtons = ({\n jobId,\n loading,\n onAction,\n status,\n successRate,\n}: {\n jobId: string\n loading: boolean\n onAction: (action: JobActionType, jobId: string) => Promise<void>\n status: string\n successRate: number\n}) => {\n return (\n <div className={styles.jobActions}>\n {status === 'ready' && (\n <button\n className={styles.actionButton}\n disabled={loading}\n onClick={() => onAction('start', jobId)}\n >\n Start\n </button>\n )}\n {status === 'running' && (\n <button\n className={styles.actionButton}\n onClick={() => onAction('pause', jobId)}\n >\n Pause\n </button>\n )}\n {status === 'paused' && (\n <>\n <button\n className={styles.actionButton}\n disabled={loading}\n onClick={() => onAction('resume', jobId)}\n >\n Resume\n </button>\n <button\n className={`${styles.actionButton} ${styles.restartButton}`}\n disabled={loading}\n onClick={() => onAction('restart', jobId)}\n title=\"Restart entire migration from beginning\"\n >\n Restart\n </button>\n </>\n )}\n {status === 'failed' && (\n <>\n <button\n className={`${styles.actionButton} ${styles.retryButton}`}\n disabled={loading}\n onClick={() => onAction('retry', jobId)}\n >\n Retry\n </button>\n <button\n className={`${styles.actionButton} ${styles.rollbackButton}`}\n disabled={loading}\n onClick={() => onAction('rollback', jobId)}\n title=\"Delete all items created by this migration\"\n >\n Rollback\n </button>\n </>\n )}\n {status === 'completed' && successRate < 100 && (\n <button\n className={`${styles.actionButton} ${styles.retryButton}`}\n disabled={loading}\n onClick={() => onAction('retry', jobId)}\n title=\"Retry failed items\"\n >\n Retry Failed\n </button>\n )}\n {status === 'completed' && (\n <>\n <button\n className={`${styles.actionButton} ${styles.updateButton}`}\n disabled={loading}\n onClick={() => onAction('update', jobId)}\n title=\"Update existing items with new field mappings\"\n >\n Update\n </button>\n <button\n className={`${styles.actionButton} ${styles.restartButton}`}\n disabled={loading}\n onClick={() => onAction('restart', jobId)}\n title=\"Restart entire migration from beginning\"\n >\n Restart\n </button>\n <button\n className={`${styles.actionButton} ${styles.rollbackButton}`}\n disabled={loading}\n onClick={() => onAction('rollback', jobId)}\n title=\"Delete all items created by this migration\"\n >\n Rollback\n </button>\n </>\n )}\n </div>\n )\n}\n"],"names":["className","status"],"mappings":";;;;AAMO;AAaL;AACOA;;AACFC;AAEGD;;;AAGD;;AAIFC;AAEGD;;AAED;;AAIFC;;;AAGKD;;;AAGD;;;;;;;AAQA;;;;AAKJC;;;;;;AAMI;;;;;;;AAQA;;;;;;;;;AAWF;;AAIFA;;;;;;;AAOI;;;;;;;AAQA;;;;;;;AAQA;;;;;;AAOX;;"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { JobActionType, MigrationSummary } from './types';
|
|
2
|
+
export declare const JobsTable: ({ jobs, loading, onJobAction, }: {
|
|
3
|
+
jobs: MigrationSummary["recentJobs"];
|
|
4
|
+
loading: boolean;
|
|
5
|
+
onJobAction: (action: JobActionType, jobId: string) => Promise<void>;
|
|
6
|
+
}) => import("react/jsx-runtime").JSX.Element;
|