feat: add dependencies section to TaskDetailDialog for improved task management
- Implemented a new section in TaskDetailDialog to display tasks that are blocked by or blocking the current task, enhancing visibility of task dependencies. - Added interactive buttons for each dependency, allowing users to quickly access related tasks. - Updated review information display to streamline task review context, improving user experience.
This commit is contained in:
parent
33ba4bdeab
commit
8d97c53cb4
1 changed files with 88 additions and 93 deletions
|
|
@ -818,6 +818,83 @@ export const TaskDetailDialog = ({
|
||||||
|
|
||||||
{/* Sections container with uniform spacing */}
|
{/* Sections container with uniform spacing */}
|
||||||
<div className="min-w-0 space-y-1">
|
<div className="min-w-0 space-y-1">
|
||||||
|
{/* Dependencies */}
|
||||||
|
{blockedByIds.length > 0 || blocksIds.length > 0 ? (
|
||||||
|
<div className="space-y-1">
|
||||||
|
{blockedByIds.length > 0 ? (
|
||||||
|
<div className="flex flex-wrap items-center gap-1.5">
|
||||||
|
<span className="inline-flex items-center gap-0.5 text-xs text-yellow-300">
|
||||||
|
<ArrowLeftFromLine size={12} />
|
||||||
|
Blocked by
|
||||||
|
</span>
|
||||||
|
{blockedByIds.map((id) => {
|
||||||
|
const depTask = taskMap.get(id);
|
||||||
|
const isCompleted = depTask?.status === 'completed';
|
||||||
|
const label = depTask
|
||||||
|
? `${formatTaskDisplayLabel(depTask)}: ${depTask.subject}`
|
||||||
|
: `#${deriveTaskDisplayId(id)}`;
|
||||||
|
return (
|
||||||
|
<Tooltip key={id}>
|
||||||
|
<TooltipTrigger asChild>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
className={`inline-flex items-center rounded px-1.5 py-0.5 text-[10px] font-medium transition-colors ${
|
||||||
|
isCompleted
|
||||||
|
? 'bg-emerald-500/15 text-emerald-400 hover:bg-emerald-500/25'
|
||||||
|
: 'bg-yellow-500/15 text-yellow-300 hover:bg-yellow-500/25'
|
||||||
|
} cursor-pointer`}
|
||||||
|
onClick={() => handleDependencyClick(id)}
|
||||||
|
>
|
||||||
|
{depTask
|
||||||
|
? formatTaskDisplayLabel(depTask)
|
||||||
|
: `#${deriveTaskDisplayId(id)}`}
|
||||||
|
</button>
|
||||||
|
</TooltipTrigger>
|
||||||
|
<TooltipContent side="bottom">{label}</TooltipContent>
|
||||||
|
</Tooltip>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
) : null}
|
||||||
|
|
||||||
|
{blocksIds.length > 0 ? (
|
||||||
|
<div className="flex flex-wrap items-center gap-1.5">
|
||||||
|
<span className="inline-flex items-center gap-0.5 text-xs text-blue-400">
|
||||||
|
<ArrowRightFromLine size={12} />
|
||||||
|
Blocks
|
||||||
|
</span>
|
||||||
|
{blocksIds.map((id) => {
|
||||||
|
const depTask = taskMap.get(id);
|
||||||
|
const isCompleted = depTask?.status === 'completed';
|
||||||
|
const label = depTask
|
||||||
|
? `${formatTaskDisplayLabel(depTask)}: ${depTask.subject}`
|
||||||
|
: `#${deriveTaskDisplayId(id)}`;
|
||||||
|
return (
|
||||||
|
<Tooltip key={id}>
|
||||||
|
<TooltipTrigger asChild>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
className={`inline-flex items-center rounded px-1.5 py-0.5 text-[10px] font-medium transition-colors ${
|
||||||
|
isCompleted
|
||||||
|
? 'bg-emerald-500/15 text-emerald-400 hover:bg-emerald-500/25'
|
||||||
|
: 'bg-blue-500/15 text-blue-400 hover:bg-blue-500/25'
|
||||||
|
} cursor-pointer`}
|
||||||
|
onClick={() => handleDependencyClick(id)}
|
||||||
|
>
|
||||||
|
{depTask
|
||||||
|
? formatTaskDisplayLabel(depTask)
|
||||||
|
: `#${deriveTaskDisplayId(id)}`}
|
||||||
|
</button>
|
||||||
|
</TooltipTrigger>
|
||||||
|
<TooltipContent side="bottom">{label}</TooltipContent>
|
||||||
|
</Tooltip>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
) : null}
|
||||||
|
</div>
|
||||||
|
) : null}
|
||||||
|
|
||||||
{/* Description */}
|
{/* Description */}
|
||||||
<CollapsibleTeamSection
|
<CollapsibleTeamSection
|
||||||
title="Description"
|
title="Description"
|
||||||
|
|
@ -1130,101 +1207,19 @@ export const TaskDetailDialog = ({
|
||||||
</CollapsibleTeamSection>
|
</CollapsibleTeamSection>
|
||||||
) : null}
|
) : null}
|
||||||
|
|
||||||
{blockedByIds.length > 0 ||
|
{/* Review info */}
|
||||||
blocksIds.length > 0 ||
|
{kanbanTaskState?.reviewer || kanbanTaskState?.errorDescription ? (
|
||||||
relatedIds.length > 0 ||
|
|
||||||
relatedByIds.length > 0 ||
|
|
||||||
kanbanTaskState?.reviewer ||
|
|
||||||
kanbanTaskState?.errorDescription ? (
|
|
||||||
<div className="space-y-1">
|
<div className="space-y-1">
|
||||||
{/* Dependencies */}
|
<div className="flex items-center gap-2">
|
||||||
{blockedByIds.length > 0 ? (
|
{kanbanTaskState.reviewer ? (
|
||||||
<div className="flex flex-wrap items-center gap-1.5">
|
<span className="text-xs text-[var(--color-text-secondary)]">
|
||||||
<span className="inline-flex items-center gap-0.5 text-xs text-yellow-300">
|
Reviewer: {kanbanTaskState.reviewer}
|
||||||
<ArrowLeftFromLine size={12} />
|
|
||||||
Blocked by
|
|
||||||
</span>
|
</span>
|
||||||
{blockedByIds.map((id) => {
|
) : null}
|
||||||
const depTask = taskMap.get(id);
|
{kanbanTaskState.errorDescription ? (
|
||||||
const isCompleted = depTask?.status === 'completed';
|
<span className="text-xs text-red-400">{kanbanTaskState.errorDescription}</span>
|
||||||
const label = depTask
|
) : null}
|
||||||
? `${formatTaskDisplayLabel(depTask)}: ${depTask.subject}`
|
</div>
|
||||||
: `#${deriveTaskDisplayId(id)}`;
|
|
||||||
return (
|
|
||||||
<Tooltip key={id}>
|
|
||||||
<TooltipTrigger asChild>
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
className={`inline-flex items-center rounded px-1.5 py-0.5 text-[10px] font-medium transition-colors ${
|
|
||||||
isCompleted
|
|
||||||
? 'bg-emerald-500/15 text-emerald-400 hover:bg-emerald-500/25'
|
|
||||||
: 'bg-yellow-500/15 text-yellow-300 hover:bg-yellow-500/25'
|
|
||||||
} cursor-pointer`}
|
|
||||||
onClick={() => handleDependencyClick(id)}
|
|
||||||
>
|
|
||||||
{depTask
|
|
||||||
? formatTaskDisplayLabel(depTask)
|
|
||||||
: `#${deriveTaskDisplayId(id)}`}
|
|
||||||
</button>
|
|
||||||
</TooltipTrigger>
|
|
||||||
<TooltipContent side="bottom">{label}</TooltipContent>
|
|
||||||
</Tooltip>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</div>
|
|
||||||
) : null}
|
|
||||||
|
|
||||||
{blocksIds.length > 0 ? (
|
|
||||||
<div className="flex flex-wrap items-center gap-1.5">
|
|
||||||
<span className="inline-flex items-center gap-0.5 text-xs text-blue-400">
|
|
||||||
<ArrowRightFromLine size={12} />
|
|
||||||
Blocks
|
|
||||||
</span>
|
|
||||||
{blocksIds.map((id) => {
|
|
||||||
const depTask = taskMap.get(id);
|
|
||||||
const isCompleted = depTask?.status === 'completed';
|
|
||||||
const label = depTask
|
|
||||||
? `${formatTaskDisplayLabel(depTask)}: ${depTask.subject}`
|
|
||||||
: `#${deriveTaskDisplayId(id)}`;
|
|
||||||
return (
|
|
||||||
<Tooltip key={id}>
|
|
||||||
<TooltipTrigger asChild>
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
className={`inline-flex items-center rounded px-1.5 py-0.5 text-[10px] font-medium transition-colors ${
|
|
||||||
isCompleted
|
|
||||||
? 'bg-emerald-500/15 text-emerald-400 hover:bg-emerald-500/25'
|
|
||||||
: 'bg-blue-500/15 text-blue-400 hover:bg-blue-500/25'
|
|
||||||
} cursor-pointer`}
|
|
||||||
onClick={() => handleDependencyClick(id)}
|
|
||||||
>
|
|
||||||
{depTask
|
|
||||||
? formatTaskDisplayLabel(depTask)
|
|
||||||
: `#${deriveTaskDisplayId(id)}`}
|
|
||||||
</button>
|
|
||||||
</TooltipTrigger>
|
|
||||||
<TooltipContent side="bottom">{label}</TooltipContent>
|
|
||||||
</Tooltip>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</div>
|
|
||||||
) : null}
|
|
||||||
|
|
||||||
{/* Review info */}
|
|
||||||
{kanbanTaskState?.reviewer || kanbanTaskState?.errorDescription ? (
|
|
||||||
<div className="flex items-center gap-2">
|
|
||||||
{kanbanTaskState.reviewer ? (
|
|
||||||
<span className="text-xs text-[var(--color-text-secondary)]">
|
|
||||||
Reviewer: {kanbanTaskState.reviewer}
|
|
||||||
</span>
|
|
||||||
) : null}
|
|
||||||
{kanbanTaskState.errorDescription ? (
|
|
||||||
<span className="text-xs text-red-400">
|
|
||||||
{kanbanTaskState.errorDescription}
|
|
||||||
</span>
|
|
||||||
) : null}
|
|
||||||
</div>
|
|
||||||
) : null}
|
|
||||||
</div>
|
</div>
|
||||||
) : null}
|
) : null}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue