From 291d8cc968cee9fbead6d38f1ef029634c9d4773 Mon Sep 17 00:00:00 2001 From: "IGNY8 VPS (Salman)" Date: Wed, 3 Dec 2025 08:32:07 +0000 Subject: [PATCH] fixees --- .../igny8_core/business/automation/models.py | 2 +- .../automation/services/automation_service.py | 22 +- .../igny8_core/business/automation/views.py | 2 +- backend/igny8_core/settings.py | 1 + .../src/components/Automation/ActivityLog.tsx | 18 +- .../src/components/Automation/RunHistory.tsx | 65 +++-- .../src/pages/Automation/AutomationPage.tsx | 253 ++++++++++-------- 7 files changed, 207 insertions(+), 156 deletions(-) diff --git a/backend/igny8_core/business/automation/models.py b/backend/igny8_core/business/automation/models.py index dcd4ac03..3da47629 100644 --- a/backend/igny8_core/business/automation/models.py +++ b/backend/igny8_core/business/automation/models.py @@ -4,7 +4,7 @@ Tracks automation runs and configuration """ from django.db import models from django.utils import timezone -from igny8_core.modules.system.models import Account, Site +from igny8_core.auth.models import Account, Site class AutomationConfig(models.Model): diff --git a/backend/igny8_core/business/automation/services/automation_service.py b/backend/igny8_core/business/automation/services/automation_service.py index ffbb1507..bab1fc83 100644 --- a/backend/igny8_core/business/automation/services/automation_service.py +++ b/backend/igny8_core/business/automation/services/automation_service.py @@ -13,17 +13,17 @@ from celery.result import AsyncResult from igny8_core.business.automation.models import AutomationRun, AutomationConfig from igny8_core.business.automation.services.automation_logger import AutomationLogger -from igny8_core.modules.system.models import Account, Site +from igny8_core.auth.models import Account, Site from igny8_core.modules.planner.models import Keywords, Clusters, ContentIdeas from igny8_core.modules.writer.models import Tasks, Content, Images -from igny8_core.business.content.models import AIUsageLog +from igny8_core.ai.models import AITaskLog # AI Functions -from igny8_core.ai.functions.auto_cluster import AutoCluster -from igny8_core.ai.functions.generate_ideas import GenerateIdeas -from igny8_core.ai.functions.generate_content import GenerateContent +from igny8_core.ai.functions.auto_cluster import AutoClusterFunction +from igny8_core.ai.functions.generate_ideas import GenerateIdeasFunction +from igny8_core.ai.functions.generate_content import GenerateContentFunction from igny8_core.ai.functions.generate_image_prompts import GenerateImagePromptsFunction -from igny8_core.ai.functions.generate_images import GenerateImages +from igny8_core.ai.functions.generate_images import GenerateImagesFunction logger = logging.getLogger(__name__) @@ -165,7 +165,7 @@ class AutomationService: ) # Call AI function - result = AutoCluster().execute( + result = AutoClusterFunction().execute( payload={'ids': batch}, account=self.account ) @@ -259,7 +259,7 @@ class AutomationService: ) # Call AI function - result = GenerateIdeas().execute( + result = GenerateIdeasFunction().execute( payload={'ids': [cluster.id]}, account=self.account ) @@ -454,7 +454,7 @@ class AutomationService: ) # Call AI function - result = GenerateContent().execute( + result = GenerateContentFunction().execute( payload={'ids': [task.id]}, account=self.account ) @@ -642,7 +642,7 @@ class AutomationService: ) # Call AI function - result = GenerateImages().execute( + result = GenerateImagesFunction().execute( payload={'image_ids': [image.id]}, account=self.account ) @@ -809,7 +809,7 @@ class AutomationService: if not self.run: return 0 - total = AIUsageLog.objects.filter( + total = AITaskLog.objects.filter( account=self.account, created_at__gte=self.run.started_at ).aggregate(total=Count('id'))['total'] or 0 diff --git a/backend/igny8_core/business/automation/views.py b/backend/igny8_core/business/automation/views.py index e41b9217..18c0e967 100644 --- a/backend/igny8_core/business/automation/views.py +++ b/backend/igny8_core/business/automation/views.py @@ -11,7 +11,7 @@ from django.utils import timezone from igny8_core.business.automation.models import AutomationConfig, AutomationRun from igny8_core.business.automation.services import AutomationService -from igny8_core.modules.system.models import Account, Site +from igny8_core.auth.models import Account, Site class AutomationViewSet(viewsets.ViewSet): diff --git a/backend/igny8_core/settings.py b/backend/igny8_core/settings.py index 53ab939d..0650754b 100644 --- a/backend/igny8_core/settings.py +++ b/backend/igny8_core/settings.py @@ -54,6 +54,7 @@ INSTALLED_APPS = [ 'igny8_core.modules.billing.apps.BillingConfig', # 'igny8_core.modules.automation.apps.AutomationConfig', # Removed - automation module disabled # 'igny8_core.business.site_building.apps.SiteBuildingConfig', # REMOVED: SiteBuilder/Blueprint deprecated + 'igny8_core.business.automation', # AI Automation Pipeline 'igny8_core.business.optimization.apps.OptimizationConfig', 'igny8_core.business.publishing.apps.PublishingConfig', 'igny8_core.business.integration.apps.IntegrationConfig', diff --git a/frontend/src/components/Automation/ActivityLog.tsx b/frontend/src/components/Automation/ActivityLog.tsx index 58461e62..d9541d77 100644 --- a/frontend/src/components/Automation/ActivityLog.tsx +++ b/frontend/src/components/Automation/ActivityLog.tsx @@ -4,6 +4,7 @@ */ import React, { useState, useEffect } from 'react'; import { automationService } from '../../services/automationService'; +import ComponentCard from '../common/ComponentCard'; interface ActivityLogProps { runId: string; @@ -31,15 +32,17 @@ const ActivityLog: React.FC = ({ runId }) => { }; return ( -
+
-

Activity Log

- +
-
+
{logs || 'No logs available'}
-
+
); }; export default ActivityLog; +}; + +export default ActivityLog; diff --git a/frontend/src/components/Automation/RunHistory.tsx b/frontend/src/components/Automation/RunHistory.tsx index 814c00f3..a908bf67 100644 --- a/frontend/src/components/Automation/RunHistory.tsx +++ b/frontend/src/components/Automation/RunHistory.tsx @@ -4,6 +4,7 @@ */ import React, { useState, useEffect } from 'react'; import { automationService, RunHistoryItem } from '../../services/automationService'; +import ComponentCard from '../common/ComponentCard'; interface RunHistoryProps { siteId: number; @@ -31,56 +32,61 @@ const RunHistory: React.FC = ({ siteId }) => { const getStatusBadge = (status: string) => { const colors: Record = { - completed: 'bg-green-100 text-green-800', - running: 'bg-blue-100 text-blue-800', - paused: 'bg-yellow-100 text-yellow-800', - failed: 'bg-red-100 text-red-800', + completed: 'bg-green-100 text-green-800 dark:bg-green-900/30 dark:text-green-400', + running: 'bg-blue-100 text-blue-800 dark:bg-blue-900/30 dark:text-blue-400', + paused: 'bg-yellow-100 text-yellow-800 dark:bg-yellow-900/30 dark:text-yellow-400', + failed: 'bg-red-100 text-red-800 dark:bg-red-900/30 dark:text-red-400', }; - return colors[status] || 'bg-gray-100 text-gray-800'; + return colors[status] || 'bg-gray-100 text-gray-800 dark:bg-gray-700 dark:text-gray-300'; }; if (loading) { - return
Loading history...
; + return ( + +
Loading history...
+
+ ); } return ( -
-

Run History

- + {history.length === 0 ? ( -
No automation runs yet
+
No automation runs yet
) : ( -
+
- + - - - - - - - - + {history.map((run) => ( - - + + - - + - - - + + ))}
+ Run ID + Status + Trigger + Started + Completed + Credits Used + Stage
{run.run_id.slice(0, 8)}...
{run.run_id.slice(0, 8)}... = ({ siteId }) => { {run.status} {run.trigger_type} + {run.trigger_type} {new Date(run.started_at).toLocaleString()} + {run.completed_at ? new Date(run.completed_at).toLocaleString() : '-'} {run.total_credits_used}{run.current_stage}/7{run.total_credits_used}{run.current_stage}/7
)} -
+
); }; export default RunHistory; +}; + +export default RunHistory; diff --git a/frontend/src/pages/Automation/AutomationPage.tsx b/frontend/src/pages/Automation/AutomationPage.tsx index cda4986c..df78ace7 100644 --- a/frontend/src/pages/Automation/AutomationPage.tsx +++ b/frontend/src/pages/Automation/AutomationPage.tsx @@ -10,6 +10,11 @@ import StageCard from '../../components/Automation/StageCard'; import ActivityLog from '../../components/Automation/ActivityLog'; import ConfigModal from '../../components/Automation/ConfigModal'; import RunHistory from '../../components/Automation/RunHistory'; +import PageMeta from '../../components/common/PageMeta'; +import ComponentCard from '../../components/common/ComponentCard'; +import DebugSiteSelector from '../../components/common/DebugSiteSelector'; +import Button from '../../components/ui/button/Button'; +import { BoltIcon } from '../../icons'; const STAGE_NAMES = [ 'Keywords → Clusters', @@ -23,11 +28,12 @@ const STAGE_NAMES = [ const AutomationPage: React.FC = () => { const { activeSite } = useSiteStore(); - const { showToast } = useToast(); + const toast = useToast(); const [config, setConfig] = useState(null); const [currentRun, setCurrentRun] = useState(null); const [showConfigModal, setShowConfigModal] = useState(false); const [loading, setLoading] = useState(true); + const [lastUpdated, setLastUpdated] = useState(new Date()); const [estimate, setEstimate] = useState<{ estimated_credits: number; current_balance: number; sufficient: boolean } | null>(null); // Poll for current run updates @@ -59,8 +65,9 @@ const AutomationPage: React.FC = () => { setConfig(configData); setCurrentRun(runData.run); setEstimate(estimateData); + setLastUpdated(new Date()); } catch (error: any) { - showToast('Failed to load automation data', 'error'); + toast.error('Failed to load automation data'); console.error(error); } finally { setLoading(false); @@ -83,16 +90,16 @@ const AutomationPage: React.FC = () => { // Check credit balance if (estimate && !estimate.sufficient) { - showToast(`Insufficient credits. Need ~${estimate.estimated_credits}, you have ${estimate.current_balance}`, 'error'); + toast.error(`Insufficient credits. Need ~${estimate.estimated_credits}, you have ${estimate.current_balance}`); return; } try { const result = await automationService.runNow(activeSite.id); - showToast('Automation started', 'success'); + toast.success('Automation started'); loadCurrentRun(); } catch (error: any) { - showToast(error.response?.data?.error || 'Failed to start automation', 'error'); + toast.error(error.response?.data?.error || 'Failed to start automation'); } }; @@ -101,10 +108,10 @@ const AutomationPage: React.FC = () => { try { await automationService.pause(currentRun.run_id); - showToast('Automation paused', 'success'); + toast.success('Automation paused'); loadCurrentRun(); } catch (error) { - showToast('Failed to pause automation', 'error'); + toast.error('Failed to pause automation'); } }; @@ -113,10 +120,10 @@ const AutomationPage: React.FC = () => { try { await automationService.resume(currentRun.run_id); - showToast('Automation resumed', 'success'); + toast.success('Automation resumed'); loadCurrentRun(); } catch (error) { - showToast('Failed to resume automation', 'error'); + toast.error('Failed to resume automation'); } }; @@ -125,150 +132,180 @@ const AutomationPage: React.FC = () => { try { await automationService.updateConfig(activeSite.id, newConfig); - showToast('Configuration saved', 'success'); + toast.success('Configuration saved'); setShowConfigModal(false); loadData(); } catch (error) { - showToast('Failed to save configuration', 'error'); + toast.error('Failed to save configuration'); } }; if (loading) { return ( -
-
Loading automation...
+
+
Loading automation...
); } if (!activeSite) { return ( -
-
Please select a site
+
+
Please select a site to view automation
); } return ( -
- {/* Header */} -
-
-
-

AI Automation Pipeline

-

- Automated content creation from keywords to published articles -

+ <> + + +
+ {/* Page Header with Site Selector (no sector) */} +
+
+
+
+ +
+

AI Automation Pipeline

+
+ {activeSite && ( +
+ {lastUpdated && ( +

+ Last updated: {lastUpdated.toLocaleTimeString()} +

+ )} + +

+ Site: {activeSite.name} +

+
+ )}
-
- - {currentRun?.status === 'running' && ( - - )} - {currentRun?.status === 'paused' && ( - - )} - {!currentRun && ( - - )} + +
+
- {/* Status Bar */} + {/* Schedule Status Card */} {config && ( -
-
+ +
-
Status
-
+
Status
+
{config.is_enabled ? ( - Enabled + ● Enabled ) : ( - Disabled + ○ Disabled )}
-
Schedule
-
+
Schedule
+
{config.frequency} at {config.scheduled_time}
-
Last Run
-
+
Last Run
+
{config.last_run_at ? new Date(config.last_run_at).toLocaleString() : 'Never'}
-
Estimated Credits
-
+
Estimated Credits
+
{estimate?.estimated_credits || 0} credits {estimate && !estimate.sufficient && ( - (Insufficient) + (Insufficient) )}
-
- )} -
- {/* Current Run Status */} - {currentRun && ( -
-
-

- Current Run: {currentRun.run_id} -

-
+
+ + {currentRun?.status === 'running' && ( + + )} + {currentRun?.status === 'paused' && ( + + )} + {!currentRun && ( + + )} +
+ + )} + + {/* Current Run Status */} + {currentRun && ( + +
-
Status
-
{currentRun.status}
+
Status
+
{currentRun.status}
-
Current Stage
-
+
Current Stage
+
Stage {currentRun.current_stage}: {STAGE_NAMES[currentRun.current_stage - 1]}
-
Started
-
+
Started
+
{new Date(currentRun.started_at).toLocaleString()}
-
Credits Used
-
{currentRun.total_credits_used}
+
Credits Used
+
{currentRun.total_credits_used}
{/* Stage Progress */} -
+
{STAGE_NAMES.map((name, index) => ( { /> ))}
-
-
- )} + + )} - {/* Activity Log */} - {currentRun && ( -
+ {/* Activity Log */} + {currentRun && ( -
- )} + )} - {/* Run History */} - + {/* Run History */} + - {/* Config Modal */} - {showConfigModal && config && ( - setShowConfigModal(false)} - /> - )} -
+ {/* Config Modal */} + {showConfigModal && config && ( + setShowConfigModal(false)} + /> + )} +
+ ); };