summaryrefslogtreecommitdiff
path: root/apps/mobile/stores/taskStore.ts
blob: 1a08a457ca50442dd01f787b3fce4f2688deafa3 (plain) (blame)
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
import { create } from 'zustand';
import type { TaskSummary, TaskOutputEntry } from '../lib/api';

interface TaskState {
  // Data
  tasks: TaskSummary[];
  selectedTaskId: string | null;
  taskOutputs: Record<string, TaskOutputEntry[]>;

  // Actions
  setTasks: (tasks: TaskSummary[]) => void;
  updateTask: (taskId: string, update: Partial<TaskSummary>) => void;
  selectTask: (taskId: string | null) => void;
  appendOutput: (taskId: string, output: TaskOutputEntry) => void;
  setTaskOutputs: (taskId: string, outputs: TaskOutputEntry[]) => void;
  clearTaskOutputs: (taskId: string) => void;
}

export const useTaskStore = create<TaskState>((set) => ({
  // Initial state
  tasks: [],
  selectedTaskId: null,
  taskOutputs: {},

  // Actions
  setTasks: (tasks) =>
    set({ tasks }),

  updateTask: (taskId, update) =>
    set((state) => ({
      tasks: state.tasks.map((task) =>
        task.id === taskId ? { ...task, ...update } : task
      ),
    })),

  selectTask: (taskId) =>
    set({ selectedTaskId: taskId }),

  appendOutput: (taskId, output) =>
    set((state) => {
      const existing = state.taskOutputs[taskId] ?? [];
      // Avoid duplicates by checking ID
      if (existing.some((o) => o.id === output.id)) {
        return state;
      }
      return {
        taskOutputs: {
          ...state.taskOutputs,
          [taskId]: [...existing, output],
        },
      };
    }),

  setTaskOutputs: (taskId, outputs) =>
    set((state) => ({
      taskOutputs: {
        ...state.taskOutputs,
        [taskId]: outputs,
      },
    })),

  clearTaskOutputs: (taskId) =>
    set((state) => {
      const { [taskId]: _, ...rest } = state.taskOutputs;
      return { taskOutputs: rest };
    }),
}));

// Selectors for common use cases
export const selectSelectedTask = (state: TaskState) =>
  state.tasks.find((t) => t.id === state.selectedTaskId);

export const selectRunningTasks = (state: TaskState) =>
  state.tasks.filter((t) =>
    ['running', 'initializing', 'starting'].includes(t.status)
  );

export const selectPendingTasks = (state: TaskState) =>
  state.tasks.filter((t) => t.status === 'pending');

export const selectCompletedTasks = (state: TaskState) =>
  state.tasks.filter((t) =>
    ['done', 'failed', 'merged'].includes(t.status)
  );