mirror of
https://github.com/wekan/wekan.git
synced 2026-01-23 17:56:09 +01:00
Fix DB migration from 8.19 to 8.21 stuck forever.
Thanks to MaccabeeY and xet7 ! Fixes #6078
This commit is contained in:
parent
e177bf54e2
commit
a31a615da6
9 changed files with 869 additions and 71 deletions
|
|
@ -862,3 +862,43 @@
|
|||
max-width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
/* Progress bar styles for #cron-setting section */
|
||||
#cron-setting .progress-section {
|
||||
margin-top: 15px;
|
||||
}
|
||||
|
||||
#cron-setting .step-counter {
|
||||
margin-bottom: 8px;
|
||||
font-weight: 600;
|
||||
color: #333;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
#cron-setting .progress {
|
||||
height: 30px;
|
||||
background-color: #e9ecef;
|
||||
border-radius: 4px;
|
||||
overflow: visible;
|
||||
margin-bottom: 5px;
|
||||
max-width: calc(100% - 40px);
|
||||
}
|
||||
|
||||
#cron-setting .progress-bar {
|
||||
height: 30px;
|
||||
line-height: 30px;
|
||||
background-color: #28a745;
|
||||
color: white;
|
||||
font-weight: 600;
|
||||
font-size: 14px;
|
||||
text-align: center;
|
||||
transition: width 0.3s ease;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
#cron-setting .progress-text {
|
||||
font-size: 13px;
|
||||
color: #666;
|
||||
margin-top: 5px;
|
||||
max-width: calc(100% - 40px);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,21 +3,52 @@ template(name="cronSettings")
|
|||
li
|
||||
h3 {{_ 'cron-migrations'}}
|
||||
.form-group
|
||||
label {{_ 'migration-status'}}
|
||||
.status-indicator
|
||||
span.status-label {{_ 'status'}}:
|
||||
span.status-value {{migrationStatus}}
|
||||
.progress-section
|
||||
.progress
|
||||
.progress-bar(role="progressbar" style="width: {{migrationProgress}}%" aria-valuenow="{{migrationProgress}}" aria-valuemin="0" aria-valuemax="100")
|
||||
| {{migrationProgress}}%
|
||||
.progress-text
|
||||
| {{migrationProgress}}% {{_ 'complete'}}
|
||||
label {{_ 'select-migration'}}
|
||||
select.js-migration-select.wekan-form-control
|
||||
option(value="0") 0 - {{_ 'all-migrations'}}
|
||||
each migrationStepsWithIndex
|
||||
option(value="{{index}}") {{index}} - {{name}}
|
||||
|
||||
.form-group
|
||||
button.js-start-all-migrations.btn.btn-primary {{_ 'start-all-migrations'}}
|
||||
button.js-pause-all-migrations.btn.btn-warning {{_ 'pause-all-migrations'}}
|
||||
button.js-stop-all-migrations.btn.btn-danger {{_ 'stop-all-migrations'}}
|
||||
label {{_ 'migration-status'}}
|
||||
.status-indicator
|
||||
span.status-value {{migrationStatus}}
|
||||
if isMigrating
|
||||
.progress-section
|
||||
.step-counter
|
||||
| Step {{migrationCurrentStepNum}}/{{migrationTotalSteps}}
|
||||
.progress
|
||||
.progress-bar(role="progressbar" style="width: {{migrationProgress}}%" aria-valuenow="{{migrationProgress}}" aria-valuemin="0" aria-valuemax="100")
|
||||
| {{migrationProgress}}%
|
||||
.progress-text
|
||||
| {{migrationProgress}}% {{_ 'complete'}}
|
||||
|
||||
.form-group
|
||||
button.js-start-migration.btn.btn-primary(disabled="{{#if isMigrating}}disabled{{/if}}") {{_ 'start'}}
|
||||
button.js-pause-migration.btn.btn-warning(disabled="{{#unless isMigrating}}disabled{{/unless}}") {{_ 'pause'}}
|
||||
button.js-stop-migration.btn.btn-danger(disabled="{{#unless isMigrating}}disabled{{/unless}}") {{_ 'stop'}}
|
||||
|
||||
.form-group.migration-errors-section
|
||||
h4 {{_ 'cron-migration-errors'}}
|
||||
if hasErrors
|
||||
.error-actions
|
||||
button.js-clear-all-errors.btn.btn-sm.btn-warning {{_ 'cron-clear-errors'}}
|
||||
.errors-list
|
||||
each migrationErrors
|
||||
.error-item(class="error-{{severity}}")
|
||||
.error-header
|
||||
span.error-severity(class="severity-{{severity}}") {{severity}}
|
||||
span.error-time {{formatDateTime createdAt}}
|
||||
if stepId
|
||||
span.error-step {{stepId}}
|
||||
.error-message {{errorMessage}}
|
||||
if context
|
||||
.error-context
|
||||
each contextValue context
|
||||
span.context-item {{this}}
|
||||
else
|
||||
.no-errors
|
||||
| {{_ 'cron-no-errors'}}
|
||||
|
||||
li
|
||||
h3 {{_ 'board-operations'}}
|
||||
|
|
|
|||
|
|
@ -170,25 +170,22 @@ template(name="setting")
|
|||
label {{_ 'migration-status'}}
|
||||
.status-indicator
|
||||
span.status-label {{_ 'status'}}:
|
||||
span.status-value {{#if isMigrating}}{{migrationStatus}}{{else}}{{_ 'idle'}}{{/if}}
|
||||
.current-step(class="{{#unless migrationCurrentStep}}hide{{/unless}}")
|
||||
span.step-label {{_ 'current-step'}}:
|
||||
span.step-value {{migrationCurrentStep}}
|
||||
.progress-section
|
||||
.progress
|
||||
.progress-bar(role="progressbar" style="width: {{migrationProgress}}%" aria-valuenow="{{migrationProgress}}" aria-valuemin="0" aria-valuemax="100")
|
||||
| {{migrationProgress}}%
|
||||
.progress-text
|
||||
| {{migrationProgress}}% {{_ 'complete'}}
|
||||
span.status-value
|
||||
if isMigrating
|
||||
i.fa.fa-spinner.fa-spin(style="margin-right: 8px;")
|
||||
| {{#if isMigrating}}{{migrationStatus}}{{else}}{{_ 'idle'}}{{/if}}
|
||||
if isMigrating
|
||||
.progress-section
|
||||
.progress
|
||||
.progress-bar(role="progressbar" style="width: {{migrationProgress}}%" aria-valuenow="{{migrationProgress}}" aria-valuemin="0" aria-valuemax="100")
|
||||
| {{migrationProgress}}%
|
||||
.progress-text
|
||||
| {{migrationProgress}}% {{_ 'complete'}}
|
||||
|
||||
.form-group
|
||||
button.js-start-all-migrations.btn.btn-primary {{#if isMigrating}}disabled{{/if}} {{_ 'start-all-migrations'}}
|
||||
button.js-pause-all-migrations.btn.btn-warning {{#unless isMigrating}}disabled{{/unless}} {{_ 'pause-all-migrations'}}
|
||||
button.js-stop-all-migrations.btn.btn-danger {{#unless isMigrating}}disabled{{/unless}} {{_ 'stop-all-migrations'}}
|
||||
|
||||
li
|
||||
h3 {{_ 'migration-steps'}}
|
||||
p Migration steps section temporarily removed
|
||||
button.js-start-all-migrations.btn.btn-primary(disabled="{{#if isMigrating}}disabled{{/if}}") {{_ 'start-all-migrations'}}
|
||||
button.js-pause-all-migrations.btn.btn-warning(disabled="{{#unless isMigrating}}disabled{{/unless}}") {{_ 'pause-all-migrations'}}
|
||||
button.js-stop-all-migrations.btn.btn-danger(disabled="{{#unless isMigrating}}disabled{{/unless}}") {{_ 'stop-all-migrations'}}
|
||||
|
||||
li
|
||||
h3 {{_ 'board-operations'}}
|
||||
|
|
|
|||
|
|
@ -8,7 +8,9 @@ import {
|
|||
cronMigrationCurrentStep,
|
||||
cronMigrationSteps,
|
||||
cronIsMigrating,
|
||||
cronJobs
|
||||
cronJobs,
|
||||
cronMigrationCurrentStepNum,
|
||||
cronMigrationTotalSteps
|
||||
} from '/imports/cronMigrationClient';
|
||||
|
||||
|
||||
|
|
@ -27,6 +29,7 @@ BlazeComponent.extendComponent({
|
|||
this.webhookSetting = new ReactiveVar(false);
|
||||
this.attachmentSettings = new ReactiveVar(false);
|
||||
this.cronSettings = new ReactiveVar(false);
|
||||
this.migrationErrorsList = new ReactiveVar([]);
|
||||
|
||||
Meteor.subscribe('setting');
|
||||
Meteor.subscribe('mailServer');
|
||||
|
|
@ -36,6 +39,23 @@ BlazeComponent.extendComponent({
|
|||
Meteor.subscribe('accessibilitySettings');
|
||||
Meteor.subscribe('globalwebhooks');
|
||||
Meteor.subscribe('lockoutSettings');
|
||||
|
||||
// Poll for migration errors
|
||||
this.errorPollInterval = Meteor.setInterval(() => {
|
||||
if (this.cronSettings.get()) {
|
||||
Meteor.call('cron.getAllMigrationErrors', 50, (error, result) => {
|
||||
if (!error && result) {
|
||||
this.migrationErrorsList.set(result);
|
||||
}
|
||||
});
|
||||
}
|
||||
}, 5000); // Poll every 5 seconds
|
||||
},
|
||||
|
||||
onDestroyed() {
|
||||
if (this.errorPollInterval) {
|
||||
Meteor.clearInterval(this.errorPollInterval);
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
|
|
@ -142,10 +162,40 @@ BlazeComponent.extendComponent({
|
|||
return cronMigrationSteps.get() || [];
|
||||
},
|
||||
|
||||
migrationStepsWithIndex() {
|
||||
const steps = cronMigrationSteps.get() || [];
|
||||
return steps.map((step, idx) => ({
|
||||
...step,
|
||||
index: idx + 1
|
||||
}));
|
||||
},
|
||||
|
||||
cronJobs() {
|
||||
return cronJobs.get() || [];
|
||||
},
|
||||
|
||||
migrationCurrentStepNum() {
|
||||
return cronMigrationCurrentStepNum.get() || 0;
|
||||
},
|
||||
|
||||
migrationTotalSteps() {
|
||||
return cronMigrationTotalSteps.get() || 0;
|
||||
},
|
||||
|
||||
migrationErrors() {
|
||||
return this.migrationErrorsList ? this.migrationErrorsList.get() : [];
|
||||
},
|
||||
|
||||
hasErrors() {
|
||||
const errors = this.migrationErrors();
|
||||
return errors && errors.length > 0;
|
||||
},
|
||||
|
||||
formatDateTime(date) {
|
||||
if (!date) return '';
|
||||
return moment(date).format('YYYY-MM-DD HH:mm:ss');
|
||||
},
|
||||
|
||||
setLoading(w) {
|
||||
this.loading.set(w);
|
||||
},
|
||||
|
|
@ -187,20 +237,35 @@ BlazeComponent.extendComponent({
|
|||
},
|
||||
|
||||
// Event handlers for cron settings
|
||||
'click button.js-start-all-migrations'(event) {
|
||||
'click button.js-start-migration'(event) {
|
||||
event.preventDefault();
|
||||
this.setLoading(true);
|
||||
Meteor.call('cron.startAllMigrations', (error, result) => {
|
||||
this.setLoading(false);
|
||||
if (error) {
|
||||
alert(TAPi18n.__('migration-start-failed') + ': ' + error.reason);
|
||||
} else {
|
||||
alert(TAPi18n.__('migration-started'));
|
||||
}
|
||||
});
|
||||
const selectedIndex = parseInt($('.js-migration-select').val() || '0', 10);
|
||||
|
||||
if (selectedIndex === 0) {
|
||||
// Run all migrations
|
||||
Meteor.call('cron.startAllMigrations', (error, result) => {
|
||||
this.setLoading(false);
|
||||
if (error) {
|
||||
alert(TAPi18n.__('migration-start-failed') + ': ' + error.reason);
|
||||
} else {
|
||||
alert(TAPi18n.__('migration-started'));
|
||||
}
|
||||
});
|
||||
} else {
|
||||
// Run specific migration
|
||||
Meteor.call('cron.startSpecificMigration', selectedIndex - 1, (error, result) => {
|
||||
this.setLoading(false);
|
||||
if (error) {
|
||||
alert(TAPi18n.__('migration-start-failed') + ': ' + error.reason);
|
||||
} else {
|
||||
alert(TAPi18n.__('migration-started'));
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
'click button.js-pause-all-migrations'(event) {
|
||||
'click button.js-pause-migration'(event) {
|
||||
event.preventDefault();
|
||||
this.setLoading(true);
|
||||
Meteor.call('cron.pauseAllMigrations', (error, result) => {
|
||||
|
|
@ -213,7 +278,7 @@ BlazeComponent.extendComponent({
|
|||
});
|
||||
},
|
||||
|
||||
'click button.js-stop-all-migrations'(event) {
|
||||
'click button.js-stop-migration'(event) {
|
||||
event.preventDefault();
|
||||
if (confirm(TAPi18n.__('migration-stop-confirm'))) {
|
||||
this.setLoading(true);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue