chore: removed sync engine since we go for filesystem based syncing
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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),
|
||||
});
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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<void> {
|
||||
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<void> {
|
||||
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<Array<{
|
||||
id: string;
|
||||
entityType: string;
|
||||
entityId: string;
|
||||
operation: string;
|
||||
status: string;
|
||||
timestamp: Date;
|
||||
errorMessage?: string;
|
||||
}>> {
|
||||
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<SyncResult> {
|
||||
return this.fullSync(direction);
|
||||
}
|
||||
|
||||
/**
|
||||
* Full sync is not currently implemented.
|
||||
* Returns a result indicating sync is not configured.
|
||||
*/
|
||||
async fullSync(_direction: SyncDirection = 'bidirectional'): Promise<SyncResult> {
|
||||
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;
|
||||
}
|
||||
@@ -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 {
|
||||
|
||||
@@ -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'));
|
||||
|
||||
@@ -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: [
|
||||
|
||||
@@ -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<unknown[]>;
|
||||
rebuildFromFiles: () => Promise<void>;
|
||||
};
|
||||
sync: {
|
||||
configure: (config: unknown) => Promise<void>;
|
||||
start: (direction?: string) => Promise<unknown>;
|
||||
getStatus: () => Promise<string>;
|
||||
isConfigured: () => Promise<boolean>;
|
||||
getPendingCount: () => Promise<{ posts: number; media: number }>;
|
||||
getLog: (limit?: number) => Promise<unknown[]>;
|
||||
stopAutoSync: () => Promise<void>;
|
||||
};
|
||||
dropbox: {
|
||||
configure: (config: unknown) => Promise<void>;
|
||||
isConfigured: () => Promise<boolean>;
|
||||
|
||||
@@ -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', () => {
|
||||
|
||||
@@ -43,16 +43,8 @@ const ImportIcon = () => (
|
||||
</svg>
|
||||
);
|
||||
|
||||
const SyncIcon = () => (
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="currentColor">
|
||||
<path d="M12 4V1L8 5l4 4V6c3.31 0 6 2.69 6 6 0 1.01-.25 1.97-.7 2.8l1.46 1.46C19.54 15.03 20 13.57 20 12c0-4.42-3.58-8-8-8zm0 14c-3.31 0-6-2.69-6-6 0-1.01.25-1.97.7-2.8L5.24 7.74C4.46 8.97 4 10.43 4 12c0 4.42 3.58 8 8 8v3l4-4-4-4v3z"/>
|
||||
</svg>
|
||||
);
|
||||
|
||||
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 = () => {
|
||||
</div>
|
||||
|
||||
<div className="activity-bar-bottom">
|
||||
<button
|
||||
className={`activity-bar-item ${syncStatus === 'syncing' ? 'syncing' : ''}`}
|
||||
onClick={() => window.electronAPI?.sync.start()}
|
||||
title={`Sync (${totalPending} pending)`}
|
||||
>
|
||||
<SyncIcon />
|
||||
{totalPending > 0 && (
|
||||
<span className="activity-bar-badge">{totalPending}</span>
|
||||
)}
|
||||
</button>
|
||||
<button
|
||||
className={`activity-bar-item ${isSettingsActive ? 'active' : ''}`}
|
||||
onClick={handleSettingsClick}
|
||||
|
||||
@@ -5,9 +5,6 @@ import './StatusBar.css';
|
||||
|
||||
export const StatusBar: React.FC = () => {
|
||||
const {
|
||||
syncStatus,
|
||||
syncConfigured,
|
||||
pendingChanges,
|
||||
media,
|
||||
tasks,
|
||||
selectedPostId,
|
||||
@@ -28,7 +25,6 @@ export const StatusBar: React.FC = () => {
|
||||
}, [selectedPostId]);
|
||||
|
||||
const runningTasks = tasks.filter(t => t.status === 'running');
|
||||
const totalPending = pendingChanges.posts + pendingChanges.media;
|
||||
|
||||
return (
|
||||
<div className="status-bar">
|
||||
@@ -36,20 +32,6 @@ export const StatusBar: React.FC = () => {
|
||||
{/* Project Selector */}
|
||||
<ProjectSelector />
|
||||
|
||||
{/* Sync Status */}
|
||||
<div className={`status-bar-item ${!syncConfigured ? 'warning' : ''}`}>
|
||||
<span className={`sync-indicator ${syncStatus}`} />
|
||||
{!syncConfigured ? (
|
||||
<span>Sync not configured</span>
|
||||
) : syncStatus === 'syncing' ? (
|
||||
<span>Syncing...</span>
|
||||
) : totalPending > 0 ? (
|
||||
<span>{totalPending} pending</span>
|
||||
) : (
|
||||
<span>Synced</span>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Running Tasks */}
|
||||
{runningTasks.length > 0 && (
|
||||
<div className="status-bar-item">
|
||||
|
||||
@@ -117,11 +117,6 @@ interface AppState {
|
||||
|
||||
// Confirm delete modal
|
||||
confirmDeleteModal: ConfirmDeleteDetails | null;
|
||||
|
||||
// Sync
|
||||
syncStatus: 'idle' | 'syncing' | 'error';
|
||||
syncConfigured: boolean;
|
||||
pendingChanges: { posts: number; media: number };
|
||||
|
||||
// Loading states
|
||||
isLoading: boolean;
|
||||
@@ -178,10 +173,7 @@ interface AppState {
|
||||
setTasks: (tasks: TaskProgress[]) => void;
|
||||
updateTask: (taskId: string, task: Partial<TaskProgress>) => void;
|
||||
|
||||
setSyncStatus: (status: 'idle' | 'syncing' | 'error') => void;
|
||||
setSyncConfigured: (configured: boolean) => void;
|
||||
setPendingChanges: (changes: { posts: number; media: number }) => void;
|
||||
|
||||
// Loading Actions
|
||||
setLoading: (loading: boolean) => void;
|
||||
setError: (error: string | null) => void;
|
||||
}
|
||||
@@ -222,11 +214,6 @@ export const useAppStore = create<AppState>()(
|
||||
|
||||
// Confirm delete modal
|
||||
confirmDeleteModal: null,
|
||||
|
||||
// Initial Sync State
|
||||
syncStatus: 'idle',
|
||||
syncConfigured: false,
|
||||
pendingChanges: { posts: 0, media: 0 },
|
||||
|
||||
// Initial Loading State
|
||||
isLoading: false,
|
||||
@@ -397,11 +384,6 @@ export const useAppStore = create<AppState>()(
|
||||
return { tasks: [...state.tasks, { taskId, status: 'running', progress: 0, message: '', startTime: new Date().toISOString(), ...task } as TaskProgress] };
|
||||
}),
|
||||
|
||||
// Sync Actions
|
||||
setSyncStatus: (syncStatus) => set({ syncStatus }),
|
||||
setSyncConfigured: (syncConfigured) => set({ syncConfigured }),
|
||||
setPendingChanges: (pendingChanges) => set({ pendingChanges }),
|
||||
|
||||
// Loading Actions
|
||||
setLoading: (isLoading) => set({ isLoading }),
|
||||
setError: (error) => set({ error }),
|
||||
|
||||
Reference in New Issue
Block a user