fixes
This commit is contained in:
@@ -4,6 +4,8 @@
|
||||
*/
|
||||
import React, { useState } from 'react';
|
||||
import { AutomationConfig } from '../../services/automationService';
|
||||
import { Modal } from '../ui/modal';
|
||||
import Button from '../ui/button/Button';
|
||||
|
||||
interface ConfigModalProps {
|
||||
config: AutomationConfig;
|
||||
@@ -28,14 +30,24 @@ const ConfigModal: React.FC<ConfigModalProps> = ({ config, onSave, onCancel }) =
|
||||
|
||||
const handleSubmit = (e: React.FormEvent) => {
|
||||
e.preventDefault();
|
||||
onSave(formData);
|
||||
// Ensure delays are included in the save
|
||||
const dataToSave = {
|
||||
...formData,
|
||||
within_stage_delay: formData.within_stage_delay || 3,
|
||||
between_stage_delay: formData.between_stage_delay || 5,
|
||||
};
|
||||
console.log('Saving config with delays:', dataToSave);
|
||||
onSave(dataToSave);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50">
|
||||
<div className="bg-white rounded-lg p-6 max-w-2xl w-full max-h-screen overflow-y-auto">
|
||||
<h2 className="text-2xl font-bold mb-4">Automation Configuration</h2>
|
||||
|
||||
<Modal
|
||||
isOpen={true}
|
||||
onClose={onCancel}
|
||||
className="max-w-4xl p-8"
|
||||
>
|
||||
<h2 className="text-2xl font-bold mb-6">Automation Configuration</h2>
|
||||
<div className="max-h-[70vh] overflow-y-auto pr-2">{/* Added pr-2 for scrollbar padding */}
|
||||
<form onSubmit={handleSubmit}>
|
||||
{/* Enable/Disable */}
|
||||
<div className="mb-4">
|
||||
@@ -270,23 +282,23 @@ const ConfigModal: React.FC<ConfigModalProps> = ({ config, onSave, onCancel }) =
|
||||
|
||||
{/* Buttons */}
|
||||
<div className="flex justify-end gap-2 mt-6">
|
||||
<button
|
||||
<Button
|
||||
type="button"
|
||||
onClick={onCancel}
|
||||
className="px-4 py-2 bg-gray-200 text-gray-800 rounded hover:bg-gray-300"
|
||||
variant="secondary"
|
||||
>
|
||||
Cancel
|
||||
</button>
|
||||
<button
|
||||
</Button>
|
||||
<Button
|
||||
type="submit"
|
||||
className="px-4 py-2 bg-blue-500 text-white rounded hover:bg-blue-600"
|
||||
variant="primary"
|
||||
>
|
||||
Save Configuration
|
||||
</button>
|
||||
</Button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</Modal>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -92,3 +92,5 @@ export const Modal: React.FC<ModalProps> = ({
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Modal;
|
||||
|
||||
@@ -63,7 +63,10 @@ const AutomationPage: React.FC = () => {
|
||||
|
||||
const interval = setInterval(() => {
|
||||
if (currentRun && (currentRun.status === 'running' || currentRun.status === 'paused')) {
|
||||
// When automation is running, refresh both run and metrics
|
||||
loadCurrentRun();
|
||||
loadPipelineOverview();
|
||||
loadMetrics(); // Add metrics refresh during run
|
||||
} else {
|
||||
loadPipelineOverview();
|
||||
}
|
||||
@@ -172,6 +175,66 @@ const AutomationPage: React.FC = () => {
|
||||
}
|
||||
};
|
||||
|
||||
const loadMetrics = async () => {
|
||||
if (!activeSite) return;
|
||||
try {
|
||||
const siteId = activeSite.id;
|
||||
const [
|
||||
keywordsTotalRes,
|
||||
keywordsNewRes,
|
||||
keywordsMappedRes,
|
||||
clustersTotalRes,
|
||||
clustersNewRes,
|
||||
clustersMappedRes,
|
||||
ideasTotalRes,
|
||||
ideasNewRes,
|
||||
ideasQueuedRes,
|
||||
ideasCompletedRes,
|
||||
tasksTotalRes,
|
||||
contentTotalRes,
|
||||
contentDraftRes,
|
||||
contentReviewRes,
|
||||
contentPublishedRes,
|
||||
imagesTotalRes,
|
||||
imagesPendingRes,
|
||||
] = await Promise.all([
|
||||
fetchKeywords({ page_size: 1, site_id: siteId }),
|
||||
fetchKeywords({ page_size: 1, site_id: siteId, status: 'new' }),
|
||||
fetchKeywords({ page_size: 1, site_id: siteId, status: 'mapped' }),
|
||||
fetchClusters({ page_size: 1, site_id: siteId }),
|
||||
fetchClusters({ page_size: 1, site_id: siteId, status: 'new' }),
|
||||
fetchClusters({ page_size: 1, site_id: siteId, status: 'mapped' }),
|
||||
fetchContentIdeas({ page_size: 1, site_id: siteId }),
|
||||
fetchContentIdeas({ page_size: 1, site_id: siteId, status: 'new' }),
|
||||
fetchContentIdeas({ page_size: 1, site_id: siteId, status: 'queued' }),
|
||||
fetchContentIdeas({ page_size: 1, site_id: siteId, status: 'completed' }),
|
||||
fetchTasks({ page_size: 1, site_id: siteId }),
|
||||
fetchContent({ page_size: 1, site_id: siteId }),
|
||||
fetchContent({ page_size: 1, site_id: siteId, status: 'draft' }),
|
||||
fetchContent({ page_size: 1, site_id: siteId, status: 'review' }),
|
||||
fetchContent({ page_size: 1, site_id: siteId, status: 'published' }),
|
||||
fetchContentImages({ page_size: 1, site_id: siteId }),
|
||||
fetchContentImages({ page_size: 1, site_id: siteId, status: 'pending' }),
|
||||
]);
|
||||
|
||||
setMetrics({
|
||||
keywords: { total: keywordsTotalRes.count || 0, new: keywordsNewRes.count || 0, mapped: keywordsMappedRes.count || 0 },
|
||||
clusters: { total: clustersTotalRes.count || 0, new: clustersNewRes.count || 0, mapped: clustersMappedRes.count || 0 },
|
||||
ideas: { total: ideasTotalRes.count || 0, new: ideasNewRes.count || 0, queued: ideasQueuedRes.count || 0, completed: ideasCompletedRes.count || 0 },
|
||||
tasks: { total: tasksTotalRes.count || 0 },
|
||||
content: {
|
||||
total: contentTotalRes.count || 0,
|
||||
draft: contentDraftRes.count || 0,
|
||||
review: contentReviewRes.count || 0,
|
||||
published: contentPublishedRes.count || 0,
|
||||
},
|
||||
images: { total: imagesTotalRes.count || 0, pending: imagesPendingRes.count || 0 },
|
||||
});
|
||||
} catch (e) {
|
||||
console.warn('Failed to fetch metrics', e);
|
||||
}
|
||||
};
|
||||
|
||||
const handleRunNow = async () => {
|
||||
if (!activeSite) return;
|
||||
if (estimate && !estimate.sufficient) {
|
||||
@@ -887,103 +950,9 @@ const AutomationPage: React.FC = () => {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Status Summary Card */}
|
||||
{currentRun && (
|
||||
<div className="relative rounded-xl border-2 border-slate-300 dark:border-gray-700 p-5 bg-gradient-to-br from-slate-100 to-slate-200 dark:from-gray-800/50 dark:to-gray-700/50">
|
||||
<div className="mb-3">
|
||||
<div className="text-sm font-bold text-gray-900 dark:text-white mb-1">Current Status</div>
|
||||
<div className="text-xs font-medium text-gray-600 dark:text-gray-400">Run Summary</div>
|
||||
</div>
|
||||
|
||||
<div className="space-y-2 text-xs">
|
||||
<div className="flex justify-between">
|
||||
<span className="text-gray-600 dark:text-gray-400">Run ID:</span>
|
||||
<span className="font-mono text-xs text-slate-900 dark:text-white">{currentRun.run_id.split('_').pop()}</span>
|
||||
</div>
|
||||
<div className="flex justify-between">
|
||||
<span className="text-gray-600 dark:text-gray-400">Started:</span>
|
||||
<span className="font-semibold text-slate-900 dark:text-white">
|
||||
{new Date(currentRun.started_at).toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' })}
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex justify-between">
|
||||
<span className="text-gray-600 dark:text-gray-400">Current Stage:</span>
|
||||
<span className="font-bold text-blue-600 dark:text-blue-400">{currentRun.current_stage}/7</span>
|
||||
</div>
|
||||
<div className="flex justify-between">
|
||||
<span className="text-gray-600 dark:text-gray-400">Credits Used:</span>
|
||||
<span className="font-bold text-brand-600 dark:text-brand-400">{currentRun.total_credits_used}</span>
|
||||
</div>
|
||||
<div className="flex justify-between">
|
||||
<span className="text-gray-600 dark:text-gray-400">Completion:</span>
|
||||
<span className="font-bold text-slate-900 dark:text-white">{Math.round((currentRun.current_stage / 7) * 100)}%</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="mt-4 pt-3 border-t border-slate-300 dark:border-gray-600">
|
||||
<div className={`
|
||||
size-12 mx-auto rounded-full flex items-center justify-center
|
||||
${currentRun.status === 'running'
|
||||
? 'bg-gradient-to-br from-blue-500 to-blue-600 animate-pulse'
|
||||
: currentRun.status === 'paused'
|
||||
? 'bg-gradient-to-br from-amber-500 to-amber-600'
|
||||
: 'bg-gradient-to-br from-success-500 to-success-600'
|
||||
}
|
||||
`}>
|
||||
{currentRun.status === 'running' && <div className="size-3 bg-white rounded-full"></div>}
|
||||
{currentRun.status === 'paused' && <ClockIcon className="size-6 text-white" />}
|
||||
{currentRun.status === 'completed' && <CheckCircleIcon className="size-6 text-white" />}
|
||||
</div>
|
||||
<div className="text-center mt-2 text-xs font-semibold text-gray-700 dark:text-gray-300 capitalize">
|
||||
{currentRun.status}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</ComponentCard>
|
||||
|
||||
{/* Current Run Details */}
|
||||
{currentRun && (
|
||||
<ComponentCard title={`Current Run: ${currentRun.run_id}`} desc="Live automation progress and detailed results">
|
||||
<div className="grid grid-cols-2 md:grid-cols-4 gap-4">
|
||||
<EnhancedMetricCard
|
||||
title="Status"
|
||||
value={currentRun.status}
|
||||
icon={
|
||||
currentRun.status === 'running' ? <BoltIcon className="size-6" /> :
|
||||
currentRun.status === 'paused' ? <ClockIcon className="size-6" /> :
|
||||
currentRun.status === 'completed' ? <CheckCircleIcon className="size-6" /> :
|
||||
<FileTextIcon className="size-6" />
|
||||
}
|
||||
accentColor={
|
||||
currentRun.status === 'running' ? 'blue' :
|
||||
currentRun.status === 'paused' ? 'orange' :
|
||||
currentRun.status === 'completed' ? 'success' : 'red'
|
||||
}
|
||||
/>
|
||||
<EnhancedMetricCard
|
||||
title="Started"
|
||||
value={new Date(currentRun.started_at).toLocaleTimeString()}
|
||||
icon={<ClockIcon className="size-6" />}
|
||||
accentColor="blue"
|
||||
/>
|
||||
<EnhancedMetricCard
|
||||
title="Credits Used"
|
||||
value={currentRun.total_credits_used}
|
||||
icon={<BoltIcon className="size-6" />}
|
||||
accentColor="blue"
|
||||
/>
|
||||
<EnhancedMetricCard
|
||||
title="Trigger"
|
||||
value={currentRun.trigger_type}
|
||||
icon={<PaperPlaneIcon className="size-6" />}
|
||||
accentColor="green"
|
||||
/>
|
||||
</div>
|
||||
</ComponentCard>
|
||||
)}
|
||||
|
||||
{/* Activity Log */}
|
||||
{currentRun && <ActivityLog runId={currentRun.run_id} />}
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ import Badge from '../../components/ui/badge/Badge';
|
||||
import {
|
||||
BoltIcon,
|
||||
DollarLineIcon,
|
||||
ClockIcon,
|
||||
TimeIcon,
|
||||
CheckCircleIcon
|
||||
} from '../../icons';
|
||||
|
||||
@@ -149,7 +149,7 @@ const CreditsAndBilling: React.FC = () => {
|
||||
<EnhancedMetricCard
|
||||
title="Total This Month"
|
||||
value={usageLogs.reduce((sum, log) => sum + log.credits_used, 0)}
|
||||
icon={ClockIcon}
|
||||
icon={TimeIcon}
|
||||
color="purple"
|
||||
iconColor="text-purple-500"
|
||||
/>
|
||||
|
||||
Reference in New Issue
Block a user