New Columns and columns visibility
This commit is contained in:
@@ -27,6 +27,7 @@ export interface ColumnConfig {
|
||||
align?: 'left' | 'center' | 'right';
|
||||
width?: string;
|
||||
render?: (value: any, row: any) => React.ReactNode;
|
||||
defaultVisible?: boolean; // Whether column is visible by default (default: true)
|
||||
}
|
||||
|
||||
export interface FormFieldConfig {
|
||||
@@ -116,21 +117,24 @@ export const createClustersPageConfig = (
|
||||
{
|
||||
key: 'keywords_count',
|
||||
label: 'Keywords',
|
||||
sortable: false,
|
||||
sortable: true,
|
||||
sortField: 'keywords_count',
|
||||
width: '120px',
|
||||
render: (value: number) => value.toLocaleString(),
|
||||
},
|
||||
{
|
||||
key: 'ideas_count',
|
||||
label: 'Ideas',
|
||||
sortable: false,
|
||||
sortable: true,
|
||||
sortField: 'ideas_count',
|
||||
width: '120px',
|
||||
render: (value: number) => value.toLocaleString(),
|
||||
},
|
||||
{
|
||||
key: 'volume',
|
||||
label: 'Volume',
|
||||
sortable: false,
|
||||
sortable: true,
|
||||
sortField: 'volume',
|
||||
width: '120px',
|
||||
render: (value: number) => value.toLocaleString(),
|
||||
},
|
||||
@@ -138,7 +142,8 @@ export const createClustersPageConfig = (
|
||||
...difficultyColumn,
|
||||
key: 'difficulty',
|
||||
label: 'Difficulty',
|
||||
sortable: false,
|
||||
sortable: true,
|
||||
sortField: 'difficulty',
|
||||
align: 'center' as const,
|
||||
render: (value: number) => {
|
||||
const difficultyNum = getDifficultyNumber(value);
|
||||
@@ -179,7 +184,8 @@ export const createClustersPageConfig = (
|
||||
{
|
||||
key: 'content_count',
|
||||
label: 'Content',
|
||||
sortable: false,
|
||||
sortable: true,
|
||||
sortField: 'content_count',
|
||||
width: '120px',
|
||||
render: (value: number) => value.toLocaleString(),
|
||||
},
|
||||
@@ -202,6 +208,36 @@ export const createClustersPageConfig = (
|
||||
sortField: 'created_at',
|
||||
render: (value: string) => formatRelativeDate(value),
|
||||
},
|
||||
// Optional columns - hidden by default
|
||||
{
|
||||
key: 'description',
|
||||
label: 'Description',
|
||||
sortable: false,
|
||||
defaultVisible: false,
|
||||
width: '250px',
|
||||
render: (value: string | null) => (
|
||||
<span className="text-sm text-gray-600 dark:text-gray-400 truncate block max-w-[250px]">
|
||||
{value || '-'}
|
||||
</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
key: 'mapped_pages',
|
||||
label: 'Mapped Pages',
|
||||
sortable: true,
|
||||
sortField: 'mapped_pages',
|
||||
defaultVisible: false,
|
||||
width: '120px',
|
||||
render: (value: number) => value.toLocaleString(),
|
||||
},
|
||||
{
|
||||
key: 'updated_at',
|
||||
label: 'Updated',
|
||||
sortable: true,
|
||||
sortField: 'updated_at',
|
||||
defaultVisible: false,
|
||||
render: (value: string) => formatRelativeDate(value),
|
||||
},
|
||||
],
|
||||
filters: [
|
||||
{
|
||||
|
||||
@@ -27,6 +27,7 @@ export interface ColumnConfig {
|
||||
toggleable?: boolean;
|
||||
toggleContentKey?: string;
|
||||
toggleContentLabel?: string;
|
||||
defaultVisible?: boolean; // Whether column is visible by default (default: true)
|
||||
}
|
||||
|
||||
export interface FilterConfig {
|
||||
@@ -124,7 +125,8 @@ export const createContentPageConfig = (
|
||||
{
|
||||
key: 'primary_keyword',
|
||||
label: 'Primary Keyword',
|
||||
sortable: false,
|
||||
sortable: true,
|
||||
sortField: 'primary_keyword',
|
||||
width: '150px',
|
||||
render: (value: string, row: Content) => (
|
||||
row.primary_keyword ? (
|
||||
@@ -262,6 +264,50 @@ export const createContentPageConfig = (
|
||||
);
|
||||
},
|
||||
},
|
||||
// Optional columns - hidden by default
|
||||
{
|
||||
key: 'task_title',
|
||||
label: 'Task Title',
|
||||
sortable: true,
|
||||
sortField: 'task_id',
|
||||
defaultVisible: false,
|
||||
width: '200px',
|
||||
render: (_value: string, row: Content) => (
|
||||
<span className="text-sm text-gray-600 dark:text-gray-400 truncate block max-w-[200px]">
|
||||
{row.task_title || '-'}
|
||||
</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
key: 'post_url',
|
||||
label: 'Post URL',
|
||||
sortable: false,
|
||||
defaultVisible: false,
|
||||
width: '200px',
|
||||
render: (value: string | null, row: Content) => {
|
||||
const url = value || row.post_url || null;
|
||||
return url ? (
|
||||
<a
|
||||
href={url}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="text-sm text-brand-600 hover:text-brand-700 dark:text-brand-400 dark:hover:text-brand-300 truncate block max-w-[200px]"
|
||||
>
|
||||
{url}
|
||||
</a>
|
||||
) : (
|
||||
<span className="text-sm text-gray-400 dark:text-gray-500">-</span>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
key: 'updated_at',
|
||||
label: 'Updated',
|
||||
sortable: true,
|
||||
sortField: 'updated_at',
|
||||
defaultVisible: false,
|
||||
render: (value: string) => formatRelativeDate(value),
|
||||
},
|
||||
],
|
||||
filters: [
|
||||
{
|
||||
|
||||
@@ -22,6 +22,7 @@ export interface ColumnConfig {
|
||||
align?: 'left' | 'center' | 'right';
|
||||
width?: string;
|
||||
render?: (value: any, row: any) => React.ReactNode;
|
||||
defaultVisible?: boolean; // Whether column is visible by default (default: true)
|
||||
}
|
||||
|
||||
export interface FormFieldConfig {
|
||||
@@ -150,7 +151,8 @@ export const createIdeasPageConfig = (
|
||||
{
|
||||
key: 'keyword_cluster_name',
|
||||
label: 'Cluster',
|
||||
sortable: false,
|
||||
sortable: true,
|
||||
sortField: 'keyword_cluster_id',
|
||||
width: '200px',
|
||||
render: (_value: string, row: ContentIdea) => row.keyword_cluster_name || '-',
|
||||
},
|
||||
@@ -188,6 +190,15 @@ export const createIdeasPageConfig = (
|
||||
sortField: 'created_at',
|
||||
render: (value: string) => formatRelativeDate(value),
|
||||
},
|
||||
// Optional columns - hidden by default
|
||||
{
|
||||
key: 'updated_at',
|
||||
label: 'Updated',
|
||||
sortable: true,
|
||||
sortField: 'updated_at',
|
||||
defaultVisible: false,
|
||||
render: (value: string) => formatRelativeDate(value),
|
||||
},
|
||||
],
|
||||
filters: [
|
||||
{
|
||||
|
||||
@@ -18,6 +18,7 @@ export interface ColumnConfig {
|
||||
align?: 'left' | 'center' | 'right';
|
||||
width?: string;
|
||||
render?: (value: any, row: any) => React.ReactNode;
|
||||
defaultVisible?: boolean; // Whether column is visible by default (default: true)
|
||||
}
|
||||
|
||||
export interface FilterConfig {
|
||||
@@ -60,7 +61,8 @@ export const createImagesPageConfig = (
|
||||
{
|
||||
key: 'content_title',
|
||||
label: 'Content Title',
|
||||
sortable: false,
|
||||
sortable: true,
|
||||
sortField: 'content_title',
|
||||
width: '250px',
|
||||
render: (_value: string, row: ContentImagesGroup) => (
|
||||
<div>
|
||||
@@ -105,7 +107,8 @@ export const createImagesPageConfig = (
|
||||
columns.push({
|
||||
key: 'overall_status',
|
||||
label: 'Status',
|
||||
sortable: false,
|
||||
sortable: true,
|
||||
sortField: 'overall_status',
|
||||
width: '180px',
|
||||
render: (value: string, row: ContentImagesGroup) => {
|
||||
const statusColors: Record<string, 'success' | 'warning' | 'error' | 'info'> = {
|
||||
|
||||
@@ -36,6 +36,7 @@ export interface ColumnConfig {
|
||||
align?: 'left' | 'center' | 'right';
|
||||
width?: string;
|
||||
render?: (value: any, row: any) => React.ReactNode;
|
||||
defaultVisible?: boolean; // Whether column is visible by default (default: true)
|
||||
}
|
||||
|
||||
// BulkActionConfig and RowActionConfig are now in table-actions.config.tsx
|
||||
@@ -163,7 +164,8 @@ export const createKeywordsPageConfig = (
|
||||
},
|
||||
{
|
||||
...clusterColumn,
|
||||
sortable: false,
|
||||
sortable: true,
|
||||
sortField: 'cluster_id',
|
||||
render: (_value: string, row: Keyword) => row.cluster_name || '-',
|
||||
},
|
||||
{
|
||||
@@ -264,6 +266,52 @@ export const createKeywordsPageConfig = (
|
||||
sortField: 'created_at',
|
||||
render: (value: string) => formatRelativeDate(value),
|
||||
},
|
||||
// Optional columns - hidden by default
|
||||
{
|
||||
key: 'updated_at',
|
||||
label: 'Updated',
|
||||
sortable: true,
|
||||
sortField: 'updated_at',
|
||||
defaultVisible: false,
|
||||
render: (value: string) => formatRelativeDate(value),
|
||||
},
|
||||
{
|
||||
key: 'volume_override',
|
||||
label: 'Volume Override',
|
||||
sortable: true,
|
||||
sortField: 'volume_override',
|
||||
defaultVisible: false,
|
||||
render: (value: number | null) => value ? value.toLocaleString() : '-',
|
||||
},
|
||||
{
|
||||
key: 'difficulty_override',
|
||||
label: 'Difficulty Override',
|
||||
sortable: true,
|
||||
sortField: 'difficulty_override',
|
||||
defaultVisible: false,
|
||||
align: 'center' as const,
|
||||
render: (value: number | null) => {
|
||||
if (value === null || value === undefined) return '-';
|
||||
const difficultyNum = getDifficultyNumber(value);
|
||||
return typeof difficultyNum === 'number' ? (
|
||||
<Badge
|
||||
color={
|
||||
difficultyNum === 1 || difficultyNum === 2
|
||||
? 'success'
|
||||
: difficultyNum === 3
|
||||
? 'warning'
|
||||
: 'error'
|
||||
}
|
||||
variant={difficultyNum === 5 ? 'solid' : 'light'}
|
||||
size="sm"
|
||||
>
|
||||
{difficultyNum}
|
||||
</Badge>
|
||||
) : (
|
||||
difficultyNum
|
||||
);
|
||||
},
|
||||
},
|
||||
],
|
||||
filters: [
|
||||
{
|
||||
|
||||
@@ -26,6 +26,7 @@ export interface ColumnConfig {
|
||||
toggleable?: boolean; // If true, this column will have a toggle button for expanding content
|
||||
toggleContentKey?: string; // Key of the field containing content to display when toggled
|
||||
toggleContentLabel?: string; // Label for the expanded content (e.g., "Content Outline", "Generated Content")
|
||||
defaultVisible?: boolean; // Whether column is visible by default (default: true)
|
||||
}
|
||||
|
||||
export interface FormFieldConfig {
|
||||
@@ -115,7 +116,8 @@ export const createTasksPageConfig = (
|
||||
{
|
||||
key: 'cluster_name',
|
||||
label: 'Cluster',
|
||||
sortable: false,
|
||||
sortable: true,
|
||||
sortField: 'cluster_id',
|
||||
width: '200px',
|
||||
render: (_value: string, row: Task) => row.cluster_name || '-',
|
||||
},
|
||||
@@ -176,6 +178,83 @@ export const createTasksPageConfig = (
|
||||
sortField: 'created_at',
|
||||
render: (value: string) => formatRelativeDate(value),
|
||||
},
|
||||
// Optional columns - hidden by default
|
||||
{
|
||||
key: 'idea_title',
|
||||
label: 'Idea',
|
||||
sortable: true,
|
||||
sortField: 'idea_id',
|
||||
defaultVisible: false,
|
||||
width: '200px',
|
||||
render: (_value: string, row: Task) => (
|
||||
<span className="text-sm text-gray-600 dark:text-gray-400 truncate block max-w-[200px]">
|
||||
{row.idea_title || '-'}
|
||||
</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
key: 'keywords',
|
||||
label: 'Keywords',
|
||||
sortable: false,
|
||||
defaultVisible: false,
|
||||
width: '200px',
|
||||
render: (value: string | null) => (
|
||||
<span className="text-sm text-gray-600 dark:text-gray-400 truncate block max-w-[200px]">
|
||||
{value || '-'}
|
||||
</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
key: 'meta_title',
|
||||
label: 'Meta Title',
|
||||
sortable: false,
|
||||
defaultVisible: false,
|
||||
width: '200px',
|
||||
render: (value: string | null) => (
|
||||
<span className="text-sm text-gray-600 dark:text-gray-400 truncate block max-w-[200px]">
|
||||
{value || '-'}
|
||||
</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
key: 'meta_description',
|
||||
label: 'Meta Description',
|
||||
sortable: false,
|
||||
defaultVisible: false,
|
||||
width: '250px',
|
||||
render: (value: string | null) => (
|
||||
<span className="text-sm text-gray-600 dark:text-gray-400 truncate block max-w-[250px]">
|
||||
{value || '-'}
|
||||
</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
key: 'post_url',
|
||||
label: 'Post URL',
|
||||
sortable: false,
|
||||
defaultVisible: false,
|
||||
width: '200px',
|
||||
render: (value: string | null) => value ? (
|
||||
<a
|
||||
href={value}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="text-sm text-brand-600 hover:text-brand-700 dark:text-brand-400 dark:hover:text-brand-300 truncate block max-w-[200px]"
|
||||
>
|
||||
{value}
|
||||
</a>
|
||||
) : (
|
||||
<span className="text-sm text-gray-400 dark:text-gray-500">-</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
key: 'updated_at',
|
||||
label: 'Updated',
|
||||
sortable: true,
|
||||
sortField: 'updated_at',
|
||||
defaultVisible: false,
|
||||
render: (value: string) => formatRelativeDate(value),
|
||||
},
|
||||
],
|
||||
filters: [
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user