Add Linker and Optimizer modules with API integration and frontend components

- Added Linker and Optimizer apps to `INSTALLED_APPS` in `settings.py`.
- Configured API endpoints for Linker and Optimizer in `urls.py`.
- Implemented `OptimizeContentFunction` for content optimization in the AI module.
- Created prompts for content optimization and site structure generation.
- Updated `OptimizerService` to utilize the new AI function for content optimization.
- Developed frontend components including dashboards and content lists for Linker and Optimizer.
- Integrated new routes and sidebar navigation for Linker and Optimizer in the frontend.
- Enhanced content management with source and sync status filters in the Writer module.
- Comprehensive test coverage added for new features and components.
This commit is contained in:
alorig
2025-11-18 00:41:00 +05:00
parent 4b9e1a49a9
commit f7115190dc
60 changed files with 4932 additions and 80 deletions

View File

@@ -5,12 +5,14 @@
import { useState, useEffect, useMemo, useCallback, useRef } from 'react';
import TablePageTemplate from '../../templates/TablePageTemplate';
import {
import {
fetchContent,
Content as ContentType,
ContentFilters,
generateImagePrompts,
} from '../../services/api';
import { optimizerApi } from '../../api/optimizer.api';
import { useNavigate } from 'react-router';
import { useToast } from '../../components/ui/toast/ToastContainer';
import { FileIcon } from '../../icons';
import { createContentPageConfig } from '../../config/pages/content.config';
@@ -32,6 +34,8 @@ export default function Content() {
// Filter state
const [searchTerm, setSearchTerm] = useState('');
const [statusFilter, setStatusFilter] = useState('');
const [sourceFilter, setSourceFilter] = useState('');
const [syncStatusFilter, setSyncStatusFilter] = useState('');
const [selectedIds, setSelectedIds] = useState<string[]>([]);
// Pagination state
@@ -58,6 +62,8 @@ export default function Content() {
const filters: ContentFilters = {
...(searchTerm && { search: searchTerm }),
...(statusFilter && { status: statusFilter }),
...(sourceFilter && { source: sourceFilter }),
...(syncStatusFilter && { sync_status: syncStatusFilter }),
page: currentPage,
page_size: pageSize,
ordering,
@@ -153,6 +159,8 @@ export default function Content() {
}));
}, [pageConfig?.headerMetrics, content, totalCount]);
const navigate = useNavigate();
const handleRowAction = useCallback(async (action: string, row: ContentType) => {
if (action === 'generate_image_prompts') {
try {
@@ -176,8 +184,18 @@ export default function Content() {
} catch (error: any) {
toast.error(`Failed to generate prompts: ${error.message}`);
}
} else if (action === 'optimize') {
try {
const result = await optimizerApi.optimize(row.id, 'writer');
toast.success(`Content optimized! Score: ${result.scores_after.overall_score.toFixed(1)}`);
loadContent(); // Reload to show updated scores
} catch (error: any) {
toast.error(`Failed to optimize content: ${error.message}`);
}
} else if (action === 'send_to_optimizer') {
navigate(`/optimizer/content?contentId=${row.id}`);
}
}, [toast, progressModal, loadContent]);
}, [toast, progressModal, loadContent, navigate]);
return (
<>
@@ -194,6 +212,8 @@ export default function Content() {
filterValues={{
search: searchTerm,
status: statusFilter,
source: sourceFilter,
sync_status: syncStatusFilter,
}}
onFilterChange={(key: string, value: any) => {
if (key === 'search') {
@@ -201,6 +221,12 @@ export default function Content() {
} else if (key === 'status') {
setStatusFilter(value);
setCurrentPage(1);
} else if (key === 'source') {
setSourceFilter(value);
setCurrentPage(1);
} else if (key === 'sync_status') {
setSyncStatusFilter(value);
setCurrentPage(1);
}
}}
pagination={{