diff --git a/src/main/engine/MetadataDiffEngine.ts b/src/main/engine/MetadataDiffEngine.ts
index 8481e26..09ca154 100644
--- a/src/main/engine/MetadataDiffEngine.ts
+++ b/src/main/engine/MetadataDiffEngine.ts
@@ -320,12 +320,17 @@ export class MetadataDiffEngine extends EventEmitter {
* Sync database metadata to files for the given posts
* (DB -> File: writes current DB metadata to markdown files)
*/
- async syncDbToFile(postIds: string[]): Promise<{ success: number; failed: number }> {
+ async syncDbToFile(
+ postIds: string[],
+ onProgress?: (percent: number, message: string) => void
+ ): Promise<{ success: number; failed: number }> {
const postEngine = getPostEngine();
+ const total = postIds.length;
let success = 0;
let failed = 0;
- for (const postId of postIds) {
+ for (let i = 0; i < postIds.length; i++) {
+ const postId = postIds[i];
try {
const synced = await postEngine.syncPublishedPostFile(postId);
if (synced) {
@@ -337,6 +342,17 @@ export class MetadataDiffEngine extends EventEmitter {
console.error(`[MetadataDiffEngine] Failed to sync post ${postId} to file:`, error);
failed++;
}
+
+ // Report progress every 10 posts or on last post
+ if (onProgress && (i % 10 === 0 || i === postIds.length - 1)) {
+ const percent = Math.round(((i + 1) / total) * 100);
+ onProgress(percent, `Synced ${i + 1} of ${total} posts...`);
+ }
+
+ // Yield to event loop every 20 posts
+ if (i % 20 === 0) {
+ await new Promise(resolve => setImmediate(resolve));
+ }
}
return { success, failed };
@@ -346,12 +362,18 @@ export class MetadataDiffEngine extends EventEmitter {
* Sync file metadata to database for the given posts
* (File -> DB: reads file metadata and updates DB)
*/
- async syncFileToDb(postIds: string[], field?: DiffField): Promise<{ success: number; failed: number }> {
+ async syncFileToDb(
+ postIds: string[],
+ field?: DiffField,
+ onProgress?: (percent: number, message: string) => void
+ ): Promise<{ success: number; failed: number }> {
const db = this.getDb();
+ const total = postIds.length;
let success = 0;
let failed = 0;
- for (const postId of postIds) {
+ for (let i = 0; i < postIds.length; i++) {
+ const postId = postIds[i];
try {
// Get the post from DB to get file path
const dbPost = await db
@@ -404,6 +426,17 @@ export class MetadataDiffEngine extends EventEmitter {
console.error(`[MetadataDiffEngine] Failed to sync post ${postId} to DB:`, error);
failed++;
}
+
+ // Report progress every 10 posts or on last post
+ if (onProgress && (i % 10 === 0 || i === postIds.length - 1)) {
+ const percent = Math.round(((i + 1) / total) * 100);
+ onProgress(percent, `Synced ${i + 1} of ${total} posts...`);
+ }
+
+ // Yield to event loop every 20 posts
+ if (i % 20 === 0) {
+ await new Promise(resolve => setImmediate(resolve));
+ }
}
return { success, failed };
@@ -433,8 +466,7 @@ export class MetadataDiffEngine extends EventEmitter {
id: `metadata-sync-db-to-file-${Date.now()}`,
name: `Syncing ${groupLabel} from DB to files`,
execute: async (onProgress) => {
- onProgress(0, `Syncing ${postIds.length} posts...`);
- const result = await this.syncDbToFile(postIds);
+ const result = await this.syncDbToFile(postIds, onProgress);
onProgress(100, `Completed: ${result.success} synced, ${result.failed} failed`);
return result;
},
@@ -449,8 +481,7 @@ export class MetadataDiffEngine extends EventEmitter {
id: `metadata-sync-file-to-db-${Date.now()}`,
name: `Syncing ${groupLabel} from files to DB`,
execute: async (onProgress) => {
- onProgress(0, `Syncing ${postIds.length} posts...`);
- const result = await this.syncFileToDb(postIds, field);
+ const result = await this.syncFileToDb(postIds, field, onProgress);
onProgress(100, `Completed: ${result.success} synced, ${result.failed} failed`);
return result;
},
diff --git a/src/renderer/components/TabBar/TabBar.tsx b/src/renderer/components/TabBar/TabBar.tsx
index 285da2e..e09c6b9 100644
--- a/src/renderer/components/TabBar/TabBar.tsx
+++ b/src/renderer/components/TabBar/TabBar.tsx
@@ -43,6 +43,10 @@ const getTabTitle = (
return importDefTitles.get(tab.id) || 'Import';
}
+ if (tab.type === 'metadata-diff') {
+ return 'Metadata Diff';
+ }
+
return 'Unknown';
};
@@ -84,6 +88,12 @@ const getTabIcon = (tab: Tab): React.ReactNode => {
);
+ case 'metadata-diff':
+ return (
+
+ );
default:
return (