078b2e6051
- Fix: replace QueryComposer::toDb() (protected) with camelCaseToUnderscore
for table name resolution — was causing 500 on real import
- Feat: optional database snapshot (mysqldump) before import with UI checkbox
(checked by default). Snapshot saved to data/backups/snapshot-{timestamp}/
- Feat: skip entity types whose module is not installed (import resilience)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
196 lines
8.9 KiB
Smarty
196 lines
8.9 KiB
Smarty
<div class="page-header">
|
|
<h3>
|
|
<a href="#Admin">{{translate 'Administration'}}</a>
|
|
<span class="breadcrumb-separator"><span class="chevron-right"></span></span>
|
|
{{translate 'Data Migration' scope='DataMigration'}}
|
|
</h3>
|
|
</div>
|
|
|
|
<div class="row">
|
|
{{! ========== LEFT COLUMN: Status + Export ========== }}
|
|
<div class="col-md-6">
|
|
|
|
{{! === Database Status === }}
|
|
<div class="panel panel-default">
|
|
<div class="panel-heading">
|
|
<div class="pull-right">
|
|
<button class="btn btn-default btn-xs" data-action="refreshStatus" title="{{translate 'Refresh'}}">
|
|
<i class="fas fa-sync-alt"></i>
|
|
</button>
|
|
</div>
|
|
<h4 class="panel-title">
|
|
<i class="fas fa-database"></i>
|
|
{{translate 'Database Status' scope='DataMigration'}}
|
|
</h4>
|
|
</div>
|
|
<div class="panel-body">
|
|
<div class="status-spinner" style="text-align: center; padding: 20px;">
|
|
<i class="fas fa-spinner fa-spin fa-2x text-muted"></i>
|
|
</div>
|
|
<div class="status-content" style="display: none;"></div>
|
|
</div>
|
|
</div>
|
|
|
|
{{! === Export === }}
|
|
<div class="panel panel-primary">
|
|
<div class="panel-heading">
|
|
<h4 class="panel-title">
|
|
<i class="fas fa-upload"></i>
|
|
{{translate 'Export / Backup' scope='DataMigration'}}
|
|
</h4>
|
|
</div>
|
|
<div class="panel-body">
|
|
<p class="text-muted" style="margin-bottom: 15px;">
|
|
{{translate 'exportDescription' category='messages' scope='DataMigration'}}
|
|
</p>
|
|
|
|
{{! Status filter }}
|
|
<div class="form-group">
|
|
<label class="control-label">
|
|
{{translate 'Filter by Case Status' scope='DataMigration'}}
|
|
<span class="text-muted" style="font-weight: normal;"> ({{translate 'optional' scope='DataMigration'}})</span>
|
|
</label>
|
|
<div class="export-status-checkboxes" style="columns: 2;">
|
|
{{#each caseStatuses}}
|
|
<div class="checkbox" style="margin-top: 2px; margin-bottom: 2px;">
|
|
<label>
|
|
<input type="checkbox" value="{{this}}"> {{this}}
|
|
</label>
|
|
</div>
|
|
{{/each}}
|
|
</div>
|
|
</div>
|
|
|
|
{{! No files option }}
|
|
<div class="form-group">
|
|
<div class="checkbox">
|
|
<label>
|
|
<input type="checkbox" name="noFiles">
|
|
{{translate 'Skip attachment files' scope='DataMigration'}}
|
|
<span class="text-muted"> — {{translate 'noFilesHint' category='messages' scope='DataMigration'}}</span>
|
|
</label>
|
|
</div>
|
|
</div>
|
|
|
|
<div>
|
|
<button class="btn btn-primary" data-action="export">
|
|
<i class="fas fa-download"></i>
|
|
{{translate 'Start Export' scope='DataMigration'}}
|
|
</button>
|
|
</div>
|
|
|
|
<div class="export-progress" style="display: none; margin-top: 15px;">
|
|
<div class="progress">
|
|
<div class="progress-bar progress-bar-striped active" style="width: 100%;">
|
|
{{translate 'Exporting...' scope='DataMigration'}}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="export-log-container" style="display: none;"></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{{! ========== RIGHT COLUMN: Backups + Import ========== }}
|
|
<div class="col-md-6">
|
|
|
|
{{! === Backup List === }}
|
|
<div class="panel panel-default">
|
|
<div class="panel-heading">
|
|
<div class="pull-right">
|
|
<button class="btn btn-default btn-xs" data-action="refreshBackups" title="{{translate 'Refresh'}}">
|
|
<i class="fas fa-sync-alt"></i>
|
|
</button>
|
|
</div>
|
|
<h4 class="panel-title">
|
|
<i class="fas fa-archive"></i>
|
|
{{translate 'Available Backups' scope='DataMigration'}}
|
|
</h4>
|
|
</div>
|
|
<div class="panel-body" style="padding: 0;">
|
|
<div class="backups-spinner" style="text-align: center; padding: 20px;">
|
|
<i class="fas fa-spinner fa-spin fa-2x text-muted"></i>
|
|
</div>
|
|
<div class="backups-list list-group" style="margin-bottom: 0;"></div>
|
|
</div>
|
|
</div>
|
|
|
|
{{! === Import === }}
|
|
<div class="import-section" style="display: none;">
|
|
<div class="panel panel-warning">
|
|
<div class="panel-heading">
|
|
<h4 class="panel-title">
|
|
<i class="fas fa-download"></i>
|
|
{{translate 'Import / Restore' scope='DataMigration'}}
|
|
</h4>
|
|
</div>
|
|
<div class="panel-body">
|
|
<div class="alert alert-info" style="margin-bottom: 15px;">
|
|
<i class="fas fa-info-circle"></i>
|
|
{{translate 'Selected backup' scope='DataMigration'}}: <strong class="selected-backup-name"></strong>
|
|
</div>
|
|
|
|
{{! Import options }}
|
|
<div class="form-group">
|
|
<label class="control-label">{{translate 'Import Options' scope='DataMigration'}}</label>
|
|
|
|
<div class="checkbox">
|
|
<label>
|
|
<input type="checkbox" name="preserveIds" checked>
|
|
{{translate 'Preserve original IDs' scope='DataMigration'}}
|
|
<span class="text-muted"> — {{translate 'preserveIdsHint' category='messages' scope='DataMigration'}}</span>
|
|
</label>
|
|
</div>
|
|
|
|
<div class="checkbox">
|
|
<label>
|
|
<input type="checkbox" name="skipDuplicates" checked>
|
|
{{translate 'Skip duplicates' scope='DataMigration'}}
|
|
<span class="text-muted"> — {{translate 'skipDuplicatesHint' category='messages' scope='DataMigration'}}</span>
|
|
</label>
|
|
</div>
|
|
|
|
<div class="checkbox">
|
|
<label>
|
|
<input type="checkbox" name="importNoFiles">
|
|
{{translate 'Skip attachment files' scope='DataMigration'}}
|
|
<span class="text-muted"> — {{translate 'importNoFilesHint' category='messages' scope='DataMigration'}}</span>
|
|
</label>
|
|
</div>
|
|
|
|
<div class="checkbox">
|
|
<label>
|
|
<input type="checkbox" name="createSnapshot" checked>
|
|
{{translate 'Create snapshot before import' scope='DataMigration'}}
|
|
<span class="text-muted"> — {{translate 'snapshotHint' category='messages' scope='DataMigration'}}</span>
|
|
</label>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="btn-group">
|
|
<button class="btn btn-warning" data-action="dryRunImport">
|
|
<i class="fas fa-vial"></i>
|
|
{{translate 'Dry Run' scope='DataMigration'}}
|
|
</button>
|
|
<button class="btn btn-danger" data-action="import">
|
|
<i class="fas fa-play"></i>
|
|
{{translate 'Import Now' scope='DataMigration'}}
|
|
</button>
|
|
</div>
|
|
|
|
<div class="import-progress" style="display: none; margin-top: 15px;">
|
|
<div class="progress">
|
|
<div class="progress-bar progress-bar-warning progress-bar-striped active" style="width: 100%;">
|
|
{{translate 'Importing...' scope='DataMigration'}}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="import-log-container" style="display: none;"></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|