1mod change_set;
2pub(crate) use change_set::{ChangeSetOperation, IndexedChangeSetError};
3pub use change_set::{ChangeSetOutcome, ChangeTarget, CreatedTaskRef};
4mod attachment_creation;
5mod consumer;
6mod creation;
7mod mutation;
8mod notes;
9
10use crate::choices::TaskSource;
11use crate::ids::TaskId;
12use crate::labels::CreatedLabel;
13use crate::metadata::TaskMetadataInput;
14use crate::types::Task;
15use crate::undo::TaskUndoSnapshot;
16
17pub struct TaskDraft {
18 pub title: String,
19 pub description: String,
20 pub project: Option<String>,
21 pub status: String,
22 pub priority: String,
23 pub source: TaskSource,
24 pub labels: Vec<String>,
25 pub metadata: Vec<TaskMetadataInput>,
26 pub available_at: Option<String>,
27 pub due_on: Option<String>,
28 pub is_epic: bool,
29}
30
31#[derive(Debug, Clone, Default)]
32pub enum TaskCreationUndo {
33 #[default]
34 None,
35 TuiTask,
36 TuiEpicChild {
37 epic_id: TaskId,
38 },
39}
40
41#[derive(Debug, Clone)]
42pub struct TaskCreationOptions {
43 epic_id: Option<TaskId>,
44 undo: TaskCreationUndo,
45 create_missing_labels: bool,
46 require_existing_project: bool,
47 capture_undo_snapshot: bool,
48 require_existing_epic: bool,
49}
50
51impl TaskCreationOptions {
52 pub fn standalone(undo: TaskCreationUndo) -> Self {
53 Self {
54 epic_id: None,
55 undo,
56 create_missing_labels: false,
57 require_existing_project: false,
58 capture_undo_snapshot: false,
59 require_existing_epic: false,
60 }
61 }
62
63 pub fn for_epic(epic_id: TaskId, undo: TaskCreationUndo) -> Self {
64 Self {
65 epic_id: Some(epic_id),
66 undo,
67 create_missing_labels: false,
68 require_existing_project: false,
69 capture_undo_snapshot: false,
70 require_existing_epic: false,
71 }
72 }
73
74 pub fn with_create_missing_labels(mut self) -> Self {
75 self.create_missing_labels = true;
76 self
77 }
78
79 pub(crate) fn for_consumer_epic(epic_id: Option<TaskId>) -> Self {
80 Self {
81 epic_id,
82 undo: TaskCreationUndo::None,
83 create_missing_labels: false,
84 require_existing_project: true,
85 capture_undo_snapshot: false,
86 require_existing_epic: true,
87 }
88 }
89
90 pub fn for_consumer_capture() -> Self {
91 Self {
92 epic_id: None,
93 undo: TaskCreationUndo::None,
94 create_missing_labels: false,
95 require_existing_project: true,
96 capture_undo_snapshot: true,
97 require_existing_epic: false,
98 }
99 }
100}
101
102#[derive(Debug)]
103pub struct TaskOutcome {
104 pub task: Task,
105 pub create_change_id: Option<String>,
106 pub attachment_change_ids: Vec<String>,
107 pub undo_snapshot: Option<TaskUndoSnapshot>,
108}
109
110struct InsertedTask {
111 id: TaskId,
112 change_id: String,
113 project_key: String,
114 label_count: usize,
115 created_labels: Vec<CreatedLabel>,
116}
117
118#[derive(Debug, Clone)]
119pub struct TaskLabelSelection {
120 pub selected: Vec<String>,
121 pub partial: Vec<String>,
122}
123
124#[derive(Clone, Default)]
125pub struct TaskUpdate {
126 pub title: Option<String>,
127 pub description: Option<String>,
128 pub project: Option<String>,
129 pub status: Option<String>,
130 pub priority: Option<String>,
131 pub cycle_priority: Option<bool>,
132 pub available_at: Option<Option<String>>,
133 pub due_on: Option<Option<String>>,
134 pub deleted: Option<bool>,
135 pub is_epic: Option<bool>,
136 pub add_labels: Vec<String>,
137 pub remove_labels: Vec<String>,
138 pub set_metadata: Vec<TaskMetadataInput>,
139 pub remove_metadata: Vec<String>,
140 pub require_metadata_fields: Vec<(crate::ids::MetadataFieldId, String)>,
141 pub label_selection: Option<TaskLabelSelection>,
142 pub create_missing_labels: bool,
143}
144
145pub struct TaskUpdateOutcome {
146 pub task: Task,
147 pub changed: bool,
148}
149
150#[derive(Debug)]
151pub struct TaskMutationOutcome {
152 pub task: Task,
153 pub before: TaskUndoSnapshot,
154 pub after: TaskUndoSnapshot,
155 pub changed: bool,
156}
157
158#[derive(Debug)]
159pub struct TaskMutationReport {
160 pub outcomes: Vec<TaskMutationOutcome>,
161}
162
163impl TaskMutationReport {
164 pub fn changed_count(&self) -> usize {
165 self.outcomes
166 .iter()
167 .filter(|outcome| outcome.changed)
168 .count()
169 }
170}
171
172pub struct NoteEditOutcome {
173 #[allow(dead_code)]
174 pub task_id: TaskId,
175 #[allow(dead_code)]
176 pub note_id: String,
177 pub found: bool,
178 pub changed: bool,
179}
180
181pub struct NoteDeleteOutcome {
182 #[allow(dead_code)]
183 pub task_id: TaskId,
184 #[allow(dead_code)]
185 pub note_id: String,
186 pub changed: bool,
187}
188
189pub struct NoteOutcome {
190 #[allow(dead_code)]
191 pub task_id: TaskId,
192 pub note_id: String,
193 pub change_id: String,
194}
195
196pub(crate) use consumer::ConsumerTaskMutation;
197#[cfg(any(test, feature = "test-support"))]
198pub(crate) use creation::create_task;
199#[cfg(any(test, feature = "test-support"))]
200pub(crate) use mutation::update_task;
201pub(crate) use mutation::update_task_labels_in_workspace;
202#[cfg(test)]
203pub(in crate::operations) use notes::add_note_operation;