wekan/client/lib/attachmentMigrationManager.js
Lauri Ojansivu bd8c565415 Fixes to make board showing correctly.
Thanks to xet7 !
2025-10-12 03:48:21 +03:00

169 lines
5.3 KiB
JavaScript

/**
* 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();