Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 | import type { JSX } from "react";
import type { TaskData } from "../../hooks/types.js";
import styles from "./TaskActionButtons.module.scss";
/** Props for {@link TaskActionButtons}. */
export interface TaskActionButtonsProps {
/** The task whose status drives which buttons are shown. */
task: TaskData;
/** Active session id — required to enable the Pause button. */
sessionId: string | undefined;
/** Whether the task is blocked by incomplete dependencies. */
isBlocked: boolean;
/** Start (or retry) the task. */
onStart: () => void;
/** Resume a paused task. */
onResume: () => void;
/** Stop the task. */
onStop: () => void;
/** Pause the task by killing its session. */
onPause: () => void;
/** Request task deletion (typically opens a confirm dialog). */
onDelete: () => void;
/** Open the task editor. */
onEdit: () => void;
}
/**
* Renders status-appropriate action buttons for a task.
*
* Which buttons appear depends on `task.status` and `isBlocked`.
* Returns `undefined` for unrecognized statuses.
*/
export function TaskActionButtons({
task,
sessionId,
isBlocked,
onStart,
onResume,
onStop,
onPause,
onDelete,
onEdit,
}: TaskActionButtonsProps): JSX.Element | undefined {
if (task.status === "not_started") {
if (isBlocked) {
return (
<div className={styles.actionButtons} data-testid="task-action-buttons">
<button onClick={onEdit} className={styles.btnGhost} data-testid="task-action-edit">
Edit
</button>
<button onClick={onDelete} className={styles.btnDanger} data-testid="task-action-delete">
Delete
</button>
</div>
);
}
return (
<div className={styles.actionButtons} data-testid="task-action-buttons">
<button data-testid="task-header-start" onClick={onStart} className={styles.btnPrimary}>
Start
</button>
<button onClick={onEdit} className={styles.btnGhost} data-testid="task-action-edit">
Edit
</button>
<button onClick={onDelete} className={styles.btnDanger} data-testid="task-action-delete">
Delete
</button>
</div>
);
}
if (task.status === "working") {
return (
<div className={styles.actionButtons} data-testid="task-action-buttons">
<button onClick={onStop} className={styles.btnDanger} data-testid="task-action-stop">
Stop
</button>
<button
onClick={onPause}
disabled={!sessionId}
className={styles.btnGhost}
data-testid="task-action-pause"
>
Pause
</button>
</div>
);
}
if (task.status === "paused") {
return (
<div className={styles.actionButtons} data-testid="task-action-buttons">
<button onClick={onStop} className={styles.btnPrimary} data-testid="task-action-stop">
Stop
</button>
<button onClick={onResume} className={styles.btnGhost} data-testid="task-action-resume">
Resume
</button>
<button onClick={onDelete} className={styles.btnDanger} data-testid="task-action-delete">
Delete
</button>
</div>
);
}
if (task.status === "complete") {
return (
<div className={styles.actionButtons} data-testid="task-action-buttons">
<button onClick={onDelete} className={styles.btnDanger} data-testid="task-action-delete">
Delete
</button>
</div>
);
}
if (task.status === "failed") {
return (
<div className={styles.actionButtons} data-testid="task-action-buttons">
<button onClick={onStart} className={styles.btnPrimary} data-testid="task-header-start">
Retry
</button>
<button onClick={onDelete} className={styles.btnDanger} data-testid="task-action-delete">
Delete
</button>
</div>
);
}
return undefined;
}
|