| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552 | import { Template } from 'meteor/templating';import { ReactiveVar } from 'meteor/reactive-var';import { Meteor } from 'meteor/meteor';import { TAPi18n } from '/imports/i18n';// Reactive variables for cron settingsconst migrationProgress = new ReactiveVar(0);const migrationStatus = new ReactiveVar('');const migrationCurrentStep = new ReactiveVar('');const migrationSteps = new ReactiveVar([]);const isMigrating = new ReactiveVar(false);const cronJobs = new ReactiveVar([]);Template.cronSettings.onCreated(function() {  this.loading = new ReactiveVar(true);  this.showMigrations = new ReactiveVar(true);  this.showBoardOperations = new ReactiveVar(false);  this.showJobs = new ReactiveVar(false);  this.showAddJob = new ReactiveVar(false);  // Board operations pagination  this.currentPage = new ReactiveVar(1);  this.pageSize = new ReactiveVar(20);  this.searchTerm = new ReactiveVar('');  this.boardOperations = new ReactiveVar([]);  this.operationStats = new ReactiveVar({});  this.pagination = new ReactiveVar({});  this.queueStats = new ReactiveVar({});  this.systemResources = new ReactiveVar({});  this.boardMigrationStats = new ReactiveVar({});  // Load initial data  loadCronData(this);});Template.cronSettings.helpers({  loading() {    const instance = Template.instance();    return instance && instance.loading ? instance.loading.get() : true;  },    showMigrations() {    const instance = Template.instance();    return instance && instance.showMigrations ? instance.showMigrations.get() : true;  },    showBoardOperations() {    const instance = Template.instance();    return instance && instance.showBoardOperations ? instance.showBoardOperations.get() : false;  },    showJobs() {    const instance = Template.instance();    return instance && instance.showJobs ? instance.showJobs.get() : false;  },    showAddJob() {    const instance = Template.instance();    return instance && instance.showAddJob ? instance.showAddJob.get() : false;  },    migrationProgress() {    return migrationProgress.get();  },    migrationStatus() {    return migrationStatus.get();  },    migrationCurrentStep() {    return migrationCurrentStep.get();  },    migrationSteps() {    const steps = migrationSteps.get();    const currentStep = migrationCurrentStep.get();        return steps.map(step => ({      ...step,      isCurrentStep: step.name === currentStep    }));  },    cronJobs() {    return cronJobs.get();  },    formatDate(date) {    if (!date) return '-';    return new Date(date).toLocaleString();  },  boardOperations() {    const instance = Template.instance();    return instance && instance.boardOperations ? instance.boardOperations.get() : [];  },  operationStats() {    const instance = Template.instance();    return instance && instance.operationStats ? instance.operationStats.get() : {};  },  pagination() {    const instance = Template.instance();    return instance && instance.pagination ? instance.pagination.get() : {};  },  queueStats() {    const instance = Template.instance();    return instance && instance.queueStats ? instance.queueStats.get() : {};  },  systemResources() {    const instance = Template.instance();    return instance && instance.systemResources ? instance.systemResources.get() : {};  },  boardMigrationStats() {    const instance = Template.instance();    return instance && instance.boardMigrationStats ? instance.boardMigrationStats.get() : {};  },  formatDateTime(date) {    if (!date) return '-';    return new Date(date).toLocaleString();  },  formatDuration(startTime, endTime) {    if (!startTime) return '-';    const start = new Date(startTime);    const end = endTime ? new Date(endTime) : new Date();    const diffMs = end - start;    const diffMins = Math.floor(diffMs / 60000);    const diffSecs = Math.floor((diffMs % 60000) / 1000);        if (diffMins > 0) {      return `${diffMins}m ${diffSecs}s`;    } else {      return `${diffSecs}s`;    }  }});Template.cronSettings.switchMenu = function(event, targetID) {  const instance = Template.instance();    // Reset all tabs  instance.showMigrations.set(false);  instance.showBoardOperations.set(false);  instance.showJobs.set(false);  instance.showAddJob.set(false);    // Set the selected tab  if (targetID === 'cron-migrations') {    instance.showMigrations.set(true);  } else if (targetID === 'cron-board-operations') {    instance.showBoardOperations.set(true);  } else if (targetID === 'cron-jobs') {    instance.showJobs.set(true);  } else if (targetID === 'cron-add') {    instance.showAddJob.set(true);  }};Template.cronSettings.events({  'click .js-cron-migrations'(event) {    event.preventDefault();    const instance = Template.instance();    instance.showMigrations.set(true);    instance.showJobs.set(false);    instance.showAddJob.set(false);  },    'click .js-cron-board-operations'(event) {    event.preventDefault();    const instance = Template.instance();    instance.showMigrations.set(false);    instance.showBoardOperations.set(true);    instance.showJobs.set(false);    instance.showAddJob.set(false);    loadBoardOperations(instance);  },    'click .js-cron-jobs'(event) {    event.preventDefault();    const instance = Template.instance();    instance.showMigrations.set(false);    instance.showBoardOperations.set(false);    instance.showJobs.set(true);    instance.showAddJob.set(false);    loadCronJobs(instance);  },    'click .js-cron-add'(event) {    event.preventDefault();    const instance = Template.instance();    instance.showMigrations.set(false);    instance.showJobs.set(false);    instance.showAddJob.set(true);  },    'click .js-start-all-migrations'(event) {    event.preventDefault();    Meteor.call('cron.startAllMigrations', (error, result) => {      if (error) {        console.error('Failed to start migrations:', error);        alert('Failed to start migrations: ' + error.message);      } else {        // Migrations started successfully        pollMigrationProgress(Template.instance());      }    });  },    'click .js-pause-all-migrations'(event) {    event.preventDefault();    // Pause all migration cron jobs    const jobs = cronJobs.get();    jobs.forEach(job => {      if (job.name.startsWith('migration_')) {        Meteor.call('cron.pauseJob', job.name);      }    });  },    'click .js-stop-all-migrations'(event) {    event.preventDefault();    // Stop all migration cron jobs    const jobs = cronJobs.get();    jobs.forEach(job => {      if (job.name.startsWith('migration_')) {        Meteor.call('cron.stopJob', job.name);      }    });  },    'click .js-refresh-jobs'(event) {    event.preventDefault();    loadCronJobs(Template.instance());  },    'click .js-start-job'(event) {    event.preventDefault();    const jobName = $(event.currentTarget).data('job');    Meteor.call('cron.startJob', jobName, (error, result) => {      if (error) {        console.error('Failed to start job:', error);        alert('Failed to start job: ' + error.message);      } else {        console.log('Job started successfully');        loadCronJobs(Template.instance());      }    });  },    'click .js-pause-job'(event) {    event.preventDefault();    const jobName = $(event.currentTarget).data('job');    Meteor.call('cron.pauseJob', jobName, (error, result) => {      if (error) {        console.error('Failed to pause job:', error);        alert('Failed to pause job: ' + error.message);      } else {        console.log('Job paused successfully');        loadCronJobs(Template.instance());      }    });  },    'click .js-stop-job'(event) {    event.preventDefault();    const jobName = $(event.currentTarget).data('job');    Meteor.call('cron.stopJob', jobName, (error, result) => {      if (error) {        console.error('Failed to stop job:', error);        alert('Failed to stop job: ' + error.message);      } else {        console.log('Job stopped successfully');        loadCronJobs(Template.instance());      }    });  },    'click .js-remove-job'(event) {    event.preventDefault();    const jobName = $(event.currentTarget).data('job');    if (confirm('Are you sure you want to remove this job?')) {      Meteor.call('cron.removeJob', jobName, (error, result) => {        if (error) {          console.error('Failed to remove job:', error);          alert('Failed to remove job: ' + error.message);        } else {          console.log('Job removed successfully');          loadCronJobs(Template.instance());        }      });    }  },    'submit .js-add-cron-job-form'(event) {    event.preventDefault();    const form = event.currentTarget;    const formData = new FormData(form);        const jobData = {      name: formData.get('name'),      description: formData.get('description'),      schedule: formData.get('schedule'),      weight: parseInt(formData.get('weight'))    };        Meteor.call('cron.addJob', jobData, (error, result) => {      if (error) {        console.error('Failed to add job:', error);        alert('Failed to add job: ' + error.message);      } else {        console.log('Job added successfully');        form.reset();        Template.instance().showJobs.set(true);        Template.instance().showAddJob.set(false);        loadCronJobs(Template.instance());      }    });  },    'click .js-cancel-add-job'(event) {    event.preventDefault();    const instance = Template.instance();    instance.showJobs.set(true);    instance.showAddJob.set(false);  },  'click .js-refresh-board-operations'(event) {    event.preventDefault();    loadBoardOperations(Template.instance());  },  'click .js-start-test-operation'(event) {    event.preventDefault();    const testBoardId = 'test-board-' + Date.now();    const operationData = {      sourceBoardId: 'source-board',      targetBoardId: 'target-board',      copyOptions: { includeCards: true, includeAttachments: true }    };        Meteor.call('cron.startBoardOperation', testBoardId, 'copy_board', operationData, (error, result) => {      if (error) {        console.error('Failed to start test operation:', error);        alert('Failed to start test operation: ' + error.message);      } else {        console.log('Test operation started:', result);        loadBoardOperations(Template.instance());      }    });  },  'input .js-search-board-operations'(event) {    const searchTerm = $(event.currentTarget).val();    const instance = Template.instance();    instance.searchTerm.set(searchTerm);    instance.currentPage.set(1);    loadBoardOperations(instance);  },  'click .js-prev-page'(event) {    event.preventDefault();    const instance = Template.instance();    const currentPage = instance.currentPage.get();    if (currentPage > 1) {      instance.currentPage.set(currentPage - 1);      loadBoardOperations(instance);    }  },  'click .js-next-page'(event) {    event.preventDefault();    const instance = Template.instance();    const currentPage = instance.currentPage.get();    const pagination = instance.pagination.get();    if (currentPage < pagination.totalPages) {      instance.currentPage.set(currentPage + 1);      loadBoardOperations(instance);    }  },  'click .js-pause-operation'(event) {    event.preventDefault();    const operationId = $(event.currentTarget).data('operation');    // Implementation for pausing operation    console.log('Pause operation:', operationId);  },  'click .js-resume-operation'(event) {    event.preventDefault();    const operationId = $(event.currentTarget).data('operation');    // Implementation for resuming operation    console.log('Resume operation:', operationId);  },  'click .js-stop-operation'(event) {    event.preventDefault();    const operationId = $(event.currentTarget).data('operation');    if (confirm('Are you sure you want to stop this operation?')) {      // Implementation for stopping operation      console.log('Stop operation:', operationId);    }  },  'click .js-view-details'(event) {    event.preventDefault();    const operationId = $(event.currentTarget).data('operation');    // Implementation for viewing operation details    console.log('View details for operation:', operationId);  },  'click .js-force-board-scan'(event) {    event.preventDefault();    Meteor.call('cron.forceBoardMigrationScan', (error, result) => {      if (error) {        console.error('Failed to force board scan:', error);        alert('Failed to force board scan: ' + error.message);      } else {        // Board scan started successfully        // Refresh the data        loadBoardOperations(Template.instance());      }    });  }});// Helper functions for cron settingsfunction loadCronData(instance) {  instance.loading.set(true);    // Load migration progress  Meteor.call('cron.getMigrationProgress', (error, result) => {    if (result) {      migrationProgress.set(result.progress);      migrationStatus.set(result.status);      migrationCurrentStep.set(result.currentStep);      migrationSteps.set(result.steps);      isMigrating.set(result.isMigrating);    }  });    // Load cron jobs  loadCronJobs(instance);    instance.loading.set(false);}function loadCronJobs(instance) {  Meteor.call('cron.getJobs', (error, result) => {    if (result) {      cronJobs.set(result);    }  });}function loadBoardOperations(instance) {  const page = instance.currentPage.get();  const limit = instance.pageSize.get();  const searchTerm = instance.searchTerm.get();  Meteor.call('cron.getAllBoardOperations', page, limit, searchTerm, (error, result) => {    if (result) {      instance.boardOperations.set(result.operations);      instance.pagination.set({        total: result.total,        page: result.page,        limit: result.limit,        totalPages: result.totalPages,        start: ((result.page - 1) * result.limit) + 1,        end: Math.min(result.page * result.limit, result.total),        hasPrev: result.page > 1,        hasNext: result.page < result.totalPages      });    }  });  // Load operation stats  Meteor.call('cron.getBoardOperationStats', (error, result) => {    if (result) {      instance.operationStats.set(result);    }  });  // Load queue stats  Meteor.call('cron.getQueueStats', (error, result) => {    if (result) {      instance.queueStats.set(result);    }  });  // Load system resources  Meteor.call('cron.getSystemResources', (error, result) => {    if (result) {      instance.systemResources.set(result);    }  });  // Load board migration stats  Meteor.call('cron.getBoardMigrationStats', (error, result) => {    if (result) {      instance.boardMigrationStats.set(result);    }  });}function pollMigrationProgress(instance) {  const pollInterval = setInterval(() => {    Meteor.call('cron.getMigrationProgress', (error, result) => {      if (result) {        migrationProgress.set(result.progress);        migrationStatus.set(result.status);        migrationCurrentStep.set(result.currentStep);        migrationSteps.set(result.steps);        isMigrating.set(result.isMigrating);                // Stop polling if migration is complete        if (!result.isMigrating && result.progress === 100) {          clearInterval(pollInterval);        }      }    });  }, 1000);}// Template helpers for cronSettingsTemplate.cronSettings.helpers({  loading() {    const instance = Template.instance();    return instance.loading && instance.loading.get();  },  showMigrations() {    const instance = Template.instance();    return instance.showMigrations && instance.showMigrations.get();  },  showBoardOperations() {    const instance = Template.instance();    return instance.showBoardOperations && instance.showBoardOperations.get();  },  showJobs() {    const instance = Template.instance();    return instance.showJobs && instance.showJobs.get();  },  showAddJob() {    const instance = Template.instance();    return instance.showAddJob && instance.showAddJob.get();  },});
 |