123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169 |
- /**
- * Attachment Migration Manager
- * Handles migration of attachments from old structure to new structure
- * with UI feedback and spinners for unconverted attachments
- */
- import { ReactiveVar } from 'meteor/reactive-var';
- import { ReactiveCache } from '/imports/reactiveCache';
- // Reactive variables for attachment migration progress
- export const attachmentMigrationProgress = new ReactiveVar(0);
- export const attachmentMigrationStatus = new ReactiveVar('');
- export const isMigratingAttachments = new ReactiveVar(false);
- export const unconvertedAttachments = new ReactiveVar([]);
- class AttachmentMigrationManager {
- constructor() {
- this.migrationCache = new Map(); // Cache migrated attachment IDs
- }
- /**
- * Check if an attachment needs migration
- * @param {string} attachmentId - The attachment ID to check
- * @returns {boolean} - True if attachment needs migration
- */
- needsMigration(attachmentId) {
- if (this.migrationCache.has(attachmentId)) {
- return false; // Already migrated
- }
- try {
- const attachment = ReactiveCache.getAttachment(attachmentId);
- if (!attachment) return false;
- // Check if attachment has old structure (no meta field or missing required fields)
- return !attachment.meta ||
- !attachment.meta.cardId ||
- !attachment.meta.boardId ||
- !attachment.meta.listId;
- } catch (error) {
- console.error('Error checking if attachment needs migration:', error);
- return false;
- }
- }
- /**
- * Get all unconverted attachments for a board
- * @param {string} boardId - The board ID
- * @returns {Array} - Array of unconverted attachments
- */
- getUnconvertedAttachments(boardId) {
- try {
- const attachments = ReactiveCache.getAttachments({
- 'meta.boardId': boardId
- });
- return attachments.filter(attachment => this.needsMigration(attachment._id));
- } catch (error) {
- console.error('Error getting unconverted attachments:', error);
- return [];
- }
- }
- /**
- * Start migration for attachments in a board
- * @param {string} boardId - The board ID
- */
- async startAttachmentMigration(boardId) {
- if (isMigratingAttachments.get()) {
- return; // Already migrating
- }
- isMigratingAttachments.set(true);
- attachmentMigrationStatus.set('Starting attachment migration...');
- attachmentMigrationProgress.set(0);
- try {
- const unconverted = this.getUnconvertedAttachments(boardId);
- unconvertedAttachments.set(unconverted);
- if (unconverted.length === 0) {
- attachmentMigrationStatus.set('All attachments are already migrated');
- attachmentMigrationProgress.set(100);
- isMigratingAttachments.set(false);
- return;
- }
- // Start server-side migration
- Meteor.call('attachmentMigration.migrateBoardAttachments', boardId, (error, result) => {
- if (error) {
- console.error('Failed to start attachment migration:', error);
- attachmentMigrationStatus.set(`Migration failed: ${error.message}`);
- isMigratingAttachments.set(false);
- } else {
- console.log('Attachment migration started for board:', boardId);
- this.pollAttachmentMigrationProgress(boardId);
- }
- });
- } catch (error) {
- console.error('Error starting attachment migration:', error);
- attachmentMigrationStatus.set(`Migration failed: ${error.message}`);
- isMigratingAttachments.set(false);
- }
- }
- /**
- * Poll for attachment migration progress
- * @param {string} boardId - The board ID
- */
- pollAttachmentMigrationProgress(boardId) {
- const pollInterval = setInterval(() => {
- Meteor.call('attachmentMigration.getProgress', boardId, (error, result) => {
- if (error) {
- console.error('Error getting migration progress:', error);
- clearInterval(pollInterval);
- isMigratingAttachments.set(false);
- return;
- }
- if (result) {
- attachmentMigrationProgress.set(result.progress);
- attachmentMigrationStatus.set(result.status);
- unconvertedAttachments.set(result.unconvertedAttachments || []);
- // Stop polling if migration is complete
- if (result.progress >= 100 || result.status === 'completed') {
- clearInterval(pollInterval);
- isMigratingAttachments.set(false);
- this.migrationCache.clear(); // Clear cache to refresh data
- }
- }
- });
- }, 1000);
- }
- /**
- * Check if an attachment is currently being migrated
- * @param {string} attachmentId - The attachment ID
- * @returns {boolean} - True if attachment is being migrated
- */
- isAttachmentBeingMigrated(attachmentId) {
- const unconverted = unconvertedAttachments.get();
- return unconverted.some(attachment => attachment._id === attachmentId);
- }
- /**
- * Get migration status for an attachment
- * @param {string} attachmentId - The attachment ID
- * @returns {string} - Migration status ('migrated', 'migrating', 'unmigrated')
- */
- getAttachmentMigrationStatus(attachmentId) {
- if (this.migrationCache.has(attachmentId)) {
- return 'migrated';
- }
- if (this.isAttachmentBeingMigrated(attachmentId)) {
- return 'migrating';
- }
- return this.needsMigration(attachmentId) ? 'unmigrated' : 'migrated';
- }
- }
- export const attachmentMigrationManager = new AttachmentMigrationManager();
|