summaryrefslogtreecommitdiff
path: root/makima/frontend
diff options
context:
space:
mode:
Diffstat (limited to 'makima/frontend')
-rw-r--r--makima/frontend/src/components/mesh/TaskList.tsx38
-rw-r--r--makima/frontend/src/hooks/useTasks.ts17
-rw-r--r--makima/frontend/src/lib/api.ts16
-rw-r--r--makima/frontend/src/routes/mesh.tsx10
4 files changed, 69 insertions, 12 deletions
diff --git a/makima/frontend/src/components/mesh/TaskList.tsx b/makima/frontend/src/components/mesh/TaskList.tsx
index e3f2862..016fef5 100644
--- a/makima/frontend/src/components/mesh/TaskList.tsx
+++ b/makima/frontend/src/components/mesh/TaskList.tsx
@@ -6,6 +6,7 @@ interface TaskListProps {
loading: boolean;
onSelect: (id: string) => void;
onDelete: (id: string) => void;
+ onDismiss: (id: string) => void;
onCreate: () => void;
}
@@ -88,6 +89,7 @@ export function TaskList({
loading,
onSelect,
onDelete,
+ onDismiss,
onCreate,
}: TaskListProps) {
// Filter state - default to 'active' to show only active contracts
@@ -300,17 +302,31 @@ export function TaskList({
</div>
</button>
{/* Supervisor tasks cannot be deleted directly - they are deleted with the contract */}
- {!task.isSupervisor && (
- <button
- onClick={(e) => {
- e.stopPropagation();
- onDelete(task.id);
- }}
- className="px-2 py-1 font-mono text-[10px] text-red-400 hover:bg-red-400/10 border border-red-400/30 hover:border-red-400/50 transition-colors uppercase"
- >
- Delete
- </button>
- )}
+ <div className="flex gap-2">
+ {/* Show dismiss button for completed standalone tasks (tasks without a contract) */}
+ {!task.contractId && (task.status === "done" || task.status === "failed" || task.status === "merged") && (
+ <button
+ onClick={(e) => {
+ e.stopPropagation();
+ onDismiss(task.id);
+ }}
+ className="px-2 py-1 font-mono text-[10px] text-[#8b949e] hover:bg-[rgba(117,170,252,0.1)] border border-[rgba(117,170,252,0.25)] hover:border-[#3f6fb3] transition-colors uppercase"
+ >
+ Dismiss
+ </button>
+ )}
+ {!task.isSupervisor && (
+ <button
+ onClick={(e) => {
+ e.stopPropagation();
+ onDelete(task.id);
+ }}
+ className="px-2 py-1 font-mono text-[10px] text-red-400 hover:bg-red-400/10 border border-red-400/30 hover:border-red-400/50 transition-colors uppercase"
+ >
+ Delete
+ </button>
+ )}
+ </div>
</div>
</div>
))}
diff --git a/makima/frontend/src/hooks/useTasks.ts b/makima/frontend/src/hooks/useTasks.ts
index 6e6c992..4667c4c 100644
--- a/makima/frontend/src/hooks/useTasks.ts
+++ b/makima/frontend/src/hooks/useTasks.ts
@@ -5,6 +5,7 @@ import {
createTask,
updateTask,
deleteTask,
+ dismissTask,
VersionConflictError,
type TaskSummary,
type TaskWithSubtasks,
@@ -110,6 +111,21 @@ export function useTasks() {
[fetchTasks]
);
+ const hideTask = useCallback(
+ async (id: string): Promise<boolean> => {
+ setError(null);
+ try {
+ await dismissTask(id);
+ await fetchTasks(); // Refresh list
+ return true;
+ } catch (e) {
+ setError(e instanceof Error ? e.message : "Failed to dismiss task");
+ return false;
+ }
+ },
+ [fetchTasks]
+ );
+
// Initial fetch
useEffect(() => {
fetchTasks();
@@ -126,5 +142,6 @@ export function useTasks() {
saveTask,
editTask,
removeTask,
+ hideTask,
};
}
diff --git a/makima/frontend/src/lib/api.ts b/makima/frontend/src/lib/api.ts
index aeaa218..76ee4d4 100644
--- a/makima/frontend/src/lib/api.ts
+++ b/makima/frontend/src/lib/api.ts
@@ -543,6 +543,8 @@ export interface TaskSummary {
subtaskCount: number;
/** Whether this is a supervisor task (contract orchestrator) */
isSupervisor: boolean;
+ /** Whether this task is hidden from the UI (user dismissed it) */
+ hidden: boolean;
version: number;
createdAt: string;
updatedAt: string;
@@ -639,6 +641,8 @@ export interface UpdateTaskRequest {
targetRepoPath?: string;
/** Action on completion: "none", "branch", "merge", "pr" */
completionAction?: CompletionAction;
+ /** Whether this task is hidden from the UI (user dismissed it) */
+ hidden?: boolean;
version?: number;
}
@@ -2657,3 +2661,15 @@ export function getSupervisorStatus(
canResume,
};
}
+
+// =============================================================================
+// Task Dismiss (Hide) Functions
+// =============================================================================
+
+/**
+ * Dismiss (hide) a completed standalone task from the UI.
+ * This marks the task as hidden so it won't appear in the task list.
+ */
+export async function dismissTask(taskId: string): Promise<Task> {
+ return updateTask(taskId, { hidden: true });
+}
diff --git a/makima/frontend/src/routes/mesh.tsx b/makima/frontend/src/routes/mesh.tsx
index 425721d..fb366a2 100644
--- a/makima/frontend/src/routes/mesh.tsx
+++ b/makima/frontend/src/routes/mesh.tsx
@@ -81,7 +81,7 @@ export default function MeshPage() {
const { id } = useParams<{ id: string }>();
const navigate = useNavigate();
const { isAuthenticated, isAuthConfigured, isLoading: authLoading } = useAuth();
- const { tasks, loading, error, conflict, clearConflict, fetchTask, fetchTasks, editTask, removeTask, saveTask } = useTasks();
+ const { tasks, loading, error, conflict, clearConflict, fetchTask, fetchTasks, editTask, removeTask, hideTask, saveTask } = useTasks();
const { pendingQuestions, submitAnswer } = useSupervisorQuestions();
// Memoize pending question IDs for efficient lookup
@@ -408,6 +408,13 @@ export default function MeshPage() {
[removeTask, id, taskDetail, navigate]
);
+ const handleDismiss = useCallback(
+ async (taskId: string) => {
+ await hideTask(taskId);
+ },
+ [hideTask]
+ );
+
const handleStart = useCallback(
async (taskId: string) => {
try {
@@ -868,6 +875,7 @@ export default function MeshPage() {
loading={loading || creating}
onSelect={handleSelectTask}
onDelete={handleDelete}
+ onDismiss={handleDismiss}
onCreate={handleCreate}
/>
</div>