@baack-software/baack-ts-tasks 0.0.0-stage → 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (229) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +158 -2
  3. package/dist/activity.d.ts +20 -0
  4. package/dist/activity.d.ts.map +1 -0
  5. package/dist/activity.js +75 -0
  6. package/dist/activity.js.map +1 -0
  7. package/dist/blockers.d.ts +28 -0
  8. package/dist/blockers.d.ts.map +1 -0
  9. package/dist/blockers.js +134 -0
  10. package/dist/blockers.js.map +1 -0
  11. package/dist/conflicts.d.ts +50 -0
  12. package/dist/conflicts.d.ts.map +1 -0
  13. package/dist/conflicts.js +73 -0
  14. package/dist/conflicts.js.map +1 -0
  15. package/dist/draft.d.ts +45 -0
  16. package/dist/draft.d.ts.map +1 -0
  17. package/dist/draft.js +155 -0
  18. package/dist/draft.js.map +1 -0
  19. package/dist/errors.d.ts +30 -0
  20. package/dist/errors.d.ts.map +1 -0
  21. package/dist/errors.js +37 -0
  22. package/dist/errors.js.map +1 -0
  23. package/dist/index.d.ts +11 -0
  24. package/dist/index.d.ts.map +1 -0
  25. package/dist/index.js +11 -0
  26. package/dist/index.js.map +1 -0
  27. package/dist/react/TaskActivity.d.ts +15 -0
  28. package/dist/react/TaskActivity.d.ts.map +1 -0
  29. package/dist/react/TaskActivity.js +60 -0
  30. package/dist/react/TaskActivity.js.map +1 -0
  31. package/dist/react/TaskBoard.d.ts +38 -0
  32. package/dist/react/TaskBoard.d.ts.map +1 -0
  33. package/dist/react/TaskBoard.js +85 -0
  34. package/dist/react/TaskBoard.js.map +1 -0
  35. package/dist/react/TaskConflicts.d.ts +26 -0
  36. package/dist/react/TaskConflicts.d.ts.map +1 -0
  37. package/dist/react/TaskConflicts.js +87 -0
  38. package/dist/react/TaskConflicts.js.map +1 -0
  39. package/dist/react/TaskCreateForm.d.ts +13 -0
  40. package/dist/react/TaskCreateForm.d.ts.map +1 -0
  41. package/dist/react/TaskCreateForm.js +68 -0
  42. package/dist/react/TaskCreateForm.js.map +1 -0
  43. package/dist/react/TaskEditor.d.ts +33 -0
  44. package/dist/react/TaskEditor.d.ts.map +1 -0
  45. package/dist/react/TaskEditor.js +172 -0
  46. package/dist/react/TaskEditor.js.map +1 -0
  47. package/dist/react/TaskFilters.d.ts +15 -0
  48. package/dist/react/TaskFilters.d.ts.map +1 -0
  49. package/dist/react/TaskFilters.js +48 -0
  50. package/dist/react/TaskFilters.js.map +1 -0
  51. package/dist/react/TaskView.d.ts +30 -0
  52. package/dist/react/TaskView.d.ts.map +1 -0
  53. package/dist/react/TaskView.js +108 -0
  54. package/dist/react/TaskView.js.map +1 -0
  55. package/dist/react/TasksAbout.d.ts +24 -0
  56. package/dist/react/TasksAbout.d.ts.map +1 -0
  57. package/dist/react/TasksAbout.js +82 -0
  58. package/dist/react/TasksAbout.js.map +1 -0
  59. package/dist/react/copy.d.ts +154 -0
  60. package/dist/react/copy.d.ts.map +1 -0
  61. package/dist/react/copy.js +173 -0
  62. package/dist/react/copy.js.map +1 -0
  63. package/dist/react/fields.d.ts +36 -0
  64. package/dist/react/fields.d.ts.map +1 -0
  65. package/dist/react/fields.js +21 -0
  66. package/dist/react/fields.js.map +1 -0
  67. package/dist/react/hooks.d.ts +9 -0
  68. package/dist/react/hooks.d.ts.map +1 -0
  69. package/dist/react/hooks.js +31 -0
  70. package/dist/react/hooks.js.map +1 -0
  71. package/dist/react/index.d.ts +13 -0
  72. package/dist/react/index.d.ts.map +1 -0
  73. package/dist/react/index.js +13 -0
  74. package/dist/react/index.js.map +1 -0
  75. package/dist/react/parts.d.ts +55 -0
  76. package/dist/react/parts.d.ts.map +1 -0
  77. package/dist/react/parts.js +92 -0
  78. package/dist/react/parts.js.map +1 -0
  79. package/dist/react/ui/alert.d.ts +11 -0
  80. package/dist/react/ui/alert.d.ts.map +1 -0
  81. package/dist/react/ui/alert.js +29 -0
  82. package/dist/react/ui/alert.js.map +1 -0
  83. package/dist/react/ui/avatar.d.ts +12 -0
  84. package/dist/react/ui/avatar.d.ts.map +1 -0
  85. package/dist/react/ui/avatar.js +24 -0
  86. package/dist/react/ui/avatar.js.map +1 -0
  87. package/dist/react/ui/badge.d.ts +10 -0
  88. package/dist/react/ui/badge.d.ts.map +1 -0
  89. package/dist/react/ui/badge.js +26 -0
  90. package/dist/react/ui/badge.js.map +1 -0
  91. package/dist/react/ui/button.d.ts +11 -0
  92. package/dist/react/ui/button.d.ts.map +1 -0
  93. package/dist/react/ui/button.js +37 -0
  94. package/dist/react/ui/button.js.map +1 -0
  95. package/dist/react/ui/card.d.ts +12 -0
  96. package/dist/react/ui/card.d.ts.map +1 -0
  97. package/dist/react/ui/card.js +26 -0
  98. package/dist/react/ui/card.js.map +1 -0
  99. package/dist/react/ui/input.d.ts +4 -0
  100. package/dist/react/ui/input.d.ts.map +1 -0
  101. package/dist/react/ui/input.js +8 -0
  102. package/dist/react/ui/input.js.map +1 -0
  103. package/dist/react/ui/label.d.ts +5 -0
  104. package/dist/react/ui/label.d.ts.map +1 -0
  105. package/dist/react/ui/label.js +10 -0
  106. package/dist/react/ui/label.js.map +1 -0
  107. package/dist/react/ui/radio-group.d.ts +6 -0
  108. package/dist/react/ui/radio-group.d.ts.map +1 -0
  109. package/dist/react/ui/radio-group.js +12 -0
  110. package/dist/react/ui/radio-group.js.map +1 -0
  111. package/dist/react/ui/select.d.ts +16 -0
  112. package/dist/react/ui/select.d.ts.map +1 -0
  113. package/dist/react/ui/select.js +37 -0
  114. package/dist/react/ui/select.js.map +1 -0
  115. package/dist/react/ui/separator.d.ts +5 -0
  116. package/dist/react/ui/separator.d.ts.map +1 -0
  117. package/dist/react/ui/separator.js +10 -0
  118. package/dist/react/ui/separator.js.map +1 -0
  119. package/dist/react/ui/sheet.d.ts +15 -0
  120. package/dist/react/ui/sheet.d.ts.map +1 -0
  121. package/dist/react/ui/sheet.js +38 -0
  122. package/dist/react/ui/sheet.js.map +1 -0
  123. package/dist/react/ui/skeleton.d.ts +3 -0
  124. package/dist/react/ui/skeleton.d.ts.map +1 -0
  125. package/dist/react/ui/skeleton.js +7 -0
  126. package/dist/react/ui/skeleton.js.map +1 -0
  127. package/dist/react/ui/table.d.ts +11 -0
  128. package/dist/react/ui/table.d.ts.map +1 -0
  129. package/dist/react/ui/table.js +29 -0
  130. package/dist/react/ui/table.js.map +1 -0
  131. package/dist/react/ui/tabs.d.ts +12 -0
  132. package/dist/react/ui/tabs.d.ts.map +1 -0
  133. package/dist/react/ui/tabs.js +31 -0
  134. package/dist/react/ui/tabs.js.map +1 -0
  135. package/dist/react/ui/textarea.d.ts +4 -0
  136. package/dist/react/ui/textarea.d.ts.map +1 -0
  137. package/dist/react/ui/textarea.js +8 -0
  138. package/dist/react/ui/textarea.js.map +1 -0
  139. package/dist/react/ui/toggle-group.d.ts +11 -0
  140. package/dist/react/ui/toggle-group.d.ts.map +1 -0
  141. package/dist/react/ui/toggle-group.js +25 -0
  142. package/dist/react/ui/toggle-group.js.map +1 -0
  143. package/dist/react/ui/toggle.d.ts +10 -0
  144. package/dist/react/ui/toggle.d.ts.map +1 -0
  145. package/dist/react/ui/toggle.js +27 -0
  146. package/dist/react/ui/toggle.js.map +1 -0
  147. package/dist/refs.d.ts +16 -0
  148. package/dist/refs.d.ts.map +1 -0
  149. package/dist/refs.js +43 -0
  150. package/dist/refs.js.map +1 -0
  151. package/dist/server/index.d.ts +4 -0
  152. package/dist/server/index.d.ts.map +1 -0
  153. package/dist/server/index.js +4 -0
  154. package/dist/server/index.js.map +1 -0
  155. package/dist/server/recipes.d.ts +39 -0
  156. package/dist/server/recipes.d.ts.map +1 -0
  157. package/dist/server/recipes.js +81 -0
  158. package/dist/server/recipes.js.map +1 -0
  159. package/dist/server/webhooks.d.ts +135 -0
  160. package/dist/server/webhooks.d.ts.map +1 -0
  161. package/dist/server/webhooks.js +243 -0
  162. package/dist/server/webhooks.js.map +1 -0
  163. package/dist/store.d.ts +124 -0
  164. package/dist/store.d.ts.map +1 -0
  165. package/dist/store.js +443 -0
  166. package/dist/store.js.map +1 -0
  167. package/dist/task-client.d.ts +137 -0
  168. package/dist/task-client.d.ts.map +1 -0
  169. package/dist/task-client.js +271 -0
  170. package/dist/task-client.js.map +1 -0
  171. package/dist/tasks.d.ts +84 -0
  172. package/dist/tasks.d.ts.map +1 -0
  173. package/dist/tasks.js +208 -0
  174. package/dist/tasks.js.map +1 -0
  175. package/dist/time.d.ts +15 -0
  176. package/dist/time.d.ts.map +1 -0
  177. package/dist/time.js +34 -0
  178. package/dist/time.js.map +1 -0
  179. package/dist/types.d.ts +74 -0
  180. package/dist/types.d.ts.map +1 -0
  181. package/dist/types.js +9 -0
  182. package/dist/types.js.map +1 -0
  183. package/package.json +101 -4
  184. package/src/activity.ts +86 -0
  185. package/src/blockers.ts +134 -0
  186. package/src/conflicts.ts +115 -0
  187. package/src/draft.ts +162 -0
  188. package/src/errors.ts +40 -0
  189. package/src/index.ts +10 -0
  190. package/src/react/TaskActivity.tsx +187 -0
  191. package/src/react/TaskBoard.tsx +264 -0
  192. package/src/react/TaskConflicts.tsx +217 -0
  193. package/src/react/TaskCreateForm.tsx +165 -0
  194. package/src/react/TaskEditor.tsx +485 -0
  195. package/src/react/TaskFilters.tsx +122 -0
  196. package/src/react/TaskView.tsx +291 -0
  197. package/src/react/TasksAbout.tsx +226 -0
  198. package/src/react/copy.tsx +253 -0
  199. package/src/react/fields.tsx +104 -0
  200. package/src/react/hooks.ts +41 -0
  201. package/src/react/index.ts +12 -0
  202. package/src/react/parts.tsx +176 -0
  203. package/src/react/ui/README.md +6 -0
  204. package/src/react/ui/alert.tsx +75 -0
  205. package/src/react/ui/avatar.tsx +109 -0
  206. package/src/react/ui/badge.tsx +48 -0
  207. package/src/react/ui/button.tsx +66 -0
  208. package/src/react/ui/card.tsx +102 -0
  209. package/src/react/ui/input.tsx +18 -0
  210. package/src/react/ui/label.tsx +23 -0
  211. package/src/react/ui/radio-group.tsx +41 -0
  212. package/src/react/ui/select.tsx +189 -0
  213. package/src/react/ui/separator.tsx +27 -0
  214. package/src/react/ui/sheet.tsx +145 -0
  215. package/src/react/ui/skeleton.tsx +13 -0
  216. package/src/react/ui/table.tsx +113 -0
  217. package/src/react/ui/tabs.tsx +89 -0
  218. package/src/react/ui/textarea.tsx +17 -0
  219. package/src/react/ui/toggle-group.tsx +89 -0
  220. package/src/react/ui/toggle.tsx +44 -0
  221. package/src/refs.ts +49 -0
  222. package/src/server/index.ts +3 -0
  223. package/src/server/recipes.ts +107 -0
  224. package/src/server/webhooks.ts +369 -0
  225. package/src/store.ts +538 -0
  226. package/src/task-client.ts +373 -0
  227. package/src/tasks.ts +263 -0
  228. package/src/time.ts +35 -0
  229. package/src/types.ts +101 -0
@@ -0,0 +1,271 @@
1
+ import { Endpoint, isBaackApiError, } from '@baack-software/baack-ts-client';
2
+ import { draft as makeDraft, isEmptyChange, updateBody, validateTask } from "./draft.js";
3
+ import { changedFields, fieldsChanged, findConflicts, rebaseLists } from "./conflicts.js";
4
+ import { TaskConflictError, TaskSearchTimeoutError, TaskValidationError } from "./errors.js";
5
+ import { ref, urnOf, withRef, withoutRef } from "./refs.js";
6
+ import { TASK_LIST_FIELDS } from "./types.js";
7
+ /**
8
+ * Typed access to Baack tasks and their activity logs, on top of a `BaackClient` that holds the base URL and
9
+ * credentials.
10
+ *
11
+ * ```ts
12
+ * const tasks = new TaskClient(new BaackClient({ baseUrl: 'https://api.baack.co', credentials: 'include' }));
13
+ * const { tasks: all } = await tasks.list({ owner: companyUrn });
14
+ * await tasks.setStatus(all[0], 'IN_PROGRESS', { actor: me });
15
+ * ```
16
+ */
17
+ export class TaskClient {
18
+ client;
19
+ constructor(client) {
20
+ this.client = client;
21
+ }
22
+ // ==========================================
23
+ // TASKS
24
+ // ==========================================
25
+ async get(task) {
26
+ return this.client.read(Endpoint.TASK, urnOf(task));
27
+ }
28
+ /** Reads a workflow: its name and its stages, which tasks move through. */
29
+ async getWorkflow(workflow) {
30
+ return this.client.read(Endpoint.WORKFLOW, urnOf(workflow));
31
+ }
32
+ /**
33
+ * Creates a task. Accepts a full `TaskDraft`, or the owner and title plus any other fields, which `draft` fills in.
34
+ * Throws `TaskValidationError` before sending when the task breaks the API's rules.
35
+ */
36
+ async create(input, options = {}) {
37
+ const body = withActor(makeDraft(input), options);
38
+ const issues = validateTask(body, { creating: true });
39
+ if (issues.length > 0)
40
+ throw new TaskValidationError(issues);
41
+ return this.client.create(Endpoint.TASK, body);
42
+ }
43
+ /**
44
+ * Changes the task. The API stores the task as an update sends it, clearing optional fields left out, so this reads
45
+ * the task, applies `changes` and sends it whole (see `updateBody`). Lists are sent whole and the server applies the
46
+ * difference. Updates to the same task from this client run one at a time, so each builds on the last.
47
+ *
48
+ * `changes` can be a function of the task as just read, for changes built from its current state, such as adding
49
+ * to a list.
50
+ *
51
+ * Throws `TaskValidationError` before sending when the changes break the API's rules. Returns the task as the
52
+ * server has it after the change.
53
+ *
54
+ * The `BaackClient`'s `failureGuard` applies: retrying a failed update before its backoff has passed fails at once
55
+ * with the same error, sending nothing.
56
+ */
57
+ async update(task, changes, options = {}) {
58
+ const urn = urnOf(task);
59
+ const { base, onChangedElsewhere, ...change } = options;
60
+ if (typeof changes !== 'function') {
61
+ check(changes, urn);
62
+ if (isEmptyChange(changes) && typeof task !== 'string' && isTask(task))
63
+ return task;
64
+ }
65
+ return this.#inTurn(urn, async () => {
66
+ const current = await this.get(urn);
67
+ let changed = typeof changes === 'function' ? changes(current) : changes;
68
+ if (typeof changes === 'function')
69
+ check(changed, urn);
70
+ if (base) {
71
+ // Reported even when the update then stops on a conflict, since the person sees the task as it is now.
72
+ const touched = new Set([...fieldsChanged(changed), ...TASK_LIST_FIELDS.filter((f) => changed[f] !== undefined)]);
73
+ const elsewhere = changedFields(base, current).filter((field) => !touched.has(field));
74
+ if (elsewhere.length > 0)
75
+ onChangedElsewhere?.(elsewhere, current);
76
+ const conflicts = findConflicts(base, current, changed);
77
+ if (conflicts.length > 0)
78
+ throw new TaskConflictError(conflicts, current);
79
+ changed = rebaseLists(base, current, changed);
80
+ }
81
+ return this.client.update(Endpoint.TASK, urn, withActor(updateBody(current, changed), change));
82
+ });
83
+ }
84
+ /** Updates waiting or running, by task URN. */
85
+ #turns = new Map();
86
+ /** Runs `work` after the task's earlier updates settle, whether they succeeded or not. */
87
+ #inTurn(urn, work) {
88
+ const result = (this.#turns.get(urn) ?? Promise.resolve()).catch(() => undefined).then(work);
89
+ this.#turns.set(urn, result);
90
+ const forget = () => {
91
+ if (this.#turns.get(urn) === result)
92
+ this.#turns.delete(urn);
93
+ };
94
+ result.then(forget, forget);
95
+ return result;
96
+ }
97
+ async delete(task) {
98
+ await this.client.delete(Endpoint.TASK, urnOf(task));
99
+ }
100
+ setStatus(task, status, options) {
101
+ return this.update(task, { status }, options);
102
+ }
103
+ setPriority(task, priority, options) {
104
+ return this.update(task, { priority }, options);
105
+ }
106
+ /** Assigns the task to `assignee`, or unassigns it with `null`. */
107
+ assign(task, assignee, options) {
108
+ return this.update(task, { assignee: assignee === null ? null : ref(assignee) }, options);
109
+ }
110
+ /** Sets the due date (a Baack timestamp, see `toTimestamp`), or removes it with `null`. */
111
+ setDue(task, dueTimestamp, options) {
112
+ return this.update(task, { dueTimestamp }, options);
113
+ }
114
+ /** Moves the task into `project`, or out of its project with `null`. */
115
+ setProject(task, project, options) {
116
+ return this.update(task, { project: project === null ? null : ref(project) }, options);
117
+ }
118
+ /** Moves the task to a workflow stage, or out of its stage with `null`. */
119
+ setWorkflowStage(task, stage, options) {
120
+ return this.update(task, { workflowStage: stage === null ? null : ref(stage) }, options);
121
+ }
122
+ /** Marks `blocker` as blocking `task`. */
123
+ addBlocker(task, blocker, options) {
124
+ return this.addTo(task, 'blockedBy', blocker, options);
125
+ }
126
+ removeBlocker(task, blocker, options) {
127
+ return this.removeFrom(task, 'blockedBy', blocker, options);
128
+ }
129
+ /** Adds a reference to one of the task's lists, as the server has the list when the update is sent. */
130
+ addTo(task, field, value, options) {
131
+ return this.update(task, (current) => ({ [field]: withRef(current[field], value) }), options);
132
+ }
133
+ /** Removes a reference from one of the task's lists, as the server has the list when the update is sent. */
134
+ removeFrom(task, field, value, options) {
135
+ return this.update(task, (current) => ({ [field]: withoutRef(current[field], value) }), options);
136
+ }
137
+ // ==========================================
138
+ // ACTIVITY LOG
139
+ // ==========================================
140
+ /** One page of the task's activity log, newest first. Pass `pagination.after` from a page to read the next. */
141
+ async logs(task, options = {}) {
142
+ const page = await this.client.read(Endpoint.TASK_LOGS, urnOf(task), {
143
+ after: options.after,
144
+ });
145
+ return { logs: page?.logs ?? [], pagination: page?.pagination ?? null };
146
+ }
147
+ /** The task's activity log across pages, newest first, stopping after `limit` entries when given. */
148
+ async allLogs(task, options = {}) {
149
+ const { limit = Number.POSITIVE_INFINITY } = options;
150
+ const logs = [];
151
+ let after;
152
+ do {
153
+ const page = await this.logs(task, after === undefined ? {} : { after });
154
+ logs.push(...page.logs);
155
+ after = page.pagination?.isMorePages ? (page.pagination.after ?? undefined) : undefined;
156
+ } while (after !== undefined && logs.length < limit);
157
+ return logs.slice(0, limit);
158
+ }
159
+ /** Adds a comment to the task's activity log. */
160
+ async comment(task, comment, options = {}) {
161
+ const body = { task: ref(task), activity: 'COMMENT_ADDED', comment };
162
+ if (options.actor !== undefined)
163
+ body['identity'] = ref(options.actor);
164
+ if (options.replyTo !== undefined)
165
+ body['replyTo'] = ref(options.replyTo);
166
+ return this.client.create(Endpoint.TASK_LOG, body);
167
+ }
168
+ // ==========================================
169
+ // LISTING
170
+ // ==========================================
171
+ /**
172
+ * Lists a company's tasks. Runs a search, waits for its full result, follows its pages, then
173
+ * reads each task (search results don't carry the task itself yet).
174
+ */
175
+ async list(options) {
176
+ const { includeRelated = true, concurrency = 6, signal } = options;
177
+ const scopes = includeRelated ? ['TASK', 'IDENTITY', 'PROJECT'] : ['TASK'];
178
+ const items = await this.search({ owner: options.owner, scopes }, { ...(options.poll ?? {}), ...(signal ? { signal } : {}) });
179
+ const taskItems = items.filter((item) => item.type === 'TASK');
180
+ const tasks = await mapLimit(taskItems, concurrency, signal, async (item) => {
181
+ if (item.item && isTask(item.item))
182
+ return item.item;
183
+ try {
184
+ return await this.get(item.urn);
185
+ }
186
+ catch (error) {
187
+ if (isBaackApiError(error) && error.isNotFound)
188
+ return undefined;
189
+ throw error;
190
+ }
191
+ });
192
+ return {
193
+ tasks: tasks.filter((task) => task !== undefined),
194
+ identities: items.filter((item) => item.type === 'IDENTITY'),
195
+ projects: items.filter((item) => item.type === 'PROJECT'),
196
+ };
197
+ }
198
+ /**
199
+ * Runs a search and returns every item once the result is full, across pages. Exposed for callers that want other
200
+ * scopes alongside tasks.
201
+ */
202
+ async search(query, options = {}) {
203
+ const { intervalMs = 250, maxIntervalMs = 2000, timeoutMs = 30000, signal } = options;
204
+ const deadline = Date.now() + timeoutMs;
205
+ // The API resolves the owner by URN; the client's Company type also wants a url.
206
+ const body = { owner: ref(query.owner), includeScopes: query.scopes };
207
+ signal?.throwIfAborted();
208
+ let search = await this.client.search(body);
209
+ let wait = intervalMs;
210
+ while (search.status !== 'FULL_RESULT') {
211
+ if (!search.urn)
212
+ throw new Error('The search API returned a search without a URN');
213
+ if (Date.now() + wait > deadline)
214
+ throw new TaskSearchTimeoutError(search.urn, timeoutMs);
215
+ await sleep(wait, signal);
216
+ search = await this.client.searchResult(search.urn);
217
+ wait = Math.min(Math.round(wait * 1.5), maxIntervalMs);
218
+ }
219
+ const items = [...(search.items ?? [])];
220
+ let pagination = search.pagination;
221
+ while (pagination?.isMorePages && pagination.after && search.urn) {
222
+ signal?.throwIfAborted();
223
+ const page = await this.client.searchResult(search.urn, pagination.after);
224
+ items.push(...(page.items ?? []));
225
+ pagination = page.pagination;
226
+ }
227
+ return items;
228
+ }
229
+ }
230
+ /** Throws `TaskValidationError` when the changes break the API's rules. */
231
+ function check(changes, urn) {
232
+ const issues = validateTask(changes, { urn });
233
+ if (issues.length > 0)
234
+ throw new TaskValidationError(issues);
235
+ }
236
+ function withActor(input, options) {
237
+ return options.actor === undefined ? input : { ...input, identityForLogs: ref(options.actor) };
238
+ }
239
+ function isTask(value) {
240
+ return typeof value === 'object' && value !== null && 'urn' in value && 'title' in value && 'status' in value;
241
+ }
242
+ function sleep(ms, signal) {
243
+ return new Promise((resolve, reject) => {
244
+ if (signal?.aborted)
245
+ return reject(signal.reason);
246
+ const timer = setTimeout(() => {
247
+ signal?.removeEventListener('abort', onAbort);
248
+ resolve();
249
+ }, ms);
250
+ const onAbort = () => {
251
+ clearTimeout(timer);
252
+ reject(signal?.reason);
253
+ };
254
+ signal?.addEventListener('abort', onAbort, { once: true });
255
+ });
256
+ }
257
+ /** Maps `items` with at most `limit` calls running at once, keeping the input order. */
258
+ async function mapLimit(items, limit, signal, fn) {
259
+ const results = new Array(items.length);
260
+ let next = 0;
261
+ const worker = async () => {
262
+ while (next < items.length) {
263
+ signal?.throwIfAborted();
264
+ const index = next++;
265
+ results[index] = await fn(items[index]);
266
+ }
267
+ };
268
+ await Promise.all(Array.from({ length: Math.min(Math.max(1, limit), items.length) }, worker));
269
+ return results;
270
+ }
271
+ //# sourceMappingURL=task-client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"task-client.js","sourceRoot":"","sources":["../src/task-client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,84 @@
1
+ import type { Task, TaskPriority, TaskStatus, Workflow, WorkflowStage } from '@baack-software/baack-ts-client';
2
+ import type { RefLike } from './types.ts';
3
+ /** Statuses in board order, from not started to done. */
4
+ export declare const TASK_STATUSES: readonly TaskStatus[];
5
+ /** Priorities from lowest to highest. */
6
+ export declare const TASK_PRIORITIES: readonly TaskPriority[];
7
+ export declare const STATUS_LABELS: Readonly<Record<TaskStatus, string>>;
8
+ export declare const PRIORITY_LABELS: Readonly<Record<TaskPriority, string>>;
9
+ /** Whether a status means the work is finished: completed or closed. */
10
+ export declare function isDoneStatus(status: TaskStatus | null | undefined): boolean;
11
+ /** Whether the task still needs work: not completed or closed. */
12
+ export declare function isOpen(task: Pick<Task, 'status'>): boolean;
13
+ /** The task's due date, or undefined when it has none. */
14
+ export declare function dueDate(task: Pick<Task, 'dueTimestamp'>): Date | undefined;
15
+ /** Whether an open task is past its due date. */
16
+ export declare function isOverdue(task: Pick<Task, 'status' | 'dueTimestamp'>, now?: Date): boolean;
17
+ /** Whether an open task is due within `ms` from now, and not yet overdue. */
18
+ export declare function isDueWithin(task: Pick<Task, 'status' | 'dueTimestamp'>, ms: number, now?: Date): boolean;
19
+ export type TaskComparator = (a: Task, b: Task) => number;
20
+ /** Highest priority first. */
21
+ export declare const byPriority: TaskComparator;
22
+ /** Board order of status. */
23
+ export declare const byStatus: TaskComparator;
24
+ /** Soonest due first; tasks without a due date last. */
25
+ export declare const byDue: TaskComparator;
26
+ /** Most recently updated first. */
27
+ export declare const byUpdated: TaskComparator;
28
+ /** Title, alphabetically. */
29
+ export declare const byTitle: TaskComparator;
30
+ /** Sorts by each comparator in turn, using the next to break ties. */
31
+ export declare function compareBy(...comparators: TaskComparator[]): TaskComparator;
32
+ /** Open tasks before completed and closed ones. */
33
+ export declare const byOpen: TaskComparator;
34
+ /** A sensible default for work lists: open first, then overdue and soonest due, then highest priority. */
35
+ export declare const byUrgency: TaskComparator;
36
+ /** Within a board column: open first, then highest priority, soonest due and title, so ties are stable. */
37
+ export declare const byPriorityThenDue: TaskComparator;
38
+ /**
39
+ * Criteria for `matchesFilter`. Each criterion left out matches every task; all given criteria must match. For
40
+ * `assignee`, `project` and `workflowStage`, `null` in the list matches tasks with none set.
41
+ */
42
+ export interface TaskFilter {
43
+ status?: readonly TaskStatus[];
44
+ priority?: readonly TaskPriority[];
45
+ assignee?: readonly (RefLike | null)[];
46
+ project?: readonly (RefLike | null)[];
47
+ workflowStage?: readonly (RefLike | null)[];
48
+ /** Tasks that block on, are blocking, or are associated with this representation. */
49
+ relatedTo?: RefLike;
50
+ /** `true` for open tasks only, `false` for done tasks only. */
51
+ open?: boolean;
52
+ /** Only open tasks past their due date. */
53
+ overdue?: boolean;
54
+ /** Case-insensitive match against the title and description. */
55
+ text?: string;
56
+ }
57
+ export declare function matchesFilter(task: Task, filter: TaskFilter, now?: Date): boolean;
58
+ export declare function filterTasks(tasks: readonly Task[], filter: TaskFilter, now?: Date): Task[];
59
+ /** Whether the task refers to `target` in its blockers, blocked tasks or associations. */
60
+ export declare function isRelatedTo(task: Task, target: RefLike): boolean;
61
+ export type TaskGrouping = 'status' | 'priority' | 'assignee' | 'project' | 'workflow' | 'workflowStage';
62
+ /** The key used for tasks without an assignee, project, workflow or workflow stage. */
63
+ export declare const NONE_KEY = "";
64
+ /**
65
+ * Groups tasks into columns, keyed by status, priority, or the URN of the assignee, project or workflow stage
66
+ * (`NONE_KEY` when unset). Status and priority groups always contain every value in order, so a board shows empty
67
+ * columns; priority runs highest first. Other groups appear in order of first use.
68
+ */
69
+ export declare function groupTasks(tasks: readonly Task[], by: TaskGrouping): Map<string, Task[]>;
70
+ /** A workflow's stages in order. */
71
+ export declare function workflowStages(workflow: Workflow): WorkflowStage[];
72
+ /**
73
+ * Groups tasks into a workflow's stages, keyed by stage URN, every stage in order even when empty. Tasks in no stage,
74
+ * or in another workflow's, go under `NONE_KEY`, last, which is left out when empty.
75
+ */
76
+ export declare function groupByStage(tasks: readonly Task[], workflow: Workflow): Map<string, Task[]>;
77
+ /** The workflow a task is in: the one its stage belongs to, as a task records only its stage. */
78
+ export declare function workflowOf(task: Task, workflows: readonly Workflow[]): Workflow | undefined;
79
+ /**
80
+ * Groups tasks by workflow, keyed by workflow URN, every workflow in the order given even when empty. Tasks in no
81
+ * workflow's stage go under `NONE_KEY`, last, which is left out when empty.
82
+ */
83
+ export declare function groupByWorkflow(tasks: readonly Task[], workflows: readonly Workflow[]): Map<string, Task[]>;
84
+ //# sourceMappingURL=tasks.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tasks.d.ts","sourceRoot":"","sources":["../src/tasks.ts"],"names":[],"mappings":"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"}
package/dist/tasks.js ADDED
@@ -0,0 +1,208 @@
1
+ import { urnOf } from "./refs.js";
2
+ import { parseTimestamp } from "./time.js";
3
+ /** Statuses in board order, from not started to done. */
4
+ export const TASK_STATUSES = [
5
+ 'UNDEFINED',
6
+ 'PENDING',
7
+ 'IN_PROGRESS',
8
+ 'BLOCKED',
9
+ 'COMPLETED',
10
+ 'CLOSED',
11
+ ];
12
+ /** Priorities from lowest to highest. */
13
+ export const TASK_PRIORITIES = ['NONE', 'LOW', 'MEDIUM', 'HIGH', 'CRITICAL'];
14
+ export const STATUS_LABELS = {
15
+ UNDEFINED: 'Undefined',
16
+ PENDING: 'Pending',
17
+ IN_PROGRESS: 'In progress',
18
+ BLOCKED: 'Blocked',
19
+ COMPLETED: 'Completed',
20
+ CLOSED: 'Closed',
21
+ };
22
+ export const PRIORITY_LABELS = {
23
+ NONE: 'None',
24
+ LOW: 'Low',
25
+ MEDIUM: 'Medium',
26
+ HIGH: 'High',
27
+ CRITICAL: 'Critical',
28
+ };
29
+ const DONE = new Set(['COMPLETED', 'CLOSED']);
30
+ /** Whether a status means the work is finished: completed or closed. */
31
+ export function isDoneStatus(status) {
32
+ return status != null && DONE.has(status);
33
+ }
34
+ /** Whether the task still needs work: not completed or closed. */
35
+ export function isOpen(task) {
36
+ return !isDoneStatus(task.status);
37
+ }
38
+ /** The task's due date, or undefined when it has none. */
39
+ export function dueDate(task) {
40
+ return parseTimestamp(task.dueTimestamp);
41
+ }
42
+ /** Whether an open task is past its due date. */
43
+ export function isOverdue(task, now = new Date()) {
44
+ const due = dueDate(task);
45
+ return isOpen(task) && due !== undefined && due.getTime() < now.getTime();
46
+ }
47
+ /** Whether an open task is due within `ms` from now, and not yet overdue. */
48
+ export function isDueWithin(task, ms, now = new Date()) {
49
+ const due = dueDate(task);
50
+ if (!isOpen(task) || due === undefined)
51
+ return false;
52
+ const left = due.getTime() - now.getTime();
53
+ return left >= 0 && left <= ms;
54
+ }
55
+ /** Highest priority first. */
56
+ export const byPriority = (a, b) => TASK_PRIORITIES.indexOf(b.priority) - TASK_PRIORITIES.indexOf(a.priority);
57
+ /** Board order of status. */
58
+ export const byStatus = (a, b) => TASK_STATUSES.indexOf(a.status) - TASK_STATUSES.indexOf(b.status);
59
+ /** Soonest due first; tasks without a due date last. */
60
+ export const byDue = (a, b) => {
61
+ const [first, second] = [timeOrInfinity(a.dueTimestamp), timeOrInfinity(b.dueTimestamp)];
62
+ // Two tasks without due dates tie (Infinity - Infinity is NaN, which would stop the next comparator breaking it).
63
+ return first === second ? 0 : first - second;
64
+ };
65
+ /** Most recently updated first. */
66
+ export const byUpdated = (a, b) => -(timeOrInfinity(a.updatedTimestamp, 0) - timeOrInfinity(b.updatedTimestamp, 0));
67
+ /** Title, alphabetically. */
68
+ export const byTitle = (a, b) => a.title.localeCompare(b.title);
69
+ /** Sorts by each comparator in turn, using the next to break ties. */
70
+ export function compareBy(...comparators) {
71
+ return (a, b) => {
72
+ for (const compare of comparators) {
73
+ const result = compare(a, b);
74
+ if (result !== 0)
75
+ return result;
76
+ }
77
+ return 0;
78
+ };
79
+ }
80
+ /** Open tasks before completed and closed ones. */
81
+ export const byOpen = (a, b) => Number(isOpen(b)) - Number(isOpen(a));
82
+ /** A sensible default for work lists: open first, then overdue and soonest due, then highest priority. */
83
+ export const byUrgency = compareBy(byOpen, byDue, byPriority, byTitle);
84
+ /** Within a board column: open first, then highest priority, soonest due and title, so ties are stable. */
85
+ export const byPriorityThenDue = compareBy(byOpen, byPriority, byDue, byTitle);
86
+ function timeOrInfinity(timestamp, fallback = Number.POSITIVE_INFINITY) {
87
+ return parseTimestamp(timestamp)?.getTime() ?? fallback;
88
+ }
89
+ export function matchesFilter(task, filter, now = new Date()) {
90
+ if (filter.status && !filter.status.includes(task.status))
91
+ return false;
92
+ if (filter.priority && !filter.priority.includes(task.priority))
93
+ return false;
94
+ if (filter.assignee && !matchesRef(task.assignee, filter.assignee))
95
+ return false;
96
+ if (filter.project && !matchesRef(task.project, filter.project))
97
+ return false;
98
+ if (filter.workflowStage && !matchesRef(task.workflowStage, filter.workflowStage))
99
+ return false;
100
+ if (filter.relatedTo !== undefined && !isRelatedTo(task, filter.relatedTo))
101
+ return false;
102
+ if (filter.open !== undefined && isOpen(task) !== filter.open)
103
+ return false;
104
+ if (filter.overdue && !isOverdue(task, now))
105
+ return false;
106
+ if (filter.text) {
107
+ const needle = filter.text.toLocaleLowerCase();
108
+ const haystack = `${task.title}\n${task.description}`.toLocaleLowerCase();
109
+ if (!haystack.includes(needle))
110
+ return false;
111
+ }
112
+ return true;
113
+ }
114
+ export function filterTasks(tasks, filter, now = new Date()) {
115
+ return tasks.filter((task) => matchesFilter(task, filter, now));
116
+ }
117
+ /** Whether the task refers to `target` in its blockers, blocked tasks or associations. */
118
+ export function isRelatedTo(task, target) {
119
+ const urn = urnOf(target);
120
+ const lists = [
121
+ task.blockedBy,
122
+ task.blocking,
123
+ task.associatedTasks,
124
+ task.associatedEntities,
125
+ task.associatedIdentities,
126
+ task.associatedCompanies,
127
+ ];
128
+ return lists.some((list) => list?.some((item) => item.urn === urn));
129
+ }
130
+ function matchesRef(value, wanted) {
131
+ return wanted.some((candidate) => (candidate === null ? value == null : value?.urn === urnOf(candidate)));
132
+ }
133
+ /** The key used for tasks without an assignee, project, workflow or workflow stage. */
134
+ export const NONE_KEY = '';
135
+ /**
136
+ * Groups tasks into columns, keyed by status, priority, or the URN of the assignee, project or workflow stage
137
+ * (`NONE_KEY` when unset). Status and priority groups always contain every value in order, so a board shows empty
138
+ * columns; priority runs highest first. Other groups appear in order of first use.
139
+ */
140
+ export function groupTasks(tasks, by) {
141
+ const groups = new Map();
142
+ if (by === 'status')
143
+ TASK_STATUSES.forEach((status) => groups.set(status, []));
144
+ if (by === 'priority')
145
+ [...TASK_PRIORITIES].reverse().forEach((priority) => groups.set(priority, []));
146
+ for (const task of tasks) {
147
+ const key = groupKey(task, by);
148
+ const group = groups.get(key);
149
+ if (group)
150
+ group.push(task);
151
+ else
152
+ groups.set(key, [task]);
153
+ }
154
+ return groups;
155
+ }
156
+ /** A workflow's stages in order. */
157
+ export function workflowStages(workflow) {
158
+ return [...(workflow.stages ?? [])].sort((a, b) => (a.order ?? 0) - (b.order ?? 0));
159
+ }
160
+ /**
161
+ * Groups tasks into a workflow's stages, keyed by stage URN, every stage in order even when empty. Tasks in no stage,
162
+ * or in another workflow's, go under `NONE_KEY`, last, which is left out when empty.
163
+ */
164
+ export function groupByStage(tasks, workflow) {
165
+ const groups = new Map(workflowStages(workflow).map((stage) => [stage.urn, []]));
166
+ const rest = [];
167
+ for (const task of tasks)
168
+ (groups.get(task.workflowStage?.urn ?? NONE_KEY) ?? rest).push(task);
169
+ if (rest.length > 0)
170
+ groups.set(NONE_KEY, rest);
171
+ return groups;
172
+ }
173
+ /** The workflow a task is in: the one its stage belongs to, as a task records only its stage. */
174
+ export function workflowOf(task, workflows) {
175
+ const stage = task.workflowStage?.urn;
176
+ return stage ? workflows.find((workflow) => workflow.stages?.some((s) => s.urn === stage)) : undefined;
177
+ }
178
+ /**
179
+ * Groups tasks by workflow, keyed by workflow URN, every workflow in the order given even when empty. Tasks in no
180
+ * workflow's stage go under `NONE_KEY`, last, which is left out when empty.
181
+ */
182
+ export function groupByWorkflow(tasks, workflows) {
183
+ const groups = new Map(workflows.map((workflow) => [workflow.urn, []]));
184
+ const rest = [];
185
+ for (const task of tasks)
186
+ (groups.get(workflowOf(task, workflows)?.urn ?? NONE_KEY) ?? rest).push(task);
187
+ if (rest.length > 0)
188
+ groups.set(NONE_KEY, rest);
189
+ return groups;
190
+ }
191
+ function groupKey(task, by) {
192
+ switch (by) {
193
+ case 'status':
194
+ return task.status;
195
+ case 'priority':
196
+ return task.priority;
197
+ case 'assignee':
198
+ return task.assignee?.urn ?? NONE_KEY;
199
+ case 'project':
200
+ return task.project?.urn ?? NONE_KEY;
201
+ case 'workflowStage':
202
+ return task.workflowStage?.urn ?? NONE_KEY;
203
+ // A task's workflow is found from its stage, which needs the workflows: `groupByWorkflow`.
204
+ case 'workflow':
205
+ return NONE_KEY;
206
+ }
207
+ }
208
+ //# sourceMappingURL=tasks.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tasks.js","sourceRoot":"","sources":["../src/tasks.ts"],"names":[],"mappings":"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"}
package/dist/time.d.ts ADDED
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Baack timestamps are ISO 8601 in UTC without a zone, for example `2025-09-13T17:08:00` or `2025-09-13T17:08:00.000`.
3
+ * A plain `new Date(timestamp)` would read them as local time, so use these helpers instead.
4
+ */
5
+ /** Reads a Baack timestamp as a `Date`, or undefined when it is empty or not a valid timestamp. */
6
+ export declare function parseTimestamp(timestamp: string | null | undefined): Date | undefined;
7
+ /** Writes a `Date` as a Baack timestamp: UTC, with milliseconds, without a zone. */
8
+ export declare function toTimestamp(date: Date): string;
9
+ /**
10
+ * The value for an `<input type="datetime-local">` showing a Baack timestamp in the viewer's local time, or `''`.
11
+ */
12
+ export declare function toLocalInput(timestamp: string | null | undefined): string;
13
+ /** Reads an `<input type="datetime-local">` value (local time) as a Baack timestamp, or undefined when empty. */
14
+ export declare function fromLocalInput(value: string | null | undefined): string | undefined;
15
+ //# sourceMappingURL=time.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"time.d.ts","sourceRoot":"","sources":["../src/time.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,mGAAmG;AACnG,wBAAgB,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,IAAI,GAAG,SAAS,CAIrF;AAED,oFAAoF;AACpF,wBAAgB,WAAW,CAAC,IAAI,EAAE,IAAI,GAAG,MAAM,CAE9C;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,CAKzE;AAED,iHAAiH;AACjH,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAInF"}