diff --git a/src/renderer/components/team/kanban/KanbanTaskCard.tsx b/src/renderer/components/team/kanban/KanbanTaskCard.tsx
index 022995d9..c2084c37 100644
--- a/src/renderer/components/team/kanban/KanbanTaskCard.tsx
+++ b/src/renderer/components/team/kanban/KanbanTaskCard.tsx
@@ -266,6 +266,208 @@ const TaskActionIconButton = ({
);
+interface TaskMetaActionsProps {
+ taskId: string;
+ unreadCount: number;
+ commentCount: number;
+ pulseKey: number;
+ canOpenChanges: boolean;
+ changesNeedAttention: boolean;
+ onViewChanges?: (taskId: string) => void;
+ onDeleteTask?: (taskId: string) => void;
+}
+
+const TaskMetaActions = memo(function TaskMetaActions({
+ taskId,
+ unreadCount,
+ commentCount,
+ pulseKey,
+ canOpenChanges,
+ changesNeedAttention,
+ onViewChanges,
+ onDeleteTask,
+}: TaskMetaActionsProps): React.JSX.Element {
+ const { t } = useAppTranslation('team');
+
+ return (
+ <>
+ {canOpenChanges && onViewChanges ? (
+ }
+ variant="ghost"
+ className={
+ changesNeedAttention
+ ? 'text-amber-400 hover:bg-amber-500/10 hover:text-amber-300'
+ : 'text-sky-400 hover:bg-sky-500/10 hover:text-sky-300'
+ }
+ onClick={(e) => {
+ e.stopPropagation();
+ onViewChanges(taskId);
+ }}
+ />
+ ) : null}
+
+ {onDeleteTask ? (
+ }
+ variant="ghost"
+ className="text-red-400 hover:bg-red-500/10 hover:text-red-300"
+ onClick={(e) => {
+ e.stopPropagation();
+ onDeleteTask(taskId);
+ }}
+ />
+ ) : null}
+ >
+ );
+});
+
+interface TaskPrimaryActionsProps {
+ taskId: string;
+ columnId: KanbanColumnId;
+ isReviewManual: boolean;
+ onRequestReview: (taskId: string) => void;
+ onApprove: (taskId: string) => void;
+ onRequestChanges: (taskId: string) => void;
+ onMoveBackToDone: (taskId: string) => void;
+ onStartTask: (taskId: string) => void;
+ onCompleteTask: (taskId: string) => void;
+ onCancelTask: (taskId: string) => void;
+}
+
+const TaskPrimaryActions = memo(function TaskPrimaryActions({
+ taskId,
+ columnId,
+ isReviewManual,
+ onRequestReview,
+ onApprove,
+ onRequestChanges,
+ onMoveBackToDone,
+ onStartTask,
+ onCompleteTask,
+ onCancelTask,
+}: TaskPrimaryActionsProps): React.JSX.Element {
+ const { t } = useAppTranslation('team');
+
+ return (
+
+ {columnId === 'todo' ? (
+ <>
+
}
+ className="border-emerald-500/40 text-emerald-400 hover:bg-emerald-500/10 hover:text-emerald-300"
+ onClick={(e) => {
+ e.stopPropagation();
+ onStartTask(taskId);
+ }}
+ />
+
}
+ className="border-emerald-500/40 text-emerald-400 hover:bg-emerald-500/10 hover:text-emerald-300"
+ onClick={(e) => {
+ e.stopPropagation();
+ onCompleteTask(taskId);
+ }}
+ />
+ >
+ ) : null}
+
+ {columnId === 'in_progress' ? (
+ <>
+
}
+ className="border-emerald-500/40 text-emerald-400 hover:bg-emerald-500/10 hover:text-emerald-300"
+ onClick={(e) => {
+ e.stopPropagation();
+ onCompleteTask(taskId);
+ }}
+ />
+
+ >
+ ) : null}
+
+ {columnId === 'done' ? (
+ <>
+
}
+ className="border-emerald-500/40 text-emerald-400 hover:bg-emerald-500/10 hover:text-emerald-300"
+ onClick={(e) => {
+ e.stopPropagation();
+ onApprove(taskId);
+ }}
+ />
+
}
+ className="border-violet-500/40 text-violet-400 hover:bg-violet-500/10 hover:text-violet-300"
+ onClick={(e) => {
+ e.stopPropagation();
+ onRequestReview(taskId);
+ }}
+ />
+ >
+ ) : null}
+
+ {columnId === 'review' ? (
+
+ {isReviewManual ? (
+
+ {t('kanban.taskCard.manualReview')}
+
+ ) : null}
+
+ }
+ className="border-emerald-500/40 text-emerald-400 hover:bg-emerald-500/10 hover:text-emerald-300"
+ onClick={(e) => {
+ e.stopPropagation();
+ onApprove(taskId);
+ }}
+ />
+ }
+ variant="destructive"
+ className="bg-red-500/90 text-white hover:bg-red-500"
+ onClick={(e) => {
+ e.stopPropagation();
+ onRequestChanges(taskId);
+ }}
+ />
+
+
+ ) : null}
+
+ {columnId === 'approved' ? (
+
}
+ className="border-amber-500/40 text-amber-400 hover:bg-amber-500/10 hover:text-amber-300"
+ onClick={(e) => {
+ e.stopPropagation();
+ onMoveBackToDone(taskId);
+ }}
+ />
+ ) : null}
+
+ );
+});
+
export const KanbanTaskCard = memo(
function KanbanTaskCard({
task,
@@ -326,48 +528,6 @@ export const KanbanTaskCard = memo(
syncCommentPulse({ taskKey: commentPulseTaskKey, comments });
}, [commentCount, commentPulseTaskKey, comments]);
- const metaActions = (
- <>
- {canOpenChanges ? (
- }
- variant="ghost"
- className={
- changesNeedAttention
- ? 'text-amber-400 hover:bg-amber-500/10 hover:text-amber-300'
- : 'text-sky-400 hover:bg-sky-500/10 hover:text-sky-300'
- }
- onClick={(e) => {
- e.stopPropagation();
- onViewChanges!(task.id);
- }}
- />
- ) : null}
-
- {onDeleteTask ? (
- }
- variant="ghost"
- className="text-red-400 hover:bg-red-500/10 hover:text-red-300"
- onClick={(e) => {
- e.stopPropagation();
- onDeleteTask(task.id);
- }}
- />
- ) : null}
- >
- );
-
return (
-
- {columnId === 'todo' ? (
- <>
-
}
- className="border-emerald-500/40 text-emerald-400 hover:bg-emerald-500/10 hover:text-emerald-300"
- onClick={(e) => {
- e.stopPropagation();
- onStartTask(task.id);
- }}
- />
-
}
- className="border-emerald-500/40 text-emerald-400 hover:bg-emerald-500/10 hover:text-emerald-300"
- onClick={(e) => {
- e.stopPropagation();
- onCompleteTask(task.id);
- }}
- />
- >
- ) : null}
+
- {columnId === 'in_progress' ? (
- <>
-
}
- className="border-emerald-500/40 text-emerald-400 hover:bg-emerald-500/10 hover:text-emerald-300"
- onClick={(e) => {
- e.stopPropagation();
- onCompleteTask(task.id);
- }}
- />
-
- >
- ) : null}
-
- {columnId === 'done' ? (
- <>
-
}
- className="border-emerald-500/40 text-emerald-400 hover:bg-emerald-500/10 hover:text-emerald-300"
- onClick={(e) => {
- e.stopPropagation();
- onApprove(task.id);
- }}
- />
-
}
- className="border-violet-500/40 text-violet-400 hover:bg-violet-500/10 hover:text-violet-300"
- onClick={(e) => {
- e.stopPropagation();
- onRequestReview(task.id);
- }}
- />
- >
- ) : null}
-
- {columnId === 'review' ? (
-
- {isReviewManual ? (
-
- {t('kanban.taskCard.manualReview')}
-
- ) : null}
-
- }
- className="border-emerald-500/40 text-emerald-400 hover:bg-emerald-500/10 hover:text-emerald-300"
- onClick={(e) => {
- e.stopPropagation();
- onApprove(task.id);
- }}
- />
- }
- variant="destructive"
- className="bg-red-500/90 text-white hover:bg-red-500"
- onClick={(e) => {
- e.stopPropagation();
- onRequestChanges(task.id);
- }}
- />
-
-
- ) : null}
-
- {columnId === 'approved' ? (
-
}
- className="border-amber-500/40 text-amber-400 hover:bg-amber-500/10 hover:text-amber-300"
- onClick={(e) => {
- e.stopPropagation();
- onMoveBackToDone(task.id);
- }}
- />
- ) : null}
+
+
-
-
{metaActions}
);