Updated iamge prompt flow adn frotnend backend
This commit is contained in:
@@ -1,17 +1,13 @@
|
||||
/**
|
||||
* Images Page Configuration
|
||||
* Centralized config for Images page table, filters, and actions
|
||||
* Centralized config for Content Images page table, filters, and actions
|
||||
* Shows one row per content with featured and in-article images
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import {
|
||||
titleColumn,
|
||||
statusColumn,
|
||||
createdColumn,
|
||||
} from '../snippets/columns.snippets';
|
||||
import Badge from '../../components/ui/badge/Badge';
|
||||
import { formatRelativeDate } from '../../utils/date';
|
||||
import { TaskImage } from '../../services/api';
|
||||
import ContentImageCell, { ContentImageData } from '../../components/common/ContentImageCell';
|
||||
import { ContentImagesGroup } from '../../services/api';
|
||||
|
||||
export interface ColumnConfig {
|
||||
key: string;
|
||||
@@ -35,121 +31,112 @@ export interface HeaderMetricConfig {
|
||||
label: string;
|
||||
value: number;
|
||||
accentColor: 'blue' | 'green' | 'amber' | 'purple';
|
||||
calculate: (data: { images: any[]; totalCount: number }) => number;
|
||||
calculate: (data: { images: ContentImagesGroup[]; totalCount: number }) => number;
|
||||
}
|
||||
|
||||
export interface ImagesPageConfig {
|
||||
columns: ColumnConfig[];
|
||||
filters: FilterConfig[];
|
||||
headerMetrics: HeaderMetricConfig[];
|
||||
maxInArticleImages: number; // Maximum number of in-article image columns to show
|
||||
}
|
||||
|
||||
export const createImagesPageConfig = (
|
||||
handlers: {
|
||||
searchTerm: string;
|
||||
setSearchTerm: (value: string) => void;
|
||||
imageTypeFilter: string;
|
||||
setImageTypeFilter: (value: string) => void;
|
||||
statusFilter: string;
|
||||
setStatusFilter: (value: string) => void;
|
||||
setCurrentPage: (page: number) => void;
|
||||
maxInArticleImages?: number; // Optional: max in-article images to display
|
||||
}
|
||||
): ImagesPageConfig => {
|
||||
const maxImages = handlers.maxInArticleImages || 5; // Default to 5 in-article images
|
||||
|
||||
// Build columns dynamically based on max in-article images
|
||||
const columns: ColumnConfig[] = [
|
||||
{
|
||||
key: 'content_title',
|
||||
label: 'Content Title',
|
||||
sortable: false,
|
||||
width: '250px',
|
||||
render: (_value: string, row: ContentImagesGroup) => (
|
||||
<div>
|
||||
<a
|
||||
href={`/writer/content/${row.content_id}`}
|
||||
className="font-medium text-brand-500 hover:text-brand-600 dark:text-brand-400"
|
||||
>
|
||||
{row.content_title}
|
||||
</a>
|
||||
<div className="text-xs text-gray-500 dark:text-gray-400 mt-1">
|
||||
ID: {row.content_id}
|
||||
</div>
|
||||
</div>
|
||||
),
|
||||
},
|
||||
{
|
||||
key: 'featured_image',
|
||||
label: 'Featured Image',
|
||||
sortable: false,
|
||||
width: '200px',
|
||||
render: (_value: any, row: ContentImagesGroup) => (
|
||||
<ContentImageCell image={row.featured_image} />
|
||||
),
|
||||
},
|
||||
];
|
||||
|
||||
// Add in-article image columns dynamically
|
||||
for (let i = 1; i <= maxImages; i++) {
|
||||
columns.push({
|
||||
key: `in_article_${i}`,
|
||||
label: `In-Article ${i}`,
|
||||
sortable: false,
|
||||
width: '200px',
|
||||
render: (_value: any, row: ContentImagesGroup) => {
|
||||
const image = row.in_article_images.find(img => img.position === i);
|
||||
return <ContentImageCell image={image || null} />;
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
// Add overall status column
|
||||
columns.push({
|
||||
key: 'overall_status',
|
||||
label: 'Status',
|
||||
sortable: false,
|
||||
width: '120px',
|
||||
render: (value: string) => {
|
||||
const statusColors: Record<string, 'success' | 'warning' | 'error' | 'info'> = {
|
||||
'complete': 'success',
|
||||
'partial': 'info',
|
||||
'pending': 'warning',
|
||||
'failed': 'error',
|
||||
};
|
||||
const labels: Record<string, string> = {
|
||||
'complete': 'Complete',
|
||||
'partial': 'Partial',
|
||||
'pending': 'Pending',
|
||||
'failed': 'Failed',
|
||||
};
|
||||
return (
|
||||
<Badge
|
||||
color={statusColors[value] || 'warning'}
|
||||
size="sm"
|
||||
>
|
||||
{labels[value] || value}
|
||||
</Badge>
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
return {
|
||||
columns: [
|
||||
{
|
||||
key: 'task_title',
|
||||
label: 'Task',
|
||||
sortable: false,
|
||||
width: '250px',
|
||||
render: (_value: string, row: TaskImage) => (
|
||||
<span className="font-medium text-gray-800 dark:text-white/90">
|
||||
{row.task_title || '-'}
|
||||
</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
key: 'image_type',
|
||||
label: 'Image Type',
|
||||
sortable: false,
|
||||
width: '150px',
|
||||
render: (value: string) => (
|
||||
<Badge color="info" size="sm" variant="light">
|
||||
{value?.replace('_', ' ') || '-'}
|
||||
</Badge>
|
||||
),
|
||||
},
|
||||
{
|
||||
key: 'image_url',
|
||||
label: 'Image',
|
||||
sortable: false,
|
||||
width: '200px',
|
||||
render: (value: string) => {
|
||||
if (!value) return <span className="text-gray-400">-</span>;
|
||||
return (
|
||||
<a
|
||||
href={value}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="text-brand-500 hover:text-brand-600 text-sm truncate block max-w-[200px]"
|
||||
>
|
||||
View Image
|
||||
</a>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
...statusColumn,
|
||||
sortable: true,
|
||||
sortField: 'status',
|
||||
render: (value: string) => {
|
||||
const statusColors: Record<string, 'success' | 'warning' | 'error'> = {
|
||||
'pending': 'warning',
|
||||
'generated': 'success',
|
||||
'failed': 'error',
|
||||
};
|
||||
return (
|
||||
<Badge
|
||||
color={statusColors[value] || 'warning'}
|
||||
size="sm"
|
||||
>
|
||||
{value}
|
||||
</Badge>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
key: 'position',
|
||||
label: 'Position',
|
||||
sortable: false,
|
||||
width: '100px',
|
||||
render: (value: number) => value || 0,
|
||||
},
|
||||
{
|
||||
...createdColumn,
|
||||
sortable: true,
|
||||
sortField: 'created_at',
|
||||
render: (value: string) => formatRelativeDate(value),
|
||||
},
|
||||
],
|
||||
columns,
|
||||
filters: [
|
||||
{
|
||||
key: 'search',
|
||||
label: 'Search',
|
||||
type: 'text',
|
||||
placeholder: 'Search by task title...',
|
||||
},
|
||||
{
|
||||
key: 'image_type',
|
||||
label: 'Image Type',
|
||||
type: 'select',
|
||||
options: [
|
||||
{ value: '', label: 'All Types' },
|
||||
{ value: 'featured', label: 'Featured Image' },
|
||||
{ value: 'desktop', label: 'Desktop Image' },
|
||||
{ value: 'mobile', label: 'Mobile Image' },
|
||||
{ value: 'in_article', label: 'In-Article Image' },
|
||||
],
|
||||
placeholder: 'Search by content title...',
|
||||
},
|
||||
{
|
||||
key: 'status',
|
||||
@@ -157,38 +144,39 @@ export const createImagesPageConfig = (
|
||||
type: 'select',
|
||||
options: [
|
||||
{ value: '', label: 'All Status' },
|
||||
{ value: 'complete', label: 'Complete' },
|
||||
{ value: 'partial', label: 'Partial' },
|
||||
{ value: 'pending', label: 'Pending' },
|
||||
{ value: 'generated', label: 'Generated' },
|
||||
{ value: 'failed', label: 'Failed' },
|
||||
],
|
||||
},
|
||||
],
|
||||
headerMetrics: [
|
||||
{
|
||||
label: 'Total Images',
|
||||
label: 'Total Content',
|
||||
value: 0,
|
||||
accentColor: 'blue' as const,
|
||||
calculate: (data) => data.totalCount || 0,
|
||||
},
|
||||
{
|
||||
label: 'Generated',
|
||||
label: 'Complete',
|
||||
value: 0,
|
||||
accentColor: 'green' as const,
|
||||
calculate: (data) => data.images.filter((i: TaskImage) => i.status === 'generated').length,
|
||||
calculate: (data) => data.images.filter((i: ContentImagesGroup) => i.overall_status === 'complete').length,
|
||||
},
|
||||
{
|
||||
label: 'Partial',
|
||||
value: 0,
|
||||
accentColor: 'info' as const,
|
||||
calculate: (data) => data.images.filter((i: ContentImagesGroup) => i.overall_status === 'partial').length,
|
||||
},
|
||||
{
|
||||
label: 'Pending',
|
||||
value: 0,
|
||||
accentColor: 'amber' as const,
|
||||
calculate: (data) => data.images.filter((i: TaskImage) => i.status === 'pending').length,
|
||||
},
|
||||
{
|
||||
label: 'Failed',
|
||||
value: 0,
|
||||
accentColor: 'error' as const,
|
||||
calculate: (data) => data.images.filter((i: TaskImage) => i.status === 'failed').length,
|
||||
calculate: (data) => data.images.filter((i: ContentImagesGroup) => i.overall_status === 'pending').length,
|
||||
},
|
||||
],
|
||||
maxInArticleImages: maxImages,
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user