@power-maverick/tool-data-migrator 0.0.1
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/README.md +238 -0
- package/dist/index.css +1 -0
- package/dist/index.html +13 -0
- package/dist/index.js +44 -0
- package/dist/index.js.map +1 -0
- package/npm-shrinkwrap.json +3594 -0
- package/package.json +57 -0
package/README.md
ADDED
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
# Data Migrator
|
|
2
|
+
|
|
3
|
+
Migrate data from one Dataverse environment to another with intelligent auto-mapping and smart operations.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
The Data Migrator is a React-based tool designed exclusively for Power Platform ToolBox (PPTB) that enables seamless data transfer between Dataverse environments with advanced features:
|
|
8
|
+
|
|
9
|
+
- **Auto-Mapping**: Automatically map users, teams, and business units between environments
|
|
10
|
+
- **Smart Operations**: Choose between create, update, or upsert operations
|
|
11
|
+
- **Field Selection**: Select which fields to migrate
|
|
12
|
+
- **Lookup Handling**: Intelligent mapping of lookup fields and references
|
|
13
|
+
- **Progress Tracking**: Real-time progress monitoring with detailed status for each record
|
|
14
|
+
- **Batch Processing**: Efficient batch processing for large data sets
|
|
15
|
+
|
|
16
|
+
## Features
|
|
17
|
+
|
|
18
|
+
### Auto-Mapping
|
|
19
|
+
|
|
20
|
+
The tool automatically maps system entities between source and target environments:
|
|
21
|
+
|
|
22
|
+
- **Users**: Matched by domain name, email address, or full name
|
|
23
|
+
- **Teams**: Matched by name and team type
|
|
24
|
+
- **Business Units**: Matched by name
|
|
25
|
+
|
|
26
|
+
Each mapping includes a confidence level (high, medium, low) based on the matching criteria used.
|
|
27
|
+
|
|
28
|
+
### Smart Migration Operations
|
|
29
|
+
|
|
30
|
+
Choose the operation that fits your scenario:
|
|
31
|
+
|
|
32
|
+
- **Create**: Insert new records only (fails if record exists)
|
|
33
|
+
- **Update**: Update existing records by primary key (requires records to exist)
|
|
34
|
+
- **Delete**: Delete records from target environment by matching primary key
|
|
35
|
+
|
|
36
|
+
### Preview Before Migration
|
|
37
|
+
|
|
38
|
+
- Preview data before migration to verify the operation
|
|
39
|
+
- Shows action column (CREATE, UPDATE, DELETE)
|
|
40
|
+
- Displays primary ID, primary name, and selected fields
|
|
41
|
+
- Limited to first 100 records for quick review
|
|
42
|
+
- Confirm before starting the actual migration
|
|
43
|
+
|
|
44
|
+
### Field and Lookup Management
|
|
45
|
+
|
|
46
|
+
- Select which fields to include in the migration
|
|
47
|
+
- Fields are loaded on-demand after entity selection for better performance
|
|
48
|
+
- Configure lookup field mapping strategies:
|
|
49
|
+
- **Auto-Map**: Automatically map system entities (users, teams, business units)
|
|
50
|
+
- **Skip**: Exclude the lookup field from migration
|
|
51
|
+
|
|
52
|
+
### Flexible Filtering
|
|
53
|
+
|
|
54
|
+
- **OData Filters**: Use OData syntax for simple filtering
|
|
55
|
+
- Example: `statecode eq 0 and createdon gt 2024-01-01`
|
|
56
|
+
- **FetchXML Queries**: Use complete FetchXML for complex queries
|
|
57
|
+
- Supports advanced filtering, joins, and aggregations
|
|
58
|
+
- Toggle between filter types with a modern selector
|
|
59
|
+
|
|
60
|
+
### Advanced Options
|
|
61
|
+
|
|
62
|
+
- **Filter Query**: Apply OData or FetchXML filters to select specific records
|
|
63
|
+
- **Batch Size**: Control batch size for optimal performance (1-100 records per batch)
|
|
64
|
+
|
|
65
|
+
### Modern, Fluid UI
|
|
66
|
+
|
|
67
|
+
- **Step-based workflow**: Clear progression through configuration steps
|
|
68
|
+
- **Collapsible sections**: Minimize scrolling with expandable step cards
|
|
69
|
+
- **Modern design**: Gradient headers, card-based layout, smooth transitions
|
|
70
|
+
- **Responsive**: Works well on different screen sizes
|
|
71
|
+
- **Visual feedback**: Color-coded badges, progress indicators, and status displays
|
|
72
|
+
|
|
73
|
+
### Progress Tracking
|
|
74
|
+
|
|
75
|
+
Real-time monitoring with:
|
|
76
|
+
|
|
77
|
+
- Overall progress bar
|
|
78
|
+
- Statistics (total, successful, failed, skipped)
|
|
79
|
+
- Batch processing status
|
|
80
|
+
- Detailed record-by-record status with error messages
|
|
81
|
+
|
|
82
|
+
## Technical Stack
|
|
83
|
+
|
|
84
|
+
- **React 18** with TypeScript
|
|
85
|
+
- **Fluent UI React Components** for modern UI
|
|
86
|
+
- **Vite** for fast development and optimized builds
|
|
87
|
+
- **PPTB API** for all Dataverse operations
|
|
88
|
+
- **@pptb/types v1.0.16** - Latest PPTB type definitions
|
|
89
|
+
|
|
90
|
+
## Installation
|
|
91
|
+
|
|
92
|
+
This tool is distributed as part of the PPTB-Tools monorepo and can be installed in Power Platform ToolBox.
|
|
93
|
+
|
|
94
|
+
### Prerequisites
|
|
95
|
+
|
|
96
|
+
- Node.js >= 18.0.0
|
|
97
|
+
- npm >= 9.0.0
|
|
98
|
+
|
|
99
|
+
### Build
|
|
100
|
+
|
|
101
|
+
```bash
|
|
102
|
+
cd tools/data-migrator
|
|
103
|
+
npm install
|
|
104
|
+
npm run build
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
The build output will be in the `dist` directory.
|
|
108
|
+
|
|
109
|
+
## Usage in PPTB
|
|
110
|
+
|
|
111
|
+
The tool follows a step-by-step workflow:
|
|
112
|
+
|
|
113
|
+
1. **Install the tool** in Power Platform ToolBox
|
|
114
|
+
2. **Connect to your source environment** (primary connection)
|
|
115
|
+
3. **Select a secondary connection** as the target environment
|
|
116
|
+
4. **Open the Data Migrator tool**
|
|
117
|
+
5. The tool will display both connections:
|
|
118
|
+
- Source (Primary): Your source environment
|
|
119
|
+
- Target (Secondary): Your target environment
|
|
120
|
+
|
|
121
|
+
### Migration Workflow
|
|
122
|
+
|
|
123
|
+
6. **Select an entity** to migrate
|
|
124
|
+
- Entity data (without fields) loads initially for faster performance
|
|
125
|
+
7. **Wait for fields to load** automatically after entity selection
|
|
126
|
+
8. **Select fields** to include in the migration
|
|
127
|
+
9. **Add filter** (optional) to select a subset of records using OData syntax
|
|
128
|
+
10. **Choose migration operation** from settings:
|
|
129
|
+
- **Create**: Insert new records only
|
|
130
|
+
- **Update**: Update existing records by primary key
|
|
131
|
+
- **Delete**: Delete records from target environment
|
|
132
|
+
11. **Set batch size** (max 100 records per batch)
|
|
133
|
+
12. **Auto-map system entities** (optional):
|
|
134
|
+
- Click "Auto-Map System Entities" to map users, teams, and business units
|
|
135
|
+
- Review the auto-mapping results
|
|
136
|
+
13. **Preview the data** to be migrated:
|
|
137
|
+
- Shows Action column (CREATE, UPDATE, DELETE)
|
|
138
|
+
- Displays primary ID and primary name
|
|
139
|
+
- Shows selected fields
|
|
140
|
+
- Limited to first 100 records for preview
|
|
141
|
+
14. **Start Migration** from the preview and monitor progress
|
|
142
|
+
|
|
143
|
+
## Important Notes
|
|
144
|
+
|
|
145
|
+
- **Secondary Connection Required**: This tool requires both a primary (source) and secondary (target) connection to be configured in PPTB
|
|
146
|
+
- **Source Environment**: Data is read from the primary connection
|
|
147
|
+
- **Target Environment**: Data is written to the secondary connection
|
|
148
|
+
- **Auto-Mapping**: Users, teams, and business units are mapped between source and target environments
|
|
149
|
+
- **Preview First**: Always preview data before starting migration to verify the operation and data
|
|
150
|
+
- **Batch Limit**: Maximum batch size is 100 records for optimal performance
|
|
151
|
+
|
|
152
|
+
## Use Cases
|
|
153
|
+
|
|
154
|
+
- **Environment Refresh**: Migrate configuration or transactional data after environment refresh
|
|
155
|
+
- **Dev to Test Migration**: Move test data from development to test environments
|
|
156
|
+
- **Cross-Tenant Migration**: Transfer data between different tenants with user/team mapping
|
|
157
|
+
- **Partial Data Migration**: Use filters to migrate specific records
|
|
158
|
+
- **Data Deletion**: Remove specific records from target environment based on source data
|
|
159
|
+
|
|
160
|
+
## Architecture
|
|
161
|
+
|
|
162
|
+
### Components
|
|
163
|
+
|
|
164
|
+
- **App.tsx**: Main application component and state management
|
|
165
|
+
- **EntitySelector**: Entity selection dropdown
|
|
166
|
+
- **OperationSelector**: Migration operation selection
|
|
167
|
+
- **FieldSelector**: Field selection with bulk actions
|
|
168
|
+
- **LookupMapper**: Lookup field mapping configuration
|
|
169
|
+
- **MigrationProgress**: Real-time progress display
|
|
170
|
+
- **AutoMappingPanel**: Auto-mapping results modal
|
|
171
|
+
|
|
172
|
+
### Utilities
|
|
173
|
+
|
|
174
|
+
- **DataverseClient**: Handles all Dataverse API interactions via PPTB API
|
|
175
|
+
- **MigrationEngine**: Core migration logic with auto-mapping and transformation
|
|
176
|
+
|
|
177
|
+
## Design Philosophy
|
|
178
|
+
|
|
179
|
+
The UI follows a **modern minimalist approach**:
|
|
180
|
+
|
|
181
|
+
- No header or unnecessary chrome
|
|
182
|
+
- Compact layout to minimize scrolling
|
|
183
|
+
- Clear visual hierarchy
|
|
184
|
+
- Progressive disclosure (options appear as needed)
|
|
185
|
+
- Real-time feedback
|
|
186
|
+
- Clean, professional appearance
|
|
187
|
+
|
|
188
|
+
## Reference
|
|
189
|
+
|
|
190
|
+
This tool is inspired by [Colso.Xrm.DataTransporter](https://github.com/bcolpaert/Colso.Xrm.DataTransporter) with enhancements for modern React, PPTB integration, and improved user experience.
|
|
191
|
+
|
|
192
|
+
## Limitations
|
|
193
|
+
|
|
194
|
+
- Primary key-based operations only (for update and upsert)
|
|
195
|
+
- Lookup auto-mapping limited to system entities (users, teams, business units)
|
|
196
|
+
- Requires same metadata schema in source and target environments
|
|
197
|
+
- Large data sets may take time to migrate (monitor batch progress)
|
|
198
|
+
|
|
199
|
+
## Best Practices
|
|
200
|
+
|
|
201
|
+
1. **Test First**: Always test with a small data set first
|
|
202
|
+
2. **Use Filters**: Use OData filters to migrate specific records
|
|
203
|
+
3. **Check Mappings**: Review auto-mapping results before starting migration
|
|
204
|
+
4. **Monitor Progress**: Watch for errors during migration
|
|
205
|
+
5. **Backup Data**: Always backup target environment before migration
|
|
206
|
+
6. **Same Metadata**: Ensure source and target have matching entity/field schemas
|
|
207
|
+
|
|
208
|
+
## Troubleshooting
|
|
209
|
+
|
|
210
|
+
### Migration Fails
|
|
211
|
+
|
|
212
|
+
- Check that target environment has the same entity/field structure
|
|
213
|
+
- Verify required fields have values
|
|
214
|
+
- Review error messages in the progress panel
|
|
215
|
+
|
|
216
|
+
### Lookup Mapping Issues
|
|
217
|
+
|
|
218
|
+
- Run auto-mapping before starting migration
|
|
219
|
+
- Verify users/teams/business units exist in target environment
|
|
220
|
+
- Check that names match between environments
|
|
221
|
+
|
|
222
|
+
### Performance Issues
|
|
223
|
+
|
|
224
|
+
- Reduce batch size for better stability
|
|
225
|
+
- Use filters to migrate fewer records at once
|
|
226
|
+
- Check network connectivity
|
|
227
|
+
|
|
228
|
+
## Contributing
|
|
229
|
+
|
|
230
|
+
Contributions are welcome! Please feel free to submit a Pull Request.
|
|
231
|
+
|
|
232
|
+
## License
|
|
233
|
+
|
|
234
|
+
This project is licensed under the GPL-2.0 License - see the [LICENSE](../../LICENSE) file for details.
|
|
235
|
+
|
|
236
|
+
## Support
|
|
237
|
+
|
|
238
|
+
For issues, questions, or contributions, please visit the [GitHub repository](https://github.com/Power-Maverick/PPTB-Tools).
|
package/dist/index.css
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
:root{--primary-color: #0078d4;--primary-hover: #106ebe;--primary-light: #deecf9;--error-color: #d13438;--success-color: #107c10;--warning-color: #ff8c00;--border-color: #e1e1e1;--background: #f5f5f5;--background-light: #faf9f8;--card-bg: #ffffff;--text-primary: #323130;--text-secondary: #605e5c;--shadow-sm: 0 1px 3px rgba(0, 0, 0, .08);--shadow-md: 0 2px 6px rgba(0, 0, 0, .12);--shadow-lg: 0 4px 12px rgba(0, 0, 0, .15)}*{box-sizing:border-box}body{margin:0;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Fira Sans,Droid Sans,Helvetica Neue,sans-serif;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;font-size:14px;color:var(--text-primary);background-color:var(--background)}.app-container{min-height:100vh;background-color:var(--background)}.loading-container,.error-container{display:flex;flex-direction:column;align-items:center;justify-content:center;min-height:100vh;padding:20px}.loading-spinner{width:40px;height:40px;border:4px solid var(--border-color);border-top-color:var(--primary-color);border-radius:50%;animation:spin 1s linear infinite}@keyframes spin{to{transform:rotate(360deg)}}.error-banner{display:flex;justify-content:space-between;align-items:center;background-color:#fde7e9;color:var(--error-color);padding:12px 20px;border-left:4px solid var(--error-color);margin:16px;border-radius:4px;box-shadow:var(--shadow-sm)}.error-banner button{background:none;border:none;color:var(--error-color);font-size:20px;cursor:pointer;padding:0;width:24px;height:24px;display:flex;align-items:center;justify-content:center}.error-message-inline{display:flex;justify-content:space-between;align-items:center;background-color:#fde7e9;color:var(--error-color);padding:12px 16px;border-left:4px solid var(--error-color);margin-top:16px;border-radius:4px;box-shadow:var(--shadow-sm);animation:slideDown .3s ease-out}.error-message-inline button{background:none;border:none;color:var(--error-color);font-size:20px;cursor:pointer;padding:0;width:24px;height:24px;display:flex;align-items:center;justify-content:center}.error-message-progress{display:flex;justify-content:space-between;align-items:center;background-color:#fde7e9;color:var(--error-color);padding:12px 16px;border-left:4px solid var(--error-color);margin-bottom:16px;border-radius:4px}.error-message-progress button{background:none;border:none;color:var(--error-color);font-size:20px;cursor:pointer;padding:0;width:24px;height:24px;display:flex;align-items:center;justify-content:center}@keyframes slideDown{0%{opacity:0;transform:translateY(-10px)}to{opacity:1;transform:translateY(0)}}.config-toolbar{display:flex;gap:12px;margin-bottom:20px;padding:12px;background:var(--card-bg);border-radius:8px;box-shadow:var(--shadow-sm)}.content-fluid{max-width:1200px;margin:0 auto;padding:20px}.header-card{background:linear-gradient(135deg,var(--primary-color) 0%,#005a9e 100%);border-radius:12px;padding:24px;margin-bottom:20px;box-shadow:var(--shadow-md);color:#fff}.header-content{display:flex;justify-content:space-between;align-items:center;flex-wrap:wrap;gap:16px}.app-title{margin:0;font-size:28px;font-weight:600;color:#fff}.connection-flow{display:flex;align-items:center;gap:12px;flex-wrap:wrap}.connection-badge{background:#ffffff26;-webkit-backdrop-filter:blur(10px);backdrop-filter:blur(10px);border-radius:8px;padding:8px 16px;display:flex;flex-direction:column;gap:4px}.connection-badge.source{border-left:3px solid #4caf50}.connection-badge.target{border-left:3px solid #ff9800}.connection-label{font-size:10px;text-transform:uppercase;letter-spacing:.5px;opacity:.9}.connection-url{font-size:12px;font-weight:500}.flow-arrow{font-size:24px;opacity:.8}.steps-container{display:flex;flex-direction:column;gap:16px}.step-card{background:var(--card-bg);border-radius:12px;overflow:hidden;box-shadow:var(--shadow-sm);transition:all .3s ease}.step-card.active{box-shadow:var(--shadow-md)}.step-card.collapsed{box-shadow:var(--shadow-sm)}.step-card.collapsed .step-content{display:none}.step-header{display:flex;align-items:center;gap:16px;padding:16px 20px;background:var(--background-light);border-bottom:1px solid var(--border-color);cursor:pointer;transition:background .2s}.step-card.collapsed .step-header{border-bottom:none}.step-header:hover{background:#f0f0f0}.step-number{width:32px;height:32px;border-radius:50%;background:var(--primary-color);color:#fff;display:flex;align-items:center;justify-content:center;font-weight:600;font-size:14px;flex-shrink:0}.step-title{margin:0;font-size:16px;font-weight:600;flex:1}.step-count{font-size:12px;color:var(--text-secondary);background:var(--primary-light);padding:4px 12px;border-radius:12px}.step-badge{font-size:11px;color:var(--text-secondary);background:#e0e0e0;padding:4px 10px;border-radius:10px;text-transform:uppercase;letter-spacing:.5px}.step-toggle{width:24px;height:24px;display:flex;align-items:center;justify-content:center;font-size:20px;font-weight:600;color:var(--primary-color);flex-shrink:0}.step-content{padding:20px}.loading-card{display:flex;flex-direction:column;align-items:center;justify-content:center;padding:40px;background:var(--card-bg);border-radius:12px;box-shadow:var(--shadow-sm)}.loading-card p{margin:12px 0 0;color:var(--text-secondary)}.form-group{margin-bottom:16px}.form-group label{display:block;margin-bottom:8px;font-weight:600;font-size:13px;color:var(--text-primary)}.modern-input,.modern-textarea,select.modern-input{width:100%;padding:10px 14px;border:2px solid var(--border-color);border-radius:8px;font-size:14px;font-family:inherit;transition:all .2s;background:#fff}.modern-input:focus,.modern-textarea:focus,select.modern-input:focus{outline:none;border-color:var(--primary-color);box-shadow:0 0 0 3px var(--primary-light)}.modern-textarea{resize:vertical;font-family:Courier New,monospace;line-height:1.5}.field-hint{font-size:12px;color:var(--text-secondary);margin:6px 0 0}.filter-type-selector{display:flex;gap:8px;margin-bottom:16px;background:var(--background-light);padding:4px;border-radius:8px}.filter-type-btn{flex:1;padding:8px 16px;border:none;background:transparent;border-radius:6px;cursor:pointer;font-weight:500;font-size:13px;color:var(--text-secondary);transition:all .2s}.filter-type-btn.active{background:#fff;color:var(--primary-color);box-shadow:var(--shadow-sm)}.filter-type-btn:hover:not(.active){background:#ffffff80}.settings-grid{display:grid;grid-template-columns:1fr 1fr;gap:20px}@media(max-width:768px){.settings-grid{grid-template-columns:1fr}}.operation-checkboxes{display:flex;flex-direction:column;gap:12px;padding:12px;background:var(--background-light);border-radius:8px;border:2px solid var(--border-color)}.action-bar{display:flex;justify-content:center;padding:24px 0}.btn-preview{background:linear-gradient(135deg,var(--primary-color) 0%,#005a9e 100%);color:#fff;border:none;padding:14px 48px;font-size:15px;font-weight:600;border-radius:28px;cursor:pointer;transition:all .3s ease;box-shadow:var(--shadow-md);text-transform:uppercase;letter-spacing:.5px}.btn-preview:hover:not(:disabled){transform:translateY(-2px);box-shadow:var(--shadow-lg)}.btn-preview:disabled{background:#ccc;cursor:not-allowed;transform:none}.btn-primary{background-color:var(--primary-color);color:#fff;border:none;padding:10px 24px;font-size:14px;font-weight:500;border-radius:6px;cursor:pointer;transition:all .2s}.btn-primary:hover:not(:disabled){background-color:var(--primary-hover);transform:translateY(-1px);box-shadow:var(--shadow-sm)}.btn-primary:disabled{background-color:#ccc;cursor:not-allowed}.btn-secondary{background-color:#fff;color:var(--text-primary);border:2px solid var(--border-color);padding:8px 20px;font-size:14px;font-weight:500;border-radius:6px;cursor:pointer;transition:all .2s}.btn-secondary:hover:not(:disabled){background-color:var(--background-light);border-color:var(--primary-color)}.progress-card{background:var(--card-bg);border-radius:12px;padding:24px;margin-top:20px;box-shadow:var(--shadow-md)}.field-list{max-height:400px;overflow-y:auto;border:2px solid var(--border-color);border-radius:8px;padding:12px;background:#fff}.checkbox-group{display:flex;align-items:center;gap:10px;margin-bottom:10px;padding:8px;border-radius:6px;transition:background .2s}.checkbox-group:hover{background:var(--background-light)}.checkbox-group input[type=checkbox]{width:18px;height:18px;cursor:pointer}.checkbox-group label{margin:0;cursor:pointer;font-weight:400;flex:1}.lookup-list{border:2px solid var(--border-color);border-radius:8px;padding:12px;margin-bottom:12px;background:#fff}.lookup-item{display:flex;align-items:center;gap:12px;padding:10px;border-bottom:1px solid var(--border-color);border-radius:6px;transition:background .2s}.lookup-item:hover{background:var(--background-light)}.lookup-item:last-child{border-bottom:none}.lookup-item label{flex:1;margin:0;font-weight:400}.lookup-item select{width:150px;padding:6px 10px;border:2px solid var(--border-color);border-radius:6px;font-size:13px;transition:border .2s}.lookup-item select:focus{outline:none;border-color:var(--primary-color)}.modal-overlay{position:fixed;top:0;left:0;right:0;bottom:0;background-color:#00000080;display:flex;align-items:center;justify-content:center;z-index:1000;-webkit-backdrop-filter:blur(4px);backdrop-filter:blur(4px)}.modal{background:var(--card-bg);padding:0;border-radius:16px;max-width:90vw;width:1000px;max-height:85vh;overflow:hidden;box-shadow:var(--shadow-lg);display:flex;flex-direction:column}.modal-header{display:flex;justify-content:space-between;align-items:center;padding:20px 24px;border-bottom:1px solid var(--border-color);background:var(--background-light)}.modal-header h3{margin:0;font-size:18px;font-weight:600}.modal-close{background:none;border:none;font-size:24px;cursor:pointer;padding:0;width:32px;height:32px;display:flex;align-items:center;justify-content:center;border-radius:50%;transition:background .2s}.modal-close:hover{background:#0000000d}.preview-info{margin:20px 24px;padding:12px;background-color:var(--primary-light);border-radius:8px;border-left:4px solid var(--primary-color)}.preview-table-container{overflow:auto;max-height:calc(85vh - 250px);margin:0 24px;border:2px solid var(--border-color);border-radius:8px}.preview-table{width:100%;border-collapse:collapse;font-size:13px}.preview-table thead{position:sticky;top:0;background-color:var(--background-light);z-index:1}.preview-table th{padding:12px 8px;text-align:left;border-bottom:2px solid var(--border-color);font-weight:600;white-space:nowrap}.preview-table td{padding:10px 8px;border-bottom:1px solid #f0f0f0;max-width:300px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.preview-table tbody tr:hover{background-color:var(--background-light)}.action-badge{padding:4px 10px;border-radius:12px;font-size:11px;font-weight:600;text-transform:uppercase;letter-spacing:.5px}.action-create{background-color:#e8f5e9;color:var(--success-color)}.action-update{background-color:#fff4e6;color:var(--warning-color)}.action-delete{background-color:#ffebee;color:var(--error-color)}.preview-note{text-align:center;padding:12px;color:var(--text-secondary);font-size:12px;background-color:var(--background-light)}.modal-footer{display:flex;justify-content:flex-end;gap:12px;padding:20px 24px;border-top:1px solid var(--border-color);background:var(--background-light)}.progress-panel{background:var(--card-bg);padding:24px;margin-bottom:16px;border-radius:12px;box-shadow:var(--shadow-md)}.progress-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:16px}.progress-stats{display:grid;grid-template-columns:repeat(auto-fit,minmax(120px,1fr));gap:16px;margin-bottom:24px}.stat-card{padding:16px;border:2px solid var(--border-color);border-radius:8px;text-align:center;background:#fff}.stat-value{font-size:28px;font-weight:700;margin-bottom:4px}.stat-label{font-size:11px;color:var(--text-secondary);text-transform:uppercase;letter-spacing:.5px}.progress-bar{width:100%;height:10px;background-color:#e0e0e0;border-radius:10px;overflow:hidden;margin-bottom:24px}.progress-fill{height:100%;background:linear-gradient(90deg,var(--primary-color) 0%,#005a9e 100%);transition:width .3s ease;border-radius:10px}.record-list{max-height:400px;overflow-y:auto;border:2px solid var(--border-color);border-radius:8px;background:#fff}.record-item{display:flex;justify-content:space-between;align-items:center;padding:12px;border-bottom:1px solid #f0f0f0}.record-item:last-child{border-bottom:none}.record-status{display:flex;align-items:center;gap:8px}.status-badge{padding:4px 10px;border-radius:10px;font-size:11px;font-weight:600;text-transform:uppercase}.status-success{background-color:#e8f5e9;color:var(--success-color)}.status-error{background-color:#ffebee;color:var(--error-color)}.status-processing{background-color:#fff4e6;color:var(--warning-color)}.status-pending{background-color:#f5f5f5;color:var(--text-secondary)}.mapping-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:24px;margin-top:16px}@media(max-width:968px){.mapping-grid{grid-template-columns:1fr}}.mapping-section h4{margin:0 0 12px;font-size:14px;font-weight:600}.mapping-list{border:2px solid var(--border-color);border-radius:8px;max-height:300px;overflow-y:auto;background:#fff}.mapping-item{padding:10px 12px;border-bottom:1px solid #f0f0f0;font-size:13px}.mapping-item:last-child{border-bottom:none}.confidence-high{color:var(--success-color);font-weight:600}.confidence-medium{color:var(--warning-color);font-weight:600}.confidence-low{color:var(--error-color);font-weight:600}.lookup-item-container{border:2px solid var(--border-color);border-radius:8px;margin-bottom:12px;overflow:hidden;transition:all .2s ease}.lookup-item-container:hover{border-color:var(--primary-color);box-shadow:var(--shadow-sm)}.manual-mapping-panel{padding:16px;background:var(--background-light);border-top:1px solid var(--border-color);animation:slideDown .3s ease}@keyframes slideDown{0%{opacity:0;max-height:0}to{opacity:1;max-height:500px}}.manual-mapping-header{display:grid;grid-template-columns:1fr 1fr auto;gap:12px;padding:8px 12px;background:var(--card-bg);border-radius:6px;font-weight:600;font-size:12px;color:var(--text-secondary);text-transform:uppercase;margin-bottom:8px}.manual-mapping-row{display:grid;grid-template-columns:1fr 1fr auto;gap:12px;padding:10px 12px;background:var(--card-bg);border-radius:6px;align-items:center;margin-bottom:6px;transition:background .2s}.manual-mapping-row:hover{background:var(--primary-light)}.manual-mapping-row span{font-size:12px;font-family:Courier New,monospace;color:var(--text-primary);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.btn-delete{background:var(--error-color);color:#fff;border:none;border-radius:4px;padding:4px 12px;cursor:pointer;font-size:14px;font-weight:700;transition:all .2s;width:32px;height:32px;display:flex;align-items:center;justify-content:center}.btn-delete:hover{background:#a21c21;transform:scale(1.05)}.manual-mapping-add{display:grid;grid-template-columns:1fr 1fr auto;gap:12px;margin-top:12px;padding:12px;background:var(--card-bg);border-radius:6px;border:2px dashed var(--border-color)}.manual-mapping-hint{font-size:11px;color:var(--text-secondary);margin-top:8px;margin-bottom:0}.btn-add{background:var(--primary-color);color:#fff;border:none;border-radius:6px;padding:8px 20px;cursor:pointer;font-size:13px;font-weight:600;transition:all .2s;white-space:nowrap}.btn-add:hover:not(:disabled){background:var(--primary-hover);transform:translateY(-1px);box-shadow:var(--shadow-sm)}.btn-add:disabled{background:#ccc;cursor:not-allowed;opacity:.6}.btn-toggle{background:var(--primary-color);color:#fff;border:none;border-radius:6px;padding:6px 12px;cursor:pointer;font-size:16px;font-weight:700;transition:all .2s;min-width:36px;height:36px;display:flex;align-items:center;justify-content:center}.btn-toggle:hover{background:var(--primary-hover);transform:scale(1.05)}@media(max-width:768px){.content-fluid{padding:12px}.header-card{padding:16px}.app-title{font-size:22px}.connection-flow{width:100%}.step-content{padding:16px}.manual-mapping-header,.manual-mapping-row,.manual-mapping-add{grid-template-columns:1fr;gap:8px}.btn-delete{width:100%}}.btn-reset{background-color:#f3f2f1!important;color:var(--text-primary)!important;border:1px solid var(--border-color)!important}.btn-reset:hover:not(:disabled){background-color:#e1dfdd!important;color:var(--text-primary)!important}.progress-placeholder{text-align:center;padding:40px 20px;color:var(--text-secondary)}.progress-placeholder h3{font-size:18px;font-weight:600;margin:0 0 8px;color:var(--text-primary)}.progress-placeholder p{font-size:14px;margin:0;color:var(--text-secondary)}
|
package/dist/index.html
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8" />
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
|
+
<title>Data Migrator</title>
|
|
7
|
+
<script type="module" crossorigin src="/index.js"></script>
|
|
8
|
+
<link rel="stylesheet" crossorigin href="/index.css">
|
|
9
|
+
</head>
|
|
10
|
+
<body>
|
|
11
|
+
<div id="root"></div>
|
|
12
|
+
</body>
|
|
13
|
+
</html>
|