Refactor content handling in GenerateContentFunction and update related models and serializers

- Enhanced GenerateContentFunction to save content in a dedicated Content model, separating it from the Tasks model.
- Updated Tasks model to remove SEO-related fields, now managed in the Content model.
- Modified TasksSerializer to include new content fields and adjusted the API to reflect these changes.
- Improved the auto_generate_content_task method to utilize the new save_output method for better content management.
- Updated frontend components to display new content structure and metadata effectively.
This commit is contained in:
IGNY8 VPS (Salman)
2025-11-10 14:06:15 +00:00
parent 8bb4c5d016
commit 8b6e18649c
11 changed files with 596 additions and 356 deletions

View File

@@ -97,18 +97,11 @@ export const createTasksPageConfig = (
columns: [
{
...titleColumn,
key: 'title',
label: 'Title',
sortable: true,
sortField: 'title',
toggleable: true, // Enable toggle for this column
toggleContentKey: 'content', // Use content field for toggle (fallback to description if content not available)
toggleContentLabel: 'Generated Content', // Label for expanded content
render: (_value: string, row: Task) => (
<span className="text-gray-800 dark:text-white font-medium">
{row.meta_title || row.title || '-'}
</span>
),
toggleable: true,
toggleContentKey: 'content_html',
toggleContentLabel: 'Generated Content',
},
// Sector column - only show when viewing all sectors
...(showSectorColumn ? [{
@@ -173,85 +166,6 @@ export const createTasksPageConfig = (
);
},
},
{
key: 'keywords',
label: 'Keywords',
sortable: false,
width: '250px',
render: (_value: any, row: Task) => {
const keywords: React.ReactNode[] = [];
// Primary keyword as info badge
if (row.primary_keyword) {
keywords.push(
<Badge key="primary" color="info" size="sm" variant="light" className="mr-1 mb-1">
{row.primary_keyword}
</Badge>
);
}
// Secondary keywords as light badges
if (row.secondary_keywords && Array.isArray(row.secondary_keywords) && row.secondary_keywords.length > 0) {
row.secondary_keywords.forEach((keyword, index) => {
if (keyword) {
keywords.push(
<Badge key={`secondary-${index}`} color="light" size="sm" variant="light" className="mr-1 mb-1">
{keyword}
</Badge>
);
}
});
}
return keywords.length > 0 ? (
<div className="flex flex-wrap gap-1">
{keywords}
</div>
) : (
<span className="text-gray-400">-</span>
);
},
},
{
key: 'tags',
label: 'Tags',
sortable: false,
width: '200px',
render: (_value: any, row: Task) => {
if (row.tags && Array.isArray(row.tags) && row.tags.length > 0) {
return (
<div className="flex flex-wrap gap-1">
{row.tags.map((tag, index) => (
<Badge key={index} color="light" size="sm" variant="light">
{tag}
</Badge>
))}
</div>
);
}
return <span className="text-gray-400">-</span>;
},
},
{
key: 'categories',
label: 'Categories',
sortable: false,
width: '200px',
render: (_value: any, row: Task) => {
if (row.categories && Array.isArray(row.categories) && row.categories.length > 0) {
return (
<div className="flex flex-wrap gap-1">
{row.categories.map((category, index) => (
<Badge key={index} color="light" size="sm" variant="light">
{category}
</Badge>
))}
</div>
);
}
return <span className="text-gray-400">-</span>;
},
},
{
...wordCountColumn,
sortable: true,