minor ui improvements

This commit is contained in:
IGNY8 VPS (Salman)
2025-12-01 10:39:42 +00:00
parent 7631a77822
commit a7eddd44b2
10 changed files with 49 additions and 29 deletions

View File

@@ -144,6 +144,7 @@ class ContentImagesGroupSerializer(serializers.Serializer):
"""Serializer for grouped content images - one row per content""" """Serializer for grouped content images - one row per content"""
content_id = serializers.IntegerField() content_id = serializers.IntegerField()
content_title = serializers.CharField() content_title = serializers.CharField()
content_status = serializers.CharField() # draft, review, publish
featured_image = ContentImageSerializer(allow_null=True) featured_image = ContentImageSerializer(allow_null=True)
in_article_images = ContentImageSerializer(many=True) in_article_images = ContentImageSerializer(many=True)
overall_status = serializers.CharField() # 'pending', 'partial', 'complete', 'failed' overall_status = serializers.CharField() # 'pending', 'partial', 'complete', 'failed'

View File

@@ -581,6 +581,7 @@ class ImagesViewSet(SiteSectorModelViewSet):
grouped_data.append({ grouped_data.append({
'content_id': content.id, 'content_id': content.id,
'content_title': content.title or content.meta_title or f"Content #{content.id}", 'content_title': content.title or content.meta_title or f"Content #{content.id}",
'content_status': content.status, # Add content status
'featured_image': featured_serializer.data if featured_serializer else None, 'featured_image': featured_serializer.data if featured_serializer else None,
'in_article_images': [s.data for s in in_article_serializers], 'in_article_images': [s.data for s in in_article_serializers],
'overall_status': overall_status, 'overall_status': overall_status,

View File

@@ -105,9 +105,9 @@ const toneStyles: Record<
}; };
const sizeClasses: Record<BadgeSize, string> = { const sizeClasses: Record<BadgeSize, string> = {
xs: "h-5 px-2 text-[11px] leading-tight", xs: "min-h-[20px] px-2.5 py-1 text-[11px] leading-[1.4]",
sm: "h-6 px-2.5 text-xs leading-tight", sm: "min-h-[24px] px-3 py-1 text-xs leading-[1.4]",
md: "h-7 px-3 text-sm leading-tight", md: "min-h-[28px] px-3.5 py-1.5 text-sm leading-[1.4]",
}; };
const Badge: React.FC<BadgeProps> = ({ const Badge: React.FC<BadgeProps> = ({
@@ -152,7 +152,7 @@ const Badge: React.FC<BadgeProps> = ({
return ( return (
<span <span
className={clsx( className={clsx(
"inline-flex items-center justify-center gap-1 rounded-full font-normal", "inline-flex items-center justify-center gap-1 rounded font-normal",
sizeClasses[size], sizeClasses[size],
toneClass, toneClass,
className, className,

View File

@@ -65,7 +65,19 @@ export const createImagesPageConfig = (
sortable: true, sortable: true,
sortField: 'content_title', sortField: 'content_title',
width: '250px', width: '250px',
render: (_value: string, row: ContentImagesGroup) => ( render: (_value: string, row: ContentImagesGroup) => {
const statusColors: Record<string, 'warning' | 'info' | 'success'> = {
draft: 'warning',
review: 'info',
publish: 'success',
};
const statusLabels: Record<string, string> = {
draft: 'Draft',
review: 'Review',
publish: 'Publish',
};
return (
<div> <div>
<a <a
href={`/writer/content/${row.content_id}`} href={`/writer/content/${row.content_id}`}
@@ -73,11 +85,15 @@ export const createImagesPageConfig = (
> >
{row.content_title} {row.content_title}
</a> </a>
<div className="text-xs text-gray-500 dark:text-gray-400 mt-1"> <div className="text-xs text-gray-500 dark:text-gray-400 mt-1 flex items-center gap-2">
ID: {row.content_id} <Badge color={statusColors[row.content_status] || 'warning'} size="xs" variant="soft">
{statusLabels[row.content_status] || row.content_status}
</Badge>
<span>ID: {row.content_id}</span>
</div> </div>
</div> </div>
), );
},
}, },
{ {
key: 'featured_image', key: 'featured_image',

View File

@@ -37,7 +37,7 @@ export default function Content() {
// Filter state // Filter state
const [searchTerm, setSearchTerm] = useState(''); const [searchTerm, setSearchTerm] = useState('');
const [statusFilter, setStatusFilter] = useState(''); const [statusFilter, setStatusFilter] = useState('draft');
const [sourceFilter, setSourceFilter] = useState(''); const [sourceFilter, setSourceFilter] = useState('');
const [selectedIds, setSelectedIds] = useState<string[]>([]); const [selectedIds, setSelectedIds] = useState<string[]>([]);
@@ -225,8 +225,8 @@ export default function Content() {
// Writer navigation tabs // Writer navigation tabs
const writerTabs = [ const writerTabs = [
{ label: 'Tasks', path: '/writer/tasks', icon: <TaskIcon /> }, { label: 'Queue', path: '/writer/tasks', icon: <TaskIcon /> },
{ label: 'Content', path: '/writer/content', icon: <FileIcon /> }, { label: 'Drafts', path: '/writer/content', icon: <FileIcon /> },
{ label: 'Images', path: '/writer/images', icon: <ImageIcon /> }, { label: 'Images', path: '/writer/images', icon: <ImageIcon /> },
{ label: 'Review', path: '/writer/review', icon: <CheckCircleIcon /> }, { label: 'Review', path: '/writer/review', icon: <CheckCircleIcon /> },
{ label: 'Published', path: '/writer/published', icon: <CheckCircleIcon /> }, { label: 'Published', path: '/writer/published', icon: <CheckCircleIcon /> },
@@ -235,7 +235,7 @@ export default function Content() {
return ( return (
<> <>
<PageHeader <PageHeader
title="Content" title="Content Drafts"
badge={{ icon: <FileIcon />, color: 'purple' }} badge={{ icon: <FileIcon />, color: 'purple' }}
navigation={<ModuleNavigationTabs tabs={writerTabs} />} navigation={<ModuleNavigationTabs tabs={writerTabs} />}
/> />

View File

@@ -497,8 +497,8 @@ export default function Images() {
// Writer navigation tabs // Writer navigation tabs
const writerTabs = [ const writerTabs = [
{ label: 'Tasks', path: '/writer/tasks', icon: <TaskIcon /> }, { label: 'Queue', path: '/writer/tasks', icon: <TaskIcon /> },
{ label: 'Content', path: '/writer/content', icon: <FileIcon /> }, { label: 'Drafts', path: '/writer/content', icon: <FileIcon /> },
{ label: 'Images', path: '/writer/images', icon: <ImageIcon /> }, { label: 'Images', path: '/writer/images', icon: <ImageIcon /> },
{ label: 'Review', path: '/writer/review', icon: <CheckCircleIcon /> }, { label: 'Review', path: '/writer/review', icon: <CheckCircleIcon /> },
{ label: 'Published', path: '/writer/published', icon: <CheckCircleIcon /> }, { label: 'Published', path: '/writer/published', icon: <CheckCircleIcon /> },

View File

@@ -307,8 +307,8 @@ export default function Published() {
// Writer navigation tabs // Writer navigation tabs
const writerTabs = [ const writerTabs = [
{ label: 'Tasks', path: '/writer/tasks', icon: <TaskIcon /> }, { label: 'Queue', path: '/writer/tasks', icon: <TaskIcon /> },
{ label: 'Content', path: '/writer/content', icon: <FileIcon /> }, { label: 'Drafts', path: '/writer/content', icon: <FileIcon /> },
{ label: 'Images', path: '/writer/images', icon: <ImageIcon /> }, { label: 'Images', path: '/writer/images', icon: <ImageIcon /> },
{ label: 'Review', path: '/writer/review', icon: <CheckCircleIcon /> }, { label: 'Review', path: '/writer/review', icon: <CheckCircleIcon /> },
{ label: 'Published', path: '/writer/published', icon: <CheckCircleIcon /> }, { label: 'Published', path: '/writer/published', icon: <CheckCircleIcon /> },

View File

@@ -345,8 +345,8 @@ export default function Review() {
// Writer navigation tabs // Writer navigation tabs
const writerTabs = [ const writerTabs = [
{ label: 'Tasks', path: '/writer/tasks', icon: <TaskIcon /> }, { label: 'Queue', path: '/writer/tasks', icon: <TaskIcon /> },
{ label: 'Content', path: '/writer/content', icon: <FileIcon /> }, { label: 'Drafts', path: '/writer/content', icon: <FileIcon /> },
{ label: 'Images', path: '/writer/images', icon: <ImageIcon /> }, { label: 'Images', path: '/writer/images', icon: <ImageIcon /> },
{ label: 'Review', path: '/writer/review', icon: <CheckCircleIcon /> }, { label: 'Review', path: '/writer/review', icon: <CheckCircleIcon /> },
{ label: 'Published', path: '/writer/published', icon: <CheckCircleIcon /> }, { label: 'Published', path: '/writer/published', icon: <CheckCircleIcon /> },

View File

@@ -560,16 +560,17 @@ export default function Tasks() {
// Writer navigation tabs // Writer navigation tabs
const writerTabs = [ const writerTabs = [
{ label: 'Tasks', path: '/writer/tasks', icon: <TaskIcon /> }, { label: 'Queue', path: '/writer/tasks', icon: <TaskIcon /> },
{ label: 'Content', path: '/writer/content', icon: <FileIcon /> }, { label: 'Drafts', path: '/writer/content', icon: <FileIcon /> },
{ label: 'Images', path: '/writer/images', icon: <ImageIcon /> }, { label: 'Images', path: '/writer/images', icon: <ImageIcon /> },
{ label: 'Review', path: '/writer/review', icon: <CheckCircleIcon /> },
{ label: 'Published', path: '/writer/published', icon: <CheckCircleIcon /> }, { label: 'Published', path: '/writer/published', icon: <CheckCircleIcon /> },
]; ];
return ( return (
<> <>
<PageHeader <PageHeader
title="Tasks" title="Content Queue"
badge={{ icon: <TaskIcon />, color: 'indigo' }} badge={{ icon: <TaskIcon />, color: 'indigo' }}
navigation={<ModuleNavigationTabs tabs={writerTabs} />} navigation={<ModuleNavigationTabs tabs={writerTabs} />}
/> />

View File

@@ -1184,6 +1184,7 @@ export interface ContentImage {
export interface ContentImagesGroup { export interface ContentImagesGroup {
content_id: number; content_id: number;
content_title: string; content_title: string;
content_status: 'draft' | 'review' | 'publish';
featured_image: ContentImage | null; featured_image: ContentImage | null;
in_article_images: ContentImage[]; in_article_images: ContentImage[];
overall_status: 'pending' | 'partial' | 'complete' | 'failed'; overall_status: 'pending' | 'partial' | 'complete' | 'failed';