diff --git a/drizzle/0001_narrow_black_bolt.sql b/drizzle/0001_narrow_black_bolt.sql new file mode 100644 index 0000000..8b9bc93 --- /dev/null +++ b/drizzle/0001_narrow_black_bolt.sql @@ -0,0 +1,5 @@ +DROP TABLE `sync_log`;--> statement-breakpoint +ALTER TABLE `media` DROP COLUMN `sync_status`;--> statement-breakpoint +ALTER TABLE `media` DROP COLUMN `synced_at`;--> statement-breakpoint +ALTER TABLE `posts` DROP COLUMN `sync_status`;--> statement-breakpoint +ALTER TABLE `posts` DROP COLUMN `synced_at`; \ No newline at end of file diff --git a/drizzle/meta/0001_snapshot.json b/drizzle/meta/0001_snapshot.json new file mode 100644 index 0000000..cd5b177 --- /dev/null +++ b/drizzle/meta/0001_snapshot.json @@ -0,0 +1,752 @@ +{ + "version": "6", + "dialect": "sqlite", + "id": "c9e34b7f-92a5-4549-99c9-e5a680004bfc", + "prevId": "af3c1207-a667-495d-833d-26f7d3451829", + "tables": { + "chat_conversations": { + "name": "chat_conversations", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "model": { + "name": "model", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "copilot_session_id": { + "name": "copilot_session_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "chat_messages": { + "name": "chat_messages", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "conversation_id": { + "name": "conversation_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "role": { + "name": "role", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "content": { + "name": "content", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "tool_call_id": { + "name": "tool_call_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "tool_calls": { + "name": "tool_calls", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "import_definitions": { + "name": "import_definitions", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "project_id": { + "name": "project_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "wxr_file_path": { + "name": "wxr_file_path", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "uploads_folder_path": { + "name": "uploads_folder_path", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "last_analysis_result": { + "name": "last_analysis_result", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "media": { + "name": "media", + "columns": { + "project_id": { + "name": "project_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "filename": { + "name": "filename", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "original_name": { + "name": "original_name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "mime_type": { + "name": "mime_type", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "size": { + "name": "size", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "width": { + "name": "width", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "height": { + "name": "height", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "alt": { + "name": "alt", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "caption": { + "name": "caption", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "file_path": { + "name": "file_path", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "sidecar_path": { + "name": "sidecar_path", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "checksum": { + "name": "checksum", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "tags": { + "name": "tags", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "post_links": { + "name": "post_links", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "source_post_id": { + "name": "source_post_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "target_post_id": { + "name": "target_post_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "link_text": { + "name": "link_text", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "post_media": { + "name": "post_media", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "project_id": { + "name": "project_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "post_id": { + "name": "post_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "media_id": { + "name": "media_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "sort_order": { + "name": "sort_order", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "post_media_post_media_idx": { + "name": "post_media_post_media_idx", + "columns": [ + "post_id", + "media_id" + ], + "isUnique": true + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "posts": { + "name": "posts", + "columns": { + "project_id": { + "name": "project_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "slug": { + "name": "slug", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "excerpt": { + "name": "excerpt", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "content": { + "name": "content", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'draft'" + }, + "author": { + "name": "author", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "published_at": { + "name": "published_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "file_path": { + "name": "file_path", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "''" + }, + "checksum": { + "name": "checksum", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "tags": { + "name": "tags", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "categories": { + "name": "categories", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "published_title": { + "name": "published_title", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "published_content": { + "name": "published_content", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "published_tags": { + "name": "published_tags", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "published_categories": { + "name": "published_categories", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "published_excerpt": { + "name": "published_excerpt", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": { + "posts_project_slug_idx": { + "name": "posts_project_slug_idx", + "columns": [ + "project_id", + "slug" + ], + "isUnique": true + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "projects": { + "name": "projects", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "slug": { + "name": "slug", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "data_path": { + "name": "data_path", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "is_active": { + "name": "is_active", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + } + }, + "indexes": { + "projects_slug_unique": { + "name": "projects_slug_unique", + "columns": [ + "slug" + ], + "isUnique": true + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "settings": { + "name": "settings", + "columns": { + "key": { + "name": "key", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "value": { + "name": "value", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "tags": { + "name": "tags", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "project_id": { + "name": "project_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "color": { + "name": "color", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "tags_project_name_idx": { + "name": "tags_project_name_idx", + "columns": [ + "project_id", + "name" + ], + "isUnique": true + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + } + }, + "views": {}, + "enums": {}, + "_meta": { + "schemas": {}, + "tables": {}, + "columns": {} + }, + "internal": { + "indexes": {} + } +} \ No newline at end of file diff --git a/drizzle/meta/_journal.json b/drizzle/meta/_journal.json index 63f0f84..ca0270d 100644 --- a/drizzle/meta/_journal.json +++ b/drizzle/meta/_journal.json @@ -8,6 +8,13 @@ "when": 1771081481654, "tag": "0000_initial", "breakpoints": true + }, + { + "idx": 1, + "version": "6", + "when": 1771088786493, + "tag": "0001_narrow_black_bolt", + "breakpoints": true } ] } \ No newline at end of file diff --git a/src/main/database/schema.ts b/src/main/database/schema.ts index 2438ed5..6a8e8b5 100644 --- a/src/main/database/schema.ts +++ b/src/main/database/schema.ts @@ -30,8 +30,6 @@ export const posts = sqliteTable('posts', { updatedAt: integer('updated_at', { mode: 'timestamp' }).notNull(), publishedAt: integer('published_at', { mode: 'timestamp' }), filePath: text('file_path').notNull().default(''), // Empty for never-published drafts - syncStatus: text('sync_status', { enum: ['pending', 'synced', 'conflict'] }).notNull().default('pending'), - syncedAt: integer('synced_at', { mode: 'timestamp' }), checksum: text('checksum'), tags: text('tags'), // JSON array stored as text categories: text('categories'), // JSON array stored as text @@ -62,24 +60,10 @@ export const media = sqliteTable('media', { sidecarPath: text('sidecar_path').notNull(), createdAt: integer('created_at', { mode: 'timestamp' }).notNull(), updatedAt: integer('updated_at', { mode: 'timestamp' }).notNull(), - syncStatus: text('sync_status', { enum: ['pending', 'synced', 'conflict'] }).notNull().default('pending'), - syncedAt: integer('synced_at', { mode: 'timestamp' }), checksum: text('checksum'), tags: text('tags'), // JSON array stored as text }); -// Sync log - tracks sync operations -export const syncLog = sqliteTable('sync_log', { - id: text('id').primaryKey(), - entityType: text('entity_type', { enum: ['post', 'media'] }).notNull(), - entityId: text('entity_id').notNull(), - operation: text('operation', { enum: ['create', 'update', 'delete'] }).notNull(), - status: text('status', { enum: ['pending', 'completed', 'failed'] }).notNull().default('pending'), - timestamp: integer('timestamp', { mode: 'timestamp' }).notNull(), - errorMessage: text('error_message'), - retryCount: integer('retry_count').notNull().default(0), -}); - // App settings - stores application configuration export const settings = sqliteTable('settings', { key: text('key').primaryKey(), @@ -162,8 +146,6 @@ export type Post = typeof posts.$inferSelect; export type NewPost = typeof posts.$inferInsert; export type Media = typeof media.$inferSelect; export type NewMedia = typeof media.$inferInsert; -export type SyncLogEntry = typeof syncLog.$inferSelect; -export type NewSyncLogEntry = typeof syncLog.$inferInsert; export type Setting = typeof settings.$inferSelect; export type NewSetting = typeof settings.$inferInsert; export type PostLink = typeof postLinks.$inferSelect; diff --git a/src/main/engine/MediaEngine.ts b/src/main/engine/MediaEngine.ts index 8f6dc89..657c991 100644 --- a/src/main/engine/MediaEngine.ts +++ b/src/main/engine/MediaEngine.ts @@ -520,7 +520,6 @@ export class MediaEngine extends EventEmitter { sidecarPath, createdAt: mediaData.createdAt, updatedAt: mediaData.updatedAt, - syncStatus: 'pending', checksum, tags: JSON.stringify(mediaData.tags), }; @@ -566,7 +565,6 @@ export class MediaEngine extends EventEmitter { alt: updated.alt, caption: updated.caption, updatedAt: updated.updatedAt, - syncStatus: 'pending', tags: JSON.stringify(updated.tags), }) .where(eq(media.id, id)); @@ -933,7 +931,6 @@ export class MediaEngine extends EventEmitter { sidecarPath, createdAt: new Date(metadata.createdAt), updatedAt: new Date(metadata.updatedAt), - syncStatus: 'pending', checksum, tags: JSON.stringify(metadata.tags), }); diff --git a/src/main/engine/PostEngine.ts b/src/main/engine/PostEngine.ts index f66e62c..44c3808 100644 --- a/src/main/engine/PostEngine.ts +++ b/src/main/engine/PostEngine.ts @@ -328,7 +328,6 @@ export class PostEngine extends EventEmitter { updatedAt: post.updatedAt, publishedAt: post.publishedAt, filePath: '', - syncStatus: 'pending', checksum, tags: JSON.stringify(post.tags), categories: JSON.stringify(post.categories), @@ -404,7 +403,6 @@ export class PostEngine extends EventEmitter { author: updated.author, updatedAt: updated.updatedAt, publishedAt: updated.publishedAt, - syncStatus: 'pending', checksum, tags: JSON.stringify(updated.tags), categories: JSON.stringify(updated.categories), @@ -851,7 +849,6 @@ export class PostEngine extends EventEmitter { updatedAt: published.updatedAt, publishedAt: published.publishedAt, filePath: newFilePath, - syncStatus: 'pending', checksum, tags: JSON.stringify(published.tags), categories: JSON.stringify(published.categories), @@ -1105,7 +1102,6 @@ export class PostEngine extends EventEmitter { updatedAt: postData.updatedAt, publishedAt: postData.publishedAt || postData.updatedAt, filePath, - syncStatus: 'pending', checksum, tags: JSON.stringify(postData.tags), categories: JSON.stringify(postData.categories), diff --git a/src/main/engine/SyncEngine.ts b/src/main/engine/SyncEngine.ts deleted file mode 100644 index d0eaeb5..0000000 --- a/src/main/engine/SyncEngine.ts +++ /dev/null @@ -1,168 +0,0 @@ -import { EventEmitter } from 'events'; -import { v4 as uuidv4 } from 'uuid'; -import { eq } from 'drizzle-orm'; -import { getDatabase } from '../database'; -import { syncLog, posts, media, NewSyncLogEntry } from '../database/schema'; - -export type SyncDirection = 'push' | 'pull' | 'bidirectional'; -export type SyncStatus = 'idle' | 'syncing' | 'error'; - -export interface SyncConfig { - autoSync: boolean; - syncInterval: number; // in minutes -} - -export interface SyncResult { - success: boolean; - pushed: number; - pulled: number; - conflicts: number; - errors: string[]; -} - -export class SyncEngine extends EventEmitter { - private syncStatus: SyncStatus = 'idle'; - private syncConfig: SyncConfig | null = null; - private syncIntervalId: NodeJS.Timeout | null = null; - - constructor() { - super(); - } - - getSyncStatus(): SyncStatus { - return this.syncStatus; - } - - /** - * Check if sync is configured. - * Currently returns false as cloud sync is not implemented. - */ - isConfigured(): boolean { - return false; - } - - async configure(config: SyncConfig): Promise { - this.syncConfig = config; - - // Stop existing auto-sync - if (this.syncIntervalId) { - clearInterval(this.syncIntervalId); - this.syncIntervalId = null; - } - - // Auto-sync is disabled as cloud sync is not implemented - this.emit('configured', config); - } - - private async logSyncOperation( - entityId: string, - entityType: 'post' | 'media', - operation: 'create' | 'update' | 'delete', - status: 'pending' | 'completed' | 'failed', - errorMessage?: string - ): Promise { - const db = getDatabase().getLocal(); - - const logEntry: NewSyncLogEntry = { - id: uuidv4(), - entityType, - entityId, - operation, - status, - timestamp: new Date(), - errorMessage, - retryCount: 0, - }; - - await db.insert(syncLog).values(logEntry); - } - - async getPendingChangesCount(): Promise<{ posts: number; media: number }> { - const db = getDatabase().getLocal(); - - const pendingPosts = await db - .select() - .from(posts) - .where(eq(posts.syncStatus, 'pending')) - .all(); - - const pendingMedia = await db - .select() - .from(media) - .where(eq(media.syncStatus, 'pending')) - .all(); - - return { - posts: pendingPosts.length, - media: pendingMedia.length, - }; - } - - async getSyncLog(limit = 50): Promise> { - const db = getDatabase().getLocal(); - - const logs = await db - .select() - .from(syncLog) - .orderBy(syncLog.timestamp) - .limit(limit) - .all(); - - return logs.map(log => ({ - id: log.id, - entityType: log.entityType, - entityId: log.entityId, - operation: log.operation, - status: log.status, - timestamp: log.timestamp, - errorMessage: log.errorMessage || undefined, - })); - } - - stopAutoSync(): void { - if (this.syncIntervalId) { - clearInterval(this.syncIntervalId); - this.syncIntervalId = null; - } - this.emit('autoSyncStopped'); - } - - /** - * Sync alias for fullSync for backward compatibility - */ - async sync(direction: SyncDirection = 'bidirectional'): Promise { - return this.fullSync(direction); - } - - /** - * Full sync is not currently implemented. - * Returns a result indicating sync is not configured. - */ - async fullSync(_direction: SyncDirection = 'bidirectional'): Promise { - return { - success: false, - pushed: 0, - pulled: 0, - conflicts: 0, - errors: ['Cloud sync not configured'], - }; - } -} - -// Singleton instance -let syncEngine: SyncEngine | null = null; - -export function getSyncEngine(): SyncEngine { - if (!syncEngine) { - syncEngine = new SyncEngine(); - } - return syncEngine; -} diff --git a/src/main/engine/index.ts b/src/main/engine/index.ts index 3750341..495e8c6 100644 --- a/src/main/engine/index.ts +++ b/src/main/engine/index.ts @@ -2,7 +2,6 @@ export { TaskManager, taskManager, type Task, type TaskProgress, type TaskStatus export { PostEngine, getPostEngine, type PostData, type PostFilter, type SearchResult, type PaginatedResult, type PaginationOptions } from './PostEngine'; export { MediaEngine, getMediaEngine, type MediaData } from './MediaEngine'; export { PostMediaEngine, getPostMediaEngine, postMediaEngine, type PostMediaLinkData } from './PostMediaEngine'; -export { SyncEngine, getSyncEngine, type SyncConfig, type SyncResult, type SyncDirection, type SyncStatus } from './SyncEngine'; export { ProjectEngine, getProjectEngine, type ProjectData } from './ProjectEngine'; export { MetaEngine, getMetaEngine, type ProjectMetadata, DEFAULT_CATEGORIES } from './MetaEngine'; export { diff --git a/src/main/ipc/handlers.ts b/src/main/ipc/handlers.ts index 87f5ad6..194dcfe 100644 --- a/src/main/ipc/handlers.ts +++ b/src/main/ipc/handlers.ts @@ -4,7 +4,6 @@ import * as fsPromises from 'fs/promises'; import { eq } from 'drizzle-orm'; import { getPostEngine, PostData, PostFilter, PaginationOptions } from '../engine/PostEngine'; import { getMediaEngine, MediaData } from '../engine/MediaEngine'; -import { getSyncEngine, SyncConfig, SyncDirection } from '../engine/SyncEngine'; import { getProjectEngine, ProjectData } from '../engine/ProjectEngine'; import { getMetaEngine } from '../engine/MetaEngine'; import { getTagEngine } from '../engine/TagEngine'; @@ -432,43 +431,6 @@ export function registerIpcHandlers(): void { return engine.regenerateMissingThumbnails(); }); - // ============ Sync Handlers ============ - - safeHandle('sync:configure', async (_, config: SyncConfig) => { - const engine = getSyncEngine(); - return engine.configure(config); - }); - - safeHandle('sync:start', async (_, direction: SyncDirection = 'bidirectional') => { - const engine = getSyncEngine(); - return engine.fullSync(direction); - }); - - safeHandle('sync:getStatus', async () => { - const engine = getSyncEngine(); - return engine.getSyncStatus(); - }); - - safeHandle('sync:isConfigured', async () => { - const engine = getSyncEngine(); - return engine.isConfigured(); - }); - - safeHandle('sync:getPendingCount', async () => { - const engine = getSyncEngine(); - return engine.getPendingChangesCount(); - }); - - safeHandle('sync:getLog', async (_, limit?: number) => { - const engine = getSyncEngine(); - return engine.getSyncLog(limit); - }); - - safeHandle('sync:stopAutoSync', async () => { - const engine = getSyncEngine(); - return engine.stopAutoSync(); - }); - // ============ Task Handlers ============ safeHandle('tasks:getAll', async () => { @@ -880,7 +842,6 @@ export function registerIpcHandlers(): void { // Forward engine events to renderer const postEngine = getPostEngine(); const mediaEngine = getMediaEngine(); - const syncEngine = getSyncEngine(); const projectEngine = getProjectEngine(); const metaEngine = getMetaEngine(); const tagEngine = getTagEngine(); @@ -926,10 +887,6 @@ export function registerIpcHandlers(): void { postMediaEngine.on('mediaReordered', forwardEvent('postMedia:reordered')); postMediaEngine.on('rebuilt', forwardEvent('postMedia:rebuilt')); - syncEngine.on('syncStarted', forwardEvent('sync:started')); - syncEngine.on('syncCompleted', forwardEvent('sync:completed')); - syncEngine.on('syncFailed', forwardEvent('sync:failed')); - taskManager.on('taskCreated', forwardEvent('task:created')); taskManager.on('taskStarted', forwardEvent('task:started')); taskManager.on('taskProgress', forwardEvent('task:progress')); diff --git a/src/main/main.ts b/src/main/main.ts index 27b2390..6198a2e 100644 --- a/src/main/main.ts +++ b/src/main/main.ts @@ -255,43 +255,6 @@ function createApplicationMenu(): Menu { }, ], }, - { - label: 'Sync', - submenu: [ - { - label: 'Sync Now', - accelerator: 'CmdOrCtrl+Shift+S', - click: () => { - mainWindow?.webContents.send('menu:syncNow'); - }, - }, - { - label: 'Push Changes', - click: () => { - mainWindow?.webContents.send('menu:pushChanges'); - }, - }, - { - label: 'Pull Changes', - click: () => { - mainWindow?.webContents.send('menu:pullChanges'); - }, - }, - { type: 'separator' }, - { - label: 'Configure Sync...', - click: () => { - mainWindow?.webContents.send('menu:configureSync'); - }, - }, - { - label: 'View Sync Log', - click: () => { - mainWindow?.webContents.send('menu:viewSyncLog'); - }, - }, - ], - }, { label: 'Help', submenu: [ diff --git a/src/main/preload.ts b/src/main/preload.ts index 6f6cd9f..e281bd0 100644 --- a/src/main/preload.ts +++ b/src/main/preload.ts @@ -78,17 +78,6 @@ contextBridge.exposeInMainWorld('electronAPI', { rebuild: () => ipcRenderer.invoke('postMedia:rebuild'), }, - // Sync - sync: { - configure: (config: unknown) => ipcRenderer.invoke('sync:configure', config), - start: (direction?: string) => ipcRenderer.invoke('sync:start', direction), - getStatus: () => ipcRenderer.invoke('sync:getStatus'), - isConfigured: () => ipcRenderer.invoke('sync:isConfigured'), - getPendingCount: () => ipcRenderer.invoke('sync:getPendingCount'), - getLog: (limit?: number) => ipcRenderer.invoke('sync:getLog', limit), - stopAutoSync: () => ipcRenderer.invoke('sync:stopAutoSync'), - }, - // Tasks tasks: { getAll: () => ipcRenderer.invoke('tasks:getAll'), @@ -273,15 +262,6 @@ export interface ElectronAPI { getAll: () => Promise; rebuildFromFiles: () => Promise; }; - sync: { - configure: (config: unknown) => Promise; - start: (direction?: string) => Promise; - getStatus: () => Promise; - isConfigured: () => Promise; - getPendingCount: () => Promise<{ posts: number; media: number }>; - getLog: (limit?: number) => Promise; - stopAutoSync: () => Promise; - }; dropbox: { configure: (config: unknown) => Promise; isConfigured: () => Promise; diff --git a/src/renderer/App.tsx b/src/renderer/App.tsx index 3a9deb8..0f2d023 100644 --- a/src/renderer/App.tsx +++ b/src/renderer/App.tsx @@ -29,9 +29,6 @@ const App: React.FC = () => { removeMedia, setTasks, updateTask, - setSyncStatus, - setSyncConfigured, - setPendingChanges, setLoading, toggleSidebar, togglePanel, @@ -74,16 +71,6 @@ const App: React.FC = () => { } } - // Check sync status - const syncConfigured = await window.electronAPI?.sync.isConfigured(); - setSyncConfigured(syncConfigured || false); - - // Get pending changes count - const pending = await window.electronAPI?.sync.getPendingCount(); - if (pending) { - setPendingChanges(pending); - } - // Load tasks const tasks = await window.electronAPI?.tasks.getAll(); if (tasks) { @@ -162,36 +149,6 @@ const App: React.FC = () => { }) || (() => {}) ); - // Sync events - unsubscribers.push( - window.electronAPI?.on('sync:started', () => { - setSyncStatus('syncing'); - showToast.loading('Syncing...'); - }) || (() => {}) - ); - - unsubscribers.push( - window.electronAPI?.on('sync:completed', async () => { - setSyncStatus('idle'); - showToast.dismiss(); - showToast.success('Sync completed'); - const pending = await window.electronAPI?.sync.getPendingCount(); - if (pending) { - setPendingChanges(pending); - } - }) || (() => {}) - ); - - unsubscribers.push( - window.electronAPI?.on('sync:failed', (errorMsg: unknown) => { - setSyncStatus('error'); - showToast.dismiss(); - const message = typeof errorMsg === 'string' && errorMsg ? errorMsg : 'Unknown error'; - showToast.error(`Sync failed: ${message}`); - console.error('Sync failed:', message); - }) || (() => {}) - ); - // Task events unsubscribers.push( window.electronAPI?.on('task:started', (task: unknown) => { @@ -267,30 +224,6 @@ const App: React.FC = () => { }) || (() => {}) ); - unsubscribers.push( - window.electronAPI?.on('menu:syncNow', () => { - window.electronAPI?.sync.start('bidirectional'); - }) || (() => {}) - ); - - unsubscribers.push( - window.electronAPI?.on('menu:pushChanges', () => { - window.electronAPI?.sync.start('push'); - }) || (() => {}) - ); - - unsubscribers.push( - window.electronAPI?.on('menu:pullChanges', () => { - window.electronAPI?.sync.start('pull'); - }) || (() => {}) - ); - - unsubscribers.push( - window.electronAPI?.on('menu:configureSync', () => { - openTab({ type: 'settings', id: 'settings', isTransient: false }); - }) || (() => {}) - ); - // Rebuild events - clear store on start, reload on complete unsubscribers.push( window.electronAPI?.on('posts:rebuildStarted', () => { diff --git a/src/renderer/components/ActivityBar/ActivityBar.tsx b/src/renderer/components/ActivityBar/ActivityBar.tsx index 3b9ef04..e5b6263 100644 --- a/src/renderer/components/ActivityBar/ActivityBar.tsx +++ b/src/renderer/components/ActivityBar/ActivityBar.tsx @@ -43,16 +43,8 @@ const ImportIcon = () => ( ); -const SyncIcon = () => ( - - - -); - export const ActivityBar: React.FC = () => { - const { activeView, setActiveView, sidebarVisible, toggleSidebar, syncStatus, pendingChanges, openTab, tabs, activeTabId } = useAppStore(); - - const totalPending = pendingChanges.posts + pendingChanges.media; + const { activeView, setActiveView, sidebarVisible, toggleSidebar, openTab, tabs, activeTabId } = useAppStore(); // Check if settings tab is currently active const isSettingsTabActive = tabs.some(t => t.type === 'settings' && t.id === activeTabId); @@ -157,16 +149,6 @@ export const ActivityBar: React.FC = () => {
-