mirror of
https://github.com/wekan/wekan.git
synced 2026-01-13 21:18:50 +01:00
Security Fix 1: There was not enough permission checks. Moved migrations to Admin Panel/Settings/Cron.
Thanks to [Joshua Rogers](https://joshua.hu) of [Aisle Research](https://aisle.com) and xet7.
This commit is contained in:
parent
d6834d0287
commit
cbb1cd78de
18 changed files with 397 additions and 1805 deletions
301
client/components/settings/migrationProgress.css
Normal file
301
client/components/settings/migrationProgress.css
Normal file
|
|
@ -0,0 +1,301 @@
|
|||
/* Migration Progress Styles */
|
||||
.migration-progress-overlay {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background: rgba(0, 0, 0, 0.7);
|
||||
z-index: 9999;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
backdrop-filter: blur(2px);
|
||||
}
|
||||
|
||||
.migration-progress-modal {
|
||||
background: white;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.3);
|
||||
max-width: 500px;
|
||||
width: 90%;
|
||||
max-height: 80vh;
|
||||
overflow: hidden;
|
||||
animation: migrationModalSlideIn 0.3s ease-out;
|
||||
}
|
||||
|
||||
@keyframes migrationModalSlideIn {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(-20px) scale(0.95);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0) scale(1);
|
||||
}
|
||||
}
|
||||
|
||||
.migration-progress-header {
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
color: white;
|
||||
padding: 20px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.migration-progress-title {
|
||||
margin: 0;
|
||||
font-size: 18px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.migration-progress-close {
|
||||
cursor: pointer;
|
||||
font-size: 16px;
|
||||
opacity: 0.8;
|
||||
transition: opacity 0.2s ease;
|
||||
}
|
||||
|
||||
.migration-progress-close:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.migration-progress-content {
|
||||
padding: 30px;
|
||||
}
|
||||
|
||||
.migration-progress-overall {
|
||||
margin-bottom: 25px;
|
||||
}
|
||||
|
||||
.migration-progress-overall-label {
|
||||
font-weight: 600;
|
||||
color: #333;
|
||||
margin-bottom: 8px;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.migration-progress-overall-bar {
|
||||
background: #e9ecef;
|
||||
border-radius: 10px;
|
||||
height: 12px;
|
||||
overflow: hidden;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.migration-progress-overall-fill {
|
||||
background: linear-gradient(90deg, #28a745, #20c997);
|
||||
height: 100%;
|
||||
border-radius: 10px;
|
||||
transition: width 0.3s ease;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.migration-progress-overall-fill::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background: linear-gradient(90deg, transparent, rgba(255,255,255,0.3), transparent);
|
||||
animation: migrationProgressShimmer 2s infinite;
|
||||
}
|
||||
|
||||
@keyframes migrationProgressShimmer {
|
||||
0% { transform: translateX(-100%); }
|
||||
100% { transform: translateX(100%); }
|
||||
}
|
||||
|
||||
.migration-progress-overall-percentage {
|
||||
text-align: right;
|
||||
font-size: 12px;
|
||||
color: #666;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.migration-progress-current-step {
|
||||
margin-bottom: 25px;
|
||||
}
|
||||
|
||||
.migration-progress-step-label {
|
||||
font-weight: 600;
|
||||
color: #333;
|
||||
margin-bottom: 8px;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.migration-progress-step-bar {
|
||||
background: #e9ecef;
|
||||
border-radius: 8px;
|
||||
height: 8px;
|
||||
overflow: hidden;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.migration-progress-step-fill {
|
||||
background: linear-gradient(90deg, #007bff, #0056b3);
|
||||
height: 100%;
|
||||
border-radius: 8px;
|
||||
transition: width 0.3s ease;
|
||||
}
|
||||
|
||||
.migration-progress-step-percentage {
|
||||
text-align: right;
|
||||
font-size: 12px;
|
||||
color: #666;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.migration-progress-status {
|
||||
margin-bottom: 20px;
|
||||
padding: 15px;
|
||||
background: #f8f9fa;
|
||||
border-radius: 6px;
|
||||
border-left: 4px solid #007bff;
|
||||
}
|
||||
|
||||
.migration-progress-status-label {
|
||||
font-weight: 600;
|
||||
color: #333;
|
||||
margin-bottom: 5px;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.migration-progress-status-text {
|
||||
color: #555;
|
||||
font-size: 14px;
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
.migration-progress-details {
|
||||
margin-bottom: 20px;
|
||||
padding: 12px;
|
||||
background: #e3f2fd;
|
||||
border-radius: 6px;
|
||||
border-left: 4px solid #2196f3;
|
||||
}
|
||||
|
||||
.migration-progress-details-label {
|
||||
font-weight: 600;
|
||||
color: #1976d2;
|
||||
margin-bottom: 5px;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.migration-progress-details-text {
|
||||
color: #1565c0;
|
||||
font-size: 13px;
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
.migration-progress-footer {
|
||||
padding: 20px 30px;
|
||||
background: #f8f9fa;
|
||||
border-top: 1px solid #e9ecef;
|
||||
}
|
||||
|
||||
.migration-progress-note {
|
||||
text-align: center;
|
||||
color: #666;
|
||||
font-size: 13px;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
/* Responsive design */
|
||||
@media (max-width: 600px) {
|
||||
.migration-progress-modal {
|
||||
width: 95%;
|
||||
margin: 20px;
|
||||
}
|
||||
|
||||
.migration-progress-content {
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.migration-progress-header {
|
||||
padding: 15px;
|
||||
}
|
||||
|
||||
.migration-progress-title {
|
||||
font-size: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
/* Dark mode support */
|
||||
@media (prefers-color-scheme: dark) {
|
||||
.migration-progress-modal {
|
||||
background: #2d3748;
|
||||
color: #e2e8f0;
|
||||
}
|
||||
|
||||
.migration-progress-overall-label,
|
||||
.migration-progress-step-label,
|
||||
.migration-progress-status-label {
|
||||
color: #e2e8f0;
|
||||
}
|
||||
|
||||
.migration-progress-status {
|
||||
background: #4a5568;
|
||||
border-left-color: #63b3ed;
|
||||
}
|
||||
|
||||
.migration-progress-status-text {
|
||||
color: #cbd5e0;
|
||||
}
|
||||
|
||||
.migration-progress-details {
|
||||
background: #2b6cb0;
|
||||
border-left-color: #4299e1;
|
||||
}
|
||||
|
||||
.migration-progress-details-label {
|
||||
color: #bee3f8;
|
||||
}
|
||||
|
||||
.migration-progress-details-text {
|
||||
color: #90cdf4;
|
||||
}
|
||||
|
||||
.migration-progress-footer {
|
||||
background: #4a5568;
|
||||
border-top-color: #718096;
|
||||
}
|
||||
|
||||
.migration-progress-note {
|
||||
color: #a0aec0;
|
||||
}
|
||||
}
|
||||
/* Attachment migration styles */
|
||||
.attachment-item.migrating {
|
||||
position: relative;
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
.attachment-migration-overlay {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background: rgba(255, 255, 255, 0.9);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
z-index: 10;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.migration-spinner {
|
||||
font-size: 24px;
|
||||
color: #007cba;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.migration-text {
|
||||
font-size: 12px;
|
||||
color: #666;
|
||||
text-align: center;
|
||||
}
|
||||
43
client/components/settings/migrationProgress.jade
Normal file
43
client/components/settings/migrationProgress.jade
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
template(name="migrationProgress")
|
||||
if isMigrating
|
||||
.migration-progress-overlay
|
||||
.migration-progress-modal
|
||||
.migration-progress-header
|
||||
h3.migration-progress-title
|
||||
| 🔄 {{_ 'migration-progress-title'}}
|
||||
.migration-progress-close.js-close-migration-progress
|
||||
| ❌
|
||||
|
||||
.migration-progress-content
|
||||
.migration-progress-overall
|
||||
.migration-progress-overall-label
|
||||
| {{_ 'migration-progress-overall'}}: {{currentStep}} {{_ 'of'}} {{totalSteps}} {{_ 'steps'}}
|
||||
.migration-progress-overall-bar
|
||||
.migration-progress-overall-fill(style="{{progressBarStyle}}")
|
||||
.migration-progress-overall-percentage
|
||||
| {{overallProgress}}%
|
||||
|
||||
.migration-progress-current-step
|
||||
.migration-progress-step-label
|
||||
| {{_ 'migration-progress-current-step'}}: {{stepNameFormatted}}
|
||||
.migration-progress-step-bar
|
||||
.migration-progress-step-fill(style="{{stepProgressBarStyle}}")
|
||||
.migration-progress-step-percentage
|
||||
| {{stepProgress}}%
|
||||
|
||||
.migration-progress-status
|
||||
.migration-progress-status-label
|
||||
| {{_ 'migration-progress-status'}}:
|
||||
.migration-progress-status-text
|
||||
| {{stepStatus}}
|
||||
|
||||
if stepDetailsFormatted
|
||||
.migration-progress-details
|
||||
.migration-progress-details-label
|
||||
| {{_ 'migration-progress-details'}}:
|
||||
.migration-progress-details-text
|
||||
| {{stepDetailsFormatted}}
|
||||
|
||||
.migration-progress-footer
|
||||
.migration-progress-note
|
||||
| {{_ 'migration-progress-note'}}
|
||||
212
client/components/settings/migrationProgress.js
Normal file
212
client/components/settings/migrationProgress.js
Normal file
|
|
@ -0,0 +1,212 @@
|
|||
/**
|
||||
* Migration Progress Component
|
||||
* Displays detailed progress for comprehensive board migration
|
||||
*/
|
||||
|
||||
import { ReactiveVar } from 'meteor/reactive-var';
|
||||
import { ReactiveCache } from '/imports/reactiveCache';
|
||||
|
||||
// Reactive variables for migration progress
|
||||
export const migrationProgress = new ReactiveVar(0);
|
||||
export const migrationStatus = new ReactiveVar('');
|
||||
export const migrationStepName = new ReactiveVar('');
|
||||
export const migrationStepProgress = new ReactiveVar(0);
|
||||
export const migrationStepStatus = new ReactiveVar('');
|
||||
export const migrationStepDetails = new ReactiveVar(null);
|
||||
export const migrationCurrentStep = new ReactiveVar(0);
|
||||
export const migrationTotalSteps = new ReactiveVar(0);
|
||||
export const isMigrating = new ReactiveVar(false);
|
||||
|
||||
class MigrationProgressManager {
|
||||
constructor() {
|
||||
this.progressHistory = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Update migration progress
|
||||
*/
|
||||
updateProgress(progressData) {
|
||||
const {
|
||||
overallProgress,
|
||||
currentStep,
|
||||
totalSteps,
|
||||
stepName,
|
||||
stepProgress,
|
||||
stepStatus,
|
||||
stepDetails,
|
||||
boardId
|
||||
} = progressData;
|
||||
|
||||
// Update reactive variables
|
||||
migrationProgress.set(overallProgress);
|
||||
migrationCurrentStep.set(currentStep);
|
||||
migrationTotalSteps.set(totalSteps);
|
||||
migrationStepName.set(stepName);
|
||||
migrationStepProgress.set(stepProgress);
|
||||
migrationStepStatus.set(stepStatus);
|
||||
migrationStepDetails.set(stepDetails);
|
||||
|
||||
// Store in history
|
||||
this.progressHistory.push({
|
||||
timestamp: new Date(),
|
||||
...progressData
|
||||
});
|
||||
|
||||
// Update overall status
|
||||
migrationStatus.set(`${stepName}: ${stepStatus}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Start migration
|
||||
*/
|
||||
startMigration() {
|
||||
isMigrating.set(true);
|
||||
migrationProgress.set(0);
|
||||
migrationStatus.set('Starting migration...');
|
||||
migrationStepName.set('');
|
||||
migrationStepProgress.set(0);
|
||||
migrationStepStatus.set('');
|
||||
migrationStepDetails.set(null);
|
||||
migrationCurrentStep.set(0);
|
||||
migrationTotalSteps.set(0);
|
||||
this.progressHistory = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Complete migration
|
||||
*/
|
||||
completeMigration() {
|
||||
isMigrating.set(false);
|
||||
migrationProgress.set(100);
|
||||
migrationStatus.set('Migration completed successfully!');
|
||||
|
||||
// Clear step details after a delay
|
||||
setTimeout(() => {
|
||||
migrationStepName.set('');
|
||||
migrationStepProgress.set(0);
|
||||
migrationStepStatus.set('');
|
||||
migrationStepDetails.set(null);
|
||||
migrationCurrentStep.set(0);
|
||||
migrationTotalSteps.set(0);
|
||||
}, 3000);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fail migration
|
||||
*/
|
||||
failMigration(error) {
|
||||
isMigrating.set(false);
|
||||
migrationStatus.set(`Migration failed: ${error.message || error}`);
|
||||
migrationStepStatus.set('Error occurred');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get progress history
|
||||
*/
|
||||
getProgressHistory() {
|
||||
return this.progressHistory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear progress
|
||||
*/
|
||||
clearProgress() {
|
||||
isMigrating.set(false);
|
||||
migrationProgress.set(0);
|
||||
migrationStatus.set('');
|
||||
migrationStepName.set('');
|
||||
migrationStepProgress.set(0);
|
||||
migrationStepStatus.set('');
|
||||
migrationStepDetails.set(null);
|
||||
migrationCurrentStep.set(0);
|
||||
migrationTotalSteps.set(0);
|
||||
this.progressHistory = [];
|
||||
}
|
||||
}
|
||||
|
||||
// Export singleton instance
|
||||
export const migrationProgressManager = new MigrationProgressManager();
|
||||
|
||||
// Template helpers
|
||||
Template.migrationProgress.helpers({
|
||||
isMigrating() {
|
||||
return isMigrating.get();
|
||||
},
|
||||
|
||||
overallProgress() {
|
||||
return migrationProgress.get();
|
||||
},
|
||||
|
||||
overallStatus() {
|
||||
return migrationStatus.get();
|
||||
},
|
||||
|
||||
currentStep() {
|
||||
return migrationCurrentStep.get();
|
||||
},
|
||||
|
||||
totalSteps() {
|
||||
return migrationTotalSteps.get();
|
||||
},
|
||||
|
||||
stepName() {
|
||||
return migrationStepName.get();
|
||||
},
|
||||
|
||||
stepProgress() {
|
||||
return migrationStepProgress.get();
|
||||
},
|
||||
|
||||
stepStatus() {
|
||||
return migrationStepStatus.get();
|
||||
},
|
||||
|
||||
stepDetails() {
|
||||
return migrationStepDetails.get();
|
||||
},
|
||||
|
||||
progressBarStyle() {
|
||||
const progress = migrationProgress.get();
|
||||
return `width: ${progress}%`;
|
||||
},
|
||||
|
||||
stepProgressBarStyle() {
|
||||
const progress = migrationStepProgress.get();
|
||||
return `width: ${progress}%`;
|
||||
},
|
||||
|
||||
stepNameFormatted() {
|
||||
const stepName = migrationStepName.get();
|
||||
if (!stepName) return '';
|
||||
|
||||
// Convert snake_case to Title Case
|
||||
return stepName
|
||||
.split('_')
|
||||
.map(word => word.charAt(0).toUpperCase() + word.slice(1))
|
||||
.join(' ');
|
||||
},
|
||||
|
||||
stepDetailsFormatted() {
|
||||
const details = migrationStepDetails.get();
|
||||
if (!details) return '';
|
||||
|
||||
const formatted = [];
|
||||
for (const [key, value] of Object.entries(details)) {
|
||||
const formattedKey = key
|
||||
.split(/(?=[A-Z])/)
|
||||
.join(' ')
|
||||
.toLowerCase()
|
||||
.replace(/^\w/, c => c.toUpperCase());
|
||||
formatted.push(`${formattedKey}: ${value}`);
|
||||
}
|
||||
|
||||
return formatted.join(', ');
|
||||
}
|
||||
});
|
||||
|
||||
// Template events
|
||||
Template.migrationProgress.events({
|
||||
'click .js-close-migration-progress'() {
|
||||
migrationProgressManager.clearProgress();
|
||||
}
|
||||
});
|
||||
|
|
@ -170,7 +170,10 @@ template(name="setting")
|
|||
label {{_ 'migration-status'}}
|
||||
.status-indicator
|
||||
span.status-label {{_ 'status'}}:
|
||||
span.status-value {{migrationStatus}}
|
||||
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")
|
||||
|
|
@ -179,9 +182,13 @@ template(name="setting")
|
|||
| {{migrationProgress}}% {{_ 'complete'}}
|
||||
|
||||
.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'}}
|
||||
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
|
||||
|
||||
li
|
||||
h3 {{_ 'board-operations'}}
|
||||
|
|
@ -200,7 +207,7 @@ template(name="setting")
|
|||
.job-info
|
||||
.job-name {{name}}
|
||||
.job-schedule {{schedule}}
|
||||
.job-description {{description}}
|
||||
.job-status {{status}}
|
||||
.job-actions
|
||||
button.js-pause-job.btn.btn-sm.btn-warning(data-job-id="{{_id}}") {{_ 'pause'}}
|
||||
button.js-delete-job.btn.btn-sm.btn-danger(data-job-id="{{_id}}") {{_ 'delete'}}
|
||||
|
|
@ -274,7 +281,7 @@ template(name='email')
|
|||
// li.smtp-form
|
||||
// .title {{_ 'smtp-username'}}
|
||||
// .form-group
|
||||
// input.wekan-form-control#mail-server-u"accounts-allowUserNameChange": "Allow Username Change",sername(type="text", placeholder="{{_ 'username'}}" value="{{currentSetting.mailServer.username}}")
|
||||
// input.wekan-form-control#mail-server-username(type="text", placeholder="{{_ 'username'}}" value="{{currentSetting.mailServer.username}}")
|
||||
// li.smtp-form
|
||||
// .title {{_ 'smtp-password'}}
|
||||
// .form-group
|
||||
|
|
|
|||
|
|
@ -2,6 +2,14 @@ import { ReactiveCache } from '/imports/reactiveCache';
|
|||
import { TAPi18n } from '/imports/i18n';
|
||||
import { ALLOWED_WAIT_SPINNERS } from '/config/const';
|
||||
import LockoutSettings from '/models/lockoutSettings';
|
||||
import {
|
||||
cronMigrationProgress,
|
||||
cronMigrationStatus,
|
||||
cronMigrationCurrentStep,
|
||||
cronMigrationSteps,
|
||||
cronIsMigrating,
|
||||
cronJobs
|
||||
} from '/imports/cronMigrationClient';
|
||||
|
||||
|
||||
BlazeComponent.extendComponent({
|
||||
|
|
@ -115,15 +123,27 @@ BlazeComponent.extendComponent({
|
|||
|
||||
// Cron settings helpers
|
||||
migrationStatus() {
|
||||
return TAPi18n.__('idle'); // Placeholder
|
||||
return cronMigrationStatus.get() || TAPi18n.__('idle');
|
||||
},
|
||||
|
||||
migrationProgress() {
|
||||
return 0; // Placeholder
|
||||
return cronMigrationProgress.get() || 0;
|
||||
},
|
||||
|
||||
migrationCurrentStep() {
|
||||
return cronMigrationCurrentStep.get() || '';
|
||||
},
|
||||
|
||||
isMigrating() {
|
||||
return cronIsMigrating.get() || false;
|
||||
},
|
||||
|
||||
migrationSteps() {
|
||||
return cronMigrationSteps.get() || [];
|
||||
},
|
||||
|
||||
cronJobs() {
|
||||
return []; // Placeholder
|
||||
return cronJobs.get() || [];
|
||||
},
|
||||
|
||||
setLoading(w) {
|
||||
|
|
@ -169,7 +189,9 @@ BlazeComponent.extendComponent({
|
|||
// Event handlers for cron settings
|
||||
'click button.js-start-all-migrations'(event) {
|
||||
event.preventDefault();
|
||||
Meteor.call('startAllMigrations', (error, result) => {
|
||||
this.setLoading(true);
|
||||
Meteor.call('cron.startAllMigrations', (error, result) => {
|
||||
this.setLoading(false);
|
||||
if (error) {
|
||||
alert(TAPi18n.__('migration-start-failed') + ': ' + error.reason);
|
||||
} else {
|
||||
|
|
@ -180,7 +202,9 @@ BlazeComponent.extendComponent({
|
|||
|
||||
'click button.js-pause-all-migrations'(event) {
|
||||
event.preventDefault();
|
||||
Meteor.call('pauseAllMigrations', (error, result) => {
|
||||
this.setLoading(true);
|
||||
Meteor.call('cron.pauseAllMigrations', (error, result) => {
|
||||
this.setLoading(false);
|
||||
if (error) {
|
||||
alert(TAPi18n.__('migration-pause-failed') + ': ' + error.reason);
|
||||
} else {
|
||||
|
|
@ -192,7 +216,9 @@ BlazeComponent.extendComponent({
|
|||
'click button.js-stop-all-migrations'(event) {
|
||||
event.preventDefault();
|
||||
if (confirm(TAPi18n.__('migration-stop-confirm'))) {
|
||||
Meteor.call('stopAllMigrations', (error, result) => {
|
||||
this.setLoading(true);
|
||||
Meteor.call('cron.stopAllMigrations', (error, result) => {
|
||||
this.setLoading(false);
|
||||
if (error) {
|
||||
alert(TAPi18n.__('migration-stop-failed') + ': ' + error.reason);
|
||||
} else {
|
||||
|
|
@ -204,41 +230,28 @@ BlazeComponent.extendComponent({
|
|||
|
||||
'click button.js-schedule-board-cleanup'(event) {
|
||||
event.preventDefault();
|
||||
Meteor.call('scheduleBoardCleanup', (error, result) => {
|
||||
if (error) {
|
||||
alert(TAPi18n.__('board-cleanup-failed') + ': ' + error.reason);
|
||||
} else {
|
||||
alert(TAPi18n.__('board-cleanup-scheduled'));
|
||||
}
|
||||
});
|
||||
// Placeholder - board cleanup scheduling
|
||||
alert(TAPi18n.__('board-cleanup-scheduled'));
|
||||
},
|
||||
|
||||
'click button.js-schedule-board-archive'(event) {
|
||||
event.preventDefault();
|
||||
Meteor.call('scheduleBoardArchive', (error, result) => {
|
||||
if (error) {
|
||||
alert(TAPi18n.__('board-archive-failed') + ': ' + error.reason);
|
||||
} else {
|
||||
alert(TAPi18n.__('board-archive-scheduled'));
|
||||
}
|
||||
});
|
||||
// Placeholder - board archive scheduling
|
||||
alert(TAPi18n.__('board-archive-scheduled'));
|
||||
},
|
||||
|
||||
'click button.js-schedule-board-backup'(event) {
|
||||
event.preventDefault();
|
||||
Meteor.call('scheduleBoardBackup', (error, result) => {
|
||||
if (error) {
|
||||
alert(TAPi18n.__('board-backup-failed') + ': ' + error.reason);
|
||||
} else {
|
||||
alert(TAPi18n.__('board-backup-scheduled'));
|
||||
}
|
||||
});
|
||||
// Placeholder - board backup scheduling
|
||||
alert(TAPi18n.__('board-backup-scheduled'));
|
||||
},
|
||||
|
||||
'click button.js-pause-job'(event) {
|
||||
event.preventDefault();
|
||||
const jobId = $(event.target).data('job-id');
|
||||
Meteor.call('pauseCronJob', jobId, (error, result) => {
|
||||
this.setLoading(true);
|
||||
Meteor.call('cron.pauseJob', jobId, (error, result) => {
|
||||
this.setLoading(false);
|
||||
if (error) {
|
||||
alert(TAPi18n.__('cron-job-pause-failed') + ': ' + error.reason);
|
||||
} else {
|
||||
|
|
@ -251,7 +264,9 @@ BlazeComponent.extendComponent({
|
|||
event.preventDefault();
|
||||
const jobId = $(event.target).data('job-id');
|
||||
if (confirm(TAPi18n.__('cron-job-delete-confirm'))) {
|
||||
Meteor.call('deleteCronJob', jobId, (error, result) => {
|
||||
this.setLoading(true);
|
||||
Meteor.call('cron.removeJob', jobId, (error, result) => {
|
||||
this.setLoading(false);
|
||||
if (error) {
|
||||
alert(TAPi18n.__('cron-job-delete-failed') + ': ' + error.reason);
|
||||
} else {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue