This commit is contained in:
alorig
2025-11-28 15:46:38 +05:00
parent 1aead06939
commit bcdbbfe233
2 changed files with 104 additions and 55 deletions

View File

@@ -1005,13 +1005,29 @@ class ContentIdeasViewSet(SiteSectorModelViewSet):
)
queryset = self.get_queryset()
ideas = queryset.filter(id__in=ids, status='new') # Only queue 'new' ideas
# Get ALL requested ideas first (don't filter by status yet)
all_ideas = queryset.filter(id__in=ids)
# Check which ones can be queued (status='new')
queueable_ideas = all_ideas.filter(status='new')
from igny8_core.modules.writer.models import Tasks
created_tasks = []
errors = []
for idea in ideas:
skipped = []
# Add skipped ideas (not 'new' status)
for idea in all_ideas:
if idea.status != 'new':
skipped.append({
'idea_id': idea.id,
'title': idea.idea_title,
'reason': f'Already {idea.status}'
})
# Process queueable ideas
for idea in queueable_ideas:
try:
# Direct copy - no mapping needed
task = Tasks.objects.create(
@@ -1037,22 +1053,42 @@ class ContentIdeasViewSet(SiteSectorModelViewSet):
idea.status = 'scheduled'
idea.save()
except Exception as e:
errors.append({'idea_id': idea.id, 'error': str(e)})
errors.append({
'idea_id': idea.id,
'title': idea.idea_title,
'error': str(e)
})
if errors:
# Return appropriate response based on results
if len(created_tasks) == 0 and (errors or skipped):
# Complete failure
return error_response(
error=f'Failed to create {len(errors)} tasks',
errors=errors,
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
error=f'Failed to queue any ideas: {len(errors)} errors, {len(skipped)} skipped',
errors=errors if errors else skipped,
status_code=status.HTTP_400_BAD_REQUEST,
request=request
)
elif errors:
# Partial success - some created, some failed
return success_response(
data={
'created_count': len(created_tasks),
'task_ids': created_tasks,
'errors': errors,
'skipped': skipped,
},
message=f'Successfully queued {len(created_tasks)} ideas to writer',
message=f'Queued {len(created_tasks)} ideas ({len(errors)} failed, {len(skipped)} skipped)',
request=request
)
else:
# Complete success
return success_response(
data={
'created_count': len(created_tasks),
'task_ids': created_tasks,
'skipped': skipped,
},
message=f'Successfully queued {len(created_tasks)} ideas to writer' + (f' ({len(skipped)} already scheduled)' if skipped else ''),
request=request
)

View File

@@ -208,48 +208,61 @@ export const createContentPageConfig = (
},
},
{
key: 'prompts_status',
label: 'Prompts',
key: 'content_status_indicators',
label: 'Status',
sortable: false,
width: '110px',
width: '100px',
align: 'center' as const,
render: (_value: any, row: Content) => {
const hasPrompts = row.has_image_prompts;
const hasPrompts = row.has_image_prompts || false;
const hasImages = row.has_generated_images || false;
return (
<Badge color={hasPrompts ? 'success' : 'warning'} size="sm" variant="light">
{hasPrompts ? (
<span className="flex items-center gap-1">
<svg className="w-3 h-3" fill="currentColor" viewBox="0 0 20 20">
<path fillRule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z" clipRule="evenodd" />
<div className="flex items-center justify-center gap-2">
{/* Prompts Icon */}
<div
className={`w-5 h-5 flex items-center justify-center flex-shrink-0 ${
hasPrompts ? 'text-purple-500 dark:text-purple-400' : 'text-gray-300 dark:text-gray-600'
}`}
title={hasPrompts ? 'Prompts ready' : 'No prompts'}
>
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
className="w-4 h-4"
>
<path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z" />
</svg>
Ready
</span>
) : (
'No Prompts'
)}
</Badge>
);
},
},
{
key: 'images_status',
label: 'Images',
sortable: false,
width: '110px',
render: (_value: any, row: Content) => {
const hasImages = row.has_generated_images;
return (
<Badge color={hasImages ? 'success' : 'warning'} size="sm" variant="light">
{hasImages ? (
<span className="flex items-center gap-1">
<svg className="w-3 h-3" fill="currentColor" viewBox="0 0 20 20">
<path fillRule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z" clipRule="evenodd" />
</div>
{/* Images Icon */}
<div
className={`w-5 h-5 flex items-center justify-center flex-shrink-0 ${
hasImages ? 'text-green-500 dark:text-green-400' : 'text-gray-300 dark:text-gray-600'
}`}
title={hasImages ? 'Images generated' : 'No images'}
>
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
className="w-4 h-4"
>
<rect x="3" y="3" width="18" height="18" rx="2" ry="2" />
<circle cx="8.5" cy="8.5" r="1.5" />
<polyline points="21 15 16 10 5 21" />
</svg>
Generated
</span>
) : (
'No Images'
)}
</Badge>
</div>
</div>
);
},
},