superthread 0.7.2
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.
- checksums.yaml +7 -0
- data/CHANGELOG.md +4 -0
- data/LICENSE +21 -0
- data/README.md +492 -0
- data/exe/suth +19 -0
- data/lib/superthread/cli/accounts.rb +240 -0
- data/lib/superthread/cli/activity.rb +210 -0
- data/lib/superthread/cli/base.rb +355 -0
- data/lib/superthread/cli/boards.rb +131 -0
- data/lib/superthread/cli/cards.rb +530 -0
- data/lib/superthread/cli/checklists.rb +223 -0
- data/lib/superthread/cli/comments.rb +86 -0
- data/lib/superthread/cli/completion.rb +306 -0
- data/lib/superthread/cli/concerns/board_resolvable.rb +70 -0
- data/lib/superthread/cli/concerns/confirmable.rb +55 -0
- data/lib/superthread/cli/concerns/date_parsable.rb +196 -0
- data/lib/superthread/cli/concerns/list_resolvable.rb +53 -0
- data/lib/superthread/cli/concerns/space_resolvable.rb +52 -0
- data/lib/superthread/cli/concerns/sprint_resolvable.rb +55 -0
- data/lib/superthread/cli/concerns/tag_resolvable.rb +49 -0
- data/lib/superthread/cli/concerns/user_resolvable.rb +52 -0
- data/lib/superthread/cli/concerns/workspace_resolvable.rb +83 -0
- data/lib/superthread/cli/config.rb +129 -0
- data/lib/superthread/cli/formatter.rb +388 -0
- data/lib/superthread/cli/lists.rb +85 -0
- data/lib/superthread/cli/main.rb +121 -0
- data/lib/superthread/cli/members.rb +19 -0
- data/lib/superthread/cli/notes.rb +64 -0
- data/lib/superthread/cli/pages.rb +128 -0
- data/lib/superthread/cli/projects.rb +124 -0
- data/lib/superthread/cli/replies.rb +94 -0
- data/lib/superthread/cli/search.rb +34 -0
- data/lib/superthread/cli/setup.rb +253 -0
- data/lib/superthread/cli/spaces.rb +141 -0
- data/lib/superthread/cli/sprints.rb +32 -0
- data/lib/superthread/cli/tags.rb +86 -0
- data/lib/superthread/cli/ui/gum_prompt.rb +58 -0
- data/lib/superthread/cli/ui/plain_prompt.rb +73 -0
- data/lib/superthread/cli/ui.rb +263 -0
- data/lib/superthread/cli/workspaces.rb +105 -0
- data/lib/superthread/cli.rb +12 -0
- data/lib/superthread/client.rb +207 -0
- data/lib/superthread/configuration.rb +354 -0
- data/lib/superthread/connection.rb +57 -0
- data/lib/superthread/error.rb +164 -0
- data/lib/superthread/mention_formatter.rb +96 -0
- data/lib/superthread/model.rb +178 -0
- data/lib/superthread/models/board.rb +59 -0
- data/lib/superthread/models/card.rb +321 -0
- data/lib/superthread/models/checklist.rb +91 -0
- data/lib/superthread/models/checklist_item.rb +69 -0
- data/lib/superthread/models/comment.rb +71 -0
- data/lib/superthread/models/concerns/archivable.rb +32 -0
- data/lib/superthread/models/concerns/presentable.rb +113 -0
- data/lib/superthread/models/concerns/timestampable.rb +91 -0
- data/lib/superthread/models/list.rb +67 -0
- data/lib/superthread/models/member.rb +40 -0
- data/lib/superthread/models/note.rb +56 -0
- data/lib/superthread/models/page.rb +70 -0
- data/lib/superthread/models/project.rb +83 -0
- data/lib/superthread/models/space.rb +71 -0
- data/lib/superthread/models/sprint.rb +53 -0
- data/lib/superthread/models/tag.rb +52 -0
- data/lib/superthread/models/team.rb +68 -0
- data/lib/superthread/models/user.rb +76 -0
- data/lib/superthread/models.rb +12 -0
- data/lib/superthread/object.rb +285 -0
- data/lib/superthread/objects/collection.rb +179 -0
- data/lib/superthread/resources/base.rb +204 -0
- data/lib/superthread/resources/boards.rb +150 -0
- data/lib/superthread/resources/cards.rb +363 -0
- data/lib/superthread/resources/comments.rb +163 -0
- data/lib/superthread/resources/notes.rb +61 -0
- data/lib/superthread/resources/pages.rb +110 -0
- data/lib/superthread/resources/projects.rb +117 -0
- data/lib/superthread/resources/search.rb +46 -0
- data/lib/superthread/resources/spaces.rb +104 -0
- data/lib/superthread/resources/sprints.rb +37 -0
- data/lib/superthread/resources/tags.rb +52 -0
- data/lib/superthread/resources/users.rb +29 -0
- data/lib/superthread/version.rb +6 -0
- data/lib/superthread/version_checker.rb +174 -0
- data/lib/superthread.rb +30 -0
- metadata +259 -0
|
@@ -0,0 +1,363 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Superthread
|
|
4
|
+
module Resources
|
|
5
|
+
# API resource for card (task/issue) operations.
|
|
6
|
+
#
|
|
7
|
+
# Provides methods for creating, updating, listing, and managing cards
|
|
8
|
+
# including their members, checklists, tags, and relationships.
|
|
9
|
+
class Cards < Base
|
|
10
|
+
# Creates a new card on a board or in a sprint.
|
|
11
|
+
#
|
|
12
|
+
# @param workspace_id [String] the workspace identifier
|
|
13
|
+
# @param params [Hash{Symbol => Object}] card creation parameters
|
|
14
|
+
# @option params [String] :title the card title (required)
|
|
15
|
+
# @option params [String] :list_id the list identifier (required)
|
|
16
|
+
# @option params [String] :board_id the board identifier (required unless sprint_id provided)
|
|
17
|
+
# @option params [String] :sprint_id the sprint identifier (required unless board_id provided)
|
|
18
|
+
# @option params [String] :content the card content as HTML
|
|
19
|
+
# @option params [String] :project_id the project/space identifier
|
|
20
|
+
# @option params [Integer] :start_date the start date as Unix timestamp
|
|
21
|
+
# @option params [Integer] :due_date the due date as Unix timestamp
|
|
22
|
+
# @option params [Integer] :priority the priority level (1-4)
|
|
23
|
+
# @option params [Integer] :estimate the story point estimate
|
|
24
|
+
# @option params [String] :parent_card_id the parent card identifier for subtasks
|
|
25
|
+
# @option params [String] :epic_id the epic/project identifier to link to
|
|
26
|
+
# @option params [String] :owner_id the owner user identifier
|
|
27
|
+
# @return [Superthread::Models::Card] the created card
|
|
28
|
+
# @raise [ArgumentError] if neither board_id nor sprint_id is provided
|
|
29
|
+
def create(workspace_id, **params)
|
|
30
|
+
unless params[:board_id] || params[:sprint_id]
|
|
31
|
+
raise ArgumentError, "Either board_id or sprint_id must be provided"
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
ws = safe_id("workspace_id", workspace_id)
|
|
35
|
+
post_object("/#{ws}/cards", body: params,
|
|
36
|
+
object_class: Models::Card, unwrap_key: :card)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# Updates an existing card's attributes.
|
|
40
|
+
#
|
|
41
|
+
# @param workspace_id [String] the workspace identifier
|
|
42
|
+
# @param card_id [String] the card identifier
|
|
43
|
+
# @param params [Hash{Symbol => Object}] the attributes to update
|
|
44
|
+
# @option params [String] :title the new card title
|
|
45
|
+
# @option params [String] :list_id the new list identifier to move the card
|
|
46
|
+
# @option params [Integer] :start_date the new start date as Unix timestamp
|
|
47
|
+
# @option params [Integer] :due_date the new due date as Unix timestamp
|
|
48
|
+
# @option params [Integer] :priority the new priority level (1-4)
|
|
49
|
+
# @option params [Integer] :estimate the new story point estimate
|
|
50
|
+
# @option params [String] :sprint_id the destination sprint identifier
|
|
51
|
+
# @option params [String] :project_id the project/space identifier (required with sprint_id)
|
|
52
|
+
# @option params [String] :epic_id the new epic identifier
|
|
53
|
+
# @option params [Boolean] :archived whether the card is archived
|
|
54
|
+
# @return [Superthread::Models::Card] the updated card
|
|
55
|
+
# @note Content cannot be updated via this API; it uses WebSocket collaboration.
|
|
56
|
+
# @note parent_card_id is not supported on update; the API silently ignores it.
|
|
57
|
+
def update(workspace_id, card_id, **params)
|
|
58
|
+
ws = safe_id("workspace_id", workspace_id)
|
|
59
|
+
card = safe_id("card_id", card_id)
|
|
60
|
+
patch_object("/#{ws}/cards/#{card}", body: compact_params(**params),
|
|
61
|
+
object_class: Models::Card, unwrap_key: :card)
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
# Gets a specific card with full details.
|
|
65
|
+
#
|
|
66
|
+
# @param workspace_id [String] the workspace identifier
|
|
67
|
+
# @param card_id [String] the card identifier
|
|
68
|
+
# @return [Superthread::Models::Card] the card with all attributes
|
|
69
|
+
def find(workspace_id, card_id)
|
|
70
|
+
ws = safe_id("workspace_id", workspace_id)
|
|
71
|
+
card = safe_id("card_id", card_id)
|
|
72
|
+
get_object("/#{ws}/cards/#{card}",
|
|
73
|
+
object_class: Models::Card, unwrap_key: :card)
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
# Deletes a card permanently.
|
|
77
|
+
#
|
|
78
|
+
# @param workspace_id [String] the workspace identifier
|
|
79
|
+
# @param card_id [String] the card identifier to delete
|
|
80
|
+
# @return [Superthread::Object] a response object with success: true
|
|
81
|
+
def destroy(workspace_id, card_id)
|
|
82
|
+
ws = safe_id("workspace_id", workspace_id)
|
|
83
|
+
card = safe_id("card_id", card_id)
|
|
84
|
+
http_delete("/#{ws}/cards/#{card}")
|
|
85
|
+
success_response
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
# Duplicates a card.
|
|
89
|
+
#
|
|
90
|
+
# @param workspace_id [String] the workspace identifier
|
|
91
|
+
# @param card_id [String] the card identifier to duplicate
|
|
92
|
+
# @param params [Hash{Symbol => Object}] optional destination parameters
|
|
93
|
+
# @option params [String] :board_id the destination board identifier
|
|
94
|
+
# @option params [String] :list_id the destination list identifier
|
|
95
|
+
# @option params [String] :sprint_id the destination sprint identifier
|
|
96
|
+
# @return [Superthread::Models::Card] the duplicated card
|
|
97
|
+
def duplicate(workspace_id, card_id, **params)
|
|
98
|
+
ws = safe_id("workspace_id", workspace_id)
|
|
99
|
+
card = safe_id("card_id", card_id)
|
|
100
|
+
post_object("/#{ws}/cards/#{card}/copy", body: compact_params(**params),
|
|
101
|
+
object_class: Models::Card, unwrap_key: :card)
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
# Lists cards with optional filters.
|
|
105
|
+
#
|
|
106
|
+
# @param workspace_id [String] the workspace identifier
|
|
107
|
+
# @param filters [Hash{Symbol => Object}] filter options
|
|
108
|
+
# @option filters [String] :board_id filter by board identifier
|
|
109
|
+
# @option filters [String] :sprint_id filter by sprint identifier
|
|
110
|
+
# @option filters [String] :list_id filter by list identifier
|
|
111
|
+
# @option filters [String] :project_id filter by project/space identifier
|
|
112
|
+
# @option filters [Boolean] :archived when true, includes archived cards
|
|
113
|
+
# @return [Superthread::Objects::Collection<Superthread::Models::Card>] the matching cards
|
|
114
|
+
def list(workspace_id, **filters)
|
|
115
|
+
ws = safe_id("workspace_id", workspace_id)
|
|
116
|
+
body = {type: "card", card_filters: build_card_filters(filters)}
|
|
117
|
+
|
|
118
|
+
post_collection("/#{ws}/views/preview", body: body,
|
|
119
|
+
item_class: Models::Card, items_key: :cards)
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
# Gets cards assigned to a user.
|
|
123
|
+
#
|
|
124
|
+
# @param workspace_id [String] the workspace identifier
|
|
125
|
+
# @param user_id [String] the user identifier to filter by assignment
|
|
126
|
+
# @param filters [Hash{Symbol => Object}] optional additional filters
|
|
127
|
+
# @option filters [String] :board_id filter by board identifier
|
|
128
|
+
# @option filters [String] :list_id filter by list identifier
|
|
129
|
+
# @option filters [String] :project_id filter by project/space identifier
|
|
130
|
+
# @option filters [Boolean] :archived when true, includes archived cards
|
|
131
|
+
# @return [Superthread::Objects::Collection<Superthread::Models::Card>] the user's assigned cards
|
|
132
|
+
def assigned(workspace_id, user_id:, **filters)
|
|
133
|
+
ws = safe_id("workspace_id", workspace_id)
|
|
134
|
+
body = {type: "card", card_filters: build_card_filters(filters, members: [user_id])}
|
|
135
|
+
|
|
136
|
+
post_collection("/#{ws}/views/preview", body: body,
|
|
137
|
+
item_class: Models::Card, items_key: :cards)
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
# Links two cards with a relationship.
|
|
141
|
+
#
|
|
142
|
+
# @param workspace_id [String] the workspace identifier
|
|
143
|
+
# @param card_id [String] the source card identifier
|
|
144
|
+
# @param related_card_id [String] the card identifier to link to
|
|
145
|
+
# @param relation_type [String] the relationship type (blocks, blocked_by, related, duplicates)
|
|
146
|
+
# @return [Superthread::Object] the link result
|
|
147
|
+
def add_related(workspace_id, card_id, related_card_id:, relation_type:)
|
|
148
|
+
ws = safe_id("workspace_id", workspace_id)
|
|
149
|
+
card = safe_id("card_id", card_id)
|
|
150
|
+
|
|
151
|
+
post_object("/#{ws}/cards/#{card}/linked_cards", body: {
|
|
152
|
+
card_id: related_card_id,
|
|
153
|
+
linked_card_type: relation_type
|
|
154
|
+
})
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
# Removes a card relationship.
|
|
158
|
+
#
|
|
159
|
+
# @param workspace_id [String] the workspace identifier
|
|
160
|
+
# @param card_id [String] the source card identifier
|
|
161
|
+
# @param linked_card_id [String] the linked card identifier to remove
|
|
162
|
+
# @return [Superthread::Object] a response object with success: true
|
|
163
|
+
def remove_related(workspace_id, card_id, linked_card_id)
|
|
164
|
+
ws = safe_id("workspace_id", workspace_id)
|
|
165
|
+
card = safe_id("card_id", card_id)
|
|
166
|
+
linked = safe_id("linked_card_id", linked_card_id)
|
|
167
|
+
http_delete("/#{ws}/cards/#{card}/linked_cards/#{linked}")
|
|
168
|
+
success_response
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
# Adds a member to a card.
|
|
172
|
+
#
|
|
173
|
+
# @param workspace_id [String] the workspace identifier
|
|
174
|
+
# @param card_id [String] the card identifier
|
|
175
|
+
# @param user_id [String] the user identifier to add as a member
|
|
176
|
+
# @param role [String] the member role (defaults to "member")
|
|
177
|
+
# @return [Superthread::Object] the membership result
|
|
178
|
+
def add_member(workspace_id, card_id, user_id:, role: "member")
|
|
179
|
+
ws = safe_id("workspace_id", workspace_id)
|
|
180
|
+
card = safe_id("card_id", card_id)
|
|
181
|
+
post_object("/#{ws}/cards/#{card}/members", body: {user_id: user_id, role: role})
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
# Removes a member from a card.
|
|
185
|
+
#
|
|
186
|
+
# @param workspace_id [String] the workspace identifier
|
|
187
|
+
# @param card_id [String] the card identifier
|
|
188
|
+
# @param user_id [String] the user identifier to remove
|
|
189
|
+
# @return [Superthread::Object] a response object with success: true
|
|
190
|
+
def remove_member(workspace_id, card_id, user_id)
|
|
191
|
+
ws = safe_id("workspace_id", workspace_id)
|
|
192
|
+
card = safe_id("card_id", card_id)
|
|
193
|
+
user = safe_id("user_id", user_id)
|
|
194
|
+
http_delete("/#{ws}/cards/#{card}/members/#{user}")
|
|
195
|
+
success_response
|
|
196
|
+
end
|
|
197
|
+
|
|
198
|
+
# Creates a checklist on a card.
|
|
199
|
+
#
|
|
200
|
+
# @param workspace_id [String] the workspace identifier
|
|
201
|
+
# @param card_id [String] the card identifier
|
|
202
|
+
# @param title [String] the checklist title
|
|
203
|
+
# @return [Superthread::Models::Checklist] the created checklist
|
|
204
|
+
def create_checklist(workspace_id, card_id, title:)
|
|
205
|
+
ws = safe_id("workspace_id", workspace_id)
|
|
206
|
+
card = safe_id("card_id", card_id)
|
|
207
|
+
post_object("/#{ws}/cards/#{card}/checklists", body: {title: title},
|
|
208
|
+
object_class: Models::Checklist, unwrap_key: :checklist)
|
|
209
|
+
end
|
|
210
|
+
|
|
211
|
+
# Adds an item to a checklist.
|
|
212
|
+
#
|
|
213
|
+
# @param workspace_id [String] the workspace identifier
|
|
214
|
+
# @param card_id [String] the card identifier
|
|
215
|
+
# @param checklist_id [String] the checklist identifier
|
|
216
|
+
# @param title [String] the item title
|
|
217
|
+
# @param checked [Boolean] whether the item is checked (defaults to false)
|
|
218
|
+
# @return [Superthread::Models::ChecklistItem] the created checklist item
|
|
219
|
+
def add_checklist_item(workspace_id, card_id, checklist_id, title:, checked: false)
|
|
220
|
+
ws = safe_id("workspace_id", workspace_id)
|
|
221
|
+
card = safe_id("card_id", card_id)
|
|
222
|
+
checklist = safe_id("checklist_id", checklist_id)
|
|
223
|
+
title = format_mentions(workspace_id, title)
|
|
224
|
+
|
|
225
|
+
post_object("/#{ws}/cards/#{card}/checklists/#{checklist}/items", body: {
|
|
226
|
+
title: title,
|
|
227
|
+
checklist_id: checklist_id,
|
|
228
|
+
checked: checked
|
|
229
|
+
}, object_class: Models::ChecklistItem, unwrap_key: :checklist_item)
|
|
230
|
+
end
|
|
231
|
+
|
|
232
|
+
# Updates a checklist item.
|
|
233
|
+
#
|
|
234
|
+
# @param workspace_id [String] the workspace identifier
|
|
235
|
+
# @param card_id [String] the card identifier
|
|
236
|
+
# @param checklist_id [String] the checklist identifier
|
|
237
|
+
# @param item_id [String] the item identifier
|
|
238
|
+
# @param params [Hash{Symbol => Object}] the attributes to update
|
|
239
|
+
# @option params [String] :title the new item title
|
|
240
|
+
# @option params [Boolean] :checked whether the item is checked
|
|
241
|
+
# @return [Superthread::Models::ChecklistItem] the updated checklist item
|
|
242
|
+
def update_checklist_item(workspace_id, card_id, checklist_id, item_id, **params)
|
|
243
|
+
ws = safe_id("workspace_id", workspace_id)
|
|
244
|
+
card = safe_id("card_id", card_id)
|
|
245
|
+
checklist = safe_id("checklist_id", checklist_id)
|
|
246
|
+
item = safe_id("item_id", item_id)
|
|
247
|
+
params[:title] = format_mentions(workspace_id, params[:title]) if params[:title]
|
|
248
|
+
|
|
249
|
+
patch_object("/#{ws}/cards/#{card}/checklists/#{checklist}/items/#{item}",
|
|
250
|
+
body: compact_params(**params), object_class: Models::ChecklistItem, unwrap_key: :checklist_item)
|
|
251
|
+
end
|
|
252
|
+
|
|
253
|
+
# Deletes a checklist item.
|
|
254
|
+
#
|
|
255
|
+
# @param workspace_id [String] the workspace identifier
|
|
256
|
+
# @param card_id [String] the card identifier
|
|
257
|
+
# @param checklist_id [String] the checklist identifier
|
|
258
|
+
# @param item_id [String] the item identifier to delete
|
|
259
|
+
# @return [Superthread::Object] a response object with success: true
|
|
260
|
+
def delete_checklist_item(workspace_id, card_id, checklist_id, item_id)
|
|
261
|
+
ws = safe_id("workspace_id", workspace_id)
|
|
262
|
+
card = safe_id("card_id", card_id)
|
|
263
|
+
checklist = safe_id("checklist_id", checklist_id)
|
|
264
|
+
item = safe_id("item_id", item_id)
|
|
265
|
+
|
|
266
|
+
http_delete("/#{ws}/cards/#{card}/checklists/#{checklist}/items/#{item}")
|
|
267
|
+
success_response
|
|
268
|
+
end
|
|
269
|
+
|
|
270
|
+
# Updates a checklist's title.
|
|
271
|
+
#
|
|
272
|
+
# @param workspace_id [String] the workspace identifier
|
|
273
|
+
# @param card_id [String] the card identifier
|
|
274
|
+
# @param checklist_id [String] the checklist identifier
|
|
275
|
+
# @param title [String] the new checklist title
|
|
276
|
+
# @return [Superthread::Models::Checklist] the updated checklist
|
|
277
|
+
def update_checklist(workspace_id, card_id, checklist_id, title:)
|
|
278
|
+
ws = safe_id("workspace_id", workspace_id)
|
|
279
|
+
card = safe_id("card_id", card_id)
|
|
280
|
+
checklist = safe_id("checklist_id", checklist_id)
|
|
281
|
+
|
|
282
|
+
patch_object("/#{ws}/cards/#{card}/checklists/#{checklist}", body: {title: title},
|
|
283
|
+
object_class: Models::Checklist, unwrap_key: :checklist)
|
|
284
|
+
end
|
|
285
|
+
|
|
286
|
+
# Deletes a checklist and all its items.
|
|
287
|
+
#
|
|
288
|
+
# @param workspace_id [String] the workspace identifier
|
|
289
|
+
# @param card_id [String] the card identifier
|
|
290
|
+
# @param checklist_id [String] the checklist identifier to delete
|
|
291
|
+
# @return [Superthread::Object] a response object with success: true
|
|
292
|
+
def delete_checklist(workspace_id, card_id, checklist_id)
|
|
293
|
+
ws = safe_id("workspace_id", workspace_id)
|
|
294
|
+
card = safe_id("card_id", card_id)
|
|
295
|
+
checklist = safe_id("checklist_id", checklist_id)
|
|
296
|
+
|
|
297
|
+
http_delete("/#{ws}/cards/#{card}/checklists/#{checklist}")
|
|
298
|
+
success_response
|
|
299
|
+
end
|
|
300
|
+
|
|
301
|
+
# Gets available tags for a workspace.
|
|
302
|
+
#
|
|
303
|
+
# @param workspace_id [String] the workspace identifier
|
|
304
|
+
# @param project_id [String, nil] optional project/space identifier to filter by
|
|
305
|
+
# @param all [Boolean, nil] when true, returns all tags including unused ones
|
|
306
|
+
# @return [Superthread::Objects::Collection<Superthread::Models::Tag>] the available tags
|
|
307
|
+
def tags(workspace_id, project_id: nil, all: nil)
|
|
308
|
+
ws = safe_id("workspace_id", workspace_id)
|
|
309
|
+
params = compact_params(project_id: project_id, all: all)
|
|
310
|
+
get_collection("/#{ws}/tags", params: params,
|
|
311
|
+
item_class: Models::Tag, items_key: :tags)
|
|
312
|
+
end
|
|
313
|
+
|
|
314
|
+
# Adds tags to a card.
|
|
315
|
+
#
|
|
316
|
+
# @param workspace_id [String] the workspace identifier
|
|
317
|
+
# @param card_id [String] the card identifier
|
|
318
|
+
# @param tag_ids [Array<String>, String] the tag identifier(s) to add
|
|
319
|
+
# @return [Superthread::Object] the tagging result
|
|
320
|
+
def add_tags(workspace_id, card_id, tag_ids:)
|
|
321
|
+
ws = safe_id("workspace_id", workspace_id)
|
|
322
|
+
card = safe_id("card_id", card_id)
|
|
323
|
+
|
|
324
|
+
body = tag_ids.is_a?(Array) ? {ids: tag_ids} : {id: tag_ids}
|
|
325
|
+
post_object("/#{ws}/cards/#{card}/tags", body: body)
|
|
326
|
+
end
|
|
327
|
+
|
|
328
|
+
# Removes a tag from a card.
|
|
329
|
+
#
|
|
330
|
+
# @param workspace_id [String] the workspace identifier
|
|
331
|
+
# @param card_id [String] the card identifier
|
|
332
|
+
# @param tag_id [String] the tag identifier to remove
|
|
333
|
+
# @return [Superthread::Object] a response object with success: true
|
|
334
|
+
def remove_tag(workspace_id, card_id, tag_id)
|
|
335
|
+
ws = safe_id("workspace_id", workspace_id)
|
|
336
|
+
card = safe_id("card_id", card_id)
|
|
337
|
+
tag = safe_id("tag_id", tag_id)
|
|
338
|
+
http_delete("/#{ws}/cards/#{card}/tags/#{tag}")
|
|
339
|
+
success_response
|
|
340
|
+
end
|
|
341
|
+
|
|
342
|
+
private
|
|
343
|
+
|
|
344
|
+
# Builds the card_filters hash for the views/preview endpoint.
|
|
345
|
+
#
|
|
346
|
+
# @param filters [Hash{Symbol => Object}] filter options
|
|
347
|
+
# @param members [Array<String>, nil] user IDs to filter by assignment
|
|
348
|
+
# @return [Hash] the card_filters structure for the API request
|
|
349
|
+
def build_card_filters(filters, members: nil)
|
|
350
|
+
includes = {}
|
|
351
|
+
includes[:members] = members if members
|
|
352
|
+
includes[:boards] = [filters[:board_id]] if filters[:board_id]
|
|
353
|
+
includes[:lists] = [filters[:list_id]] if filters[:list_id]
|
|
354
|
+
includes[:projects] = [filters[:project_id]] if filters[:project_id]
|
|
355
|
+
includes[:sprints] = [filters[:sprint_id]] if filters[:sprint_id]
|
|
356
|
+
|
|
357
|
+
card_filters = {include: includes}
|
|
358
|
+
card_filters[:is_archived] = filters[:archived] unless filters[:archived].nil?
|
|
359
|
+
card_filters
|
|
360
|
+
end
|
|
361
|
+
end
|
|
362
|
+
end
|
|
363
|
+
end
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Superthread
|
|
4
|
+
module Resources
|
|
5
|
+
# API resource for comment operations.
|
|
6
|
+
#
|
|
7
|
+
# Provides methods for creating, updating, and managing comments
|
|
8
|
+
# on cards and pages, including threaded replies.
|
|
9
|
+
class Comments < Base
|
|
10
|
+
# Lists comments on a card.
|
|
11
|
+
#
|
|
12
|
+
# @param workspace_id [String] the workspace identifier
|
|
13
|
+
# @param card_id [String] the card identifier to list comments for
|
|
14
|
+
# @return [Superthread::Objects::Collection<Superthread::Models::Comment>] the card's comments
|
|
15
|
+
def list(workspace_id, card_id:)
|
|
16
|
+
ws = safe_id("workspace_id", workspace_id)
|
|
17
|
+
params = compact_params(card_id: card_id)
|
|
18
|
+
get_collection("/#{ws}/comments", params: params,
|
|
19
|
+
item_class: Models::Comment, items_key: :comments)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# Creates a comment on a card or page.
|
|
23
|
+
#
|
|
24
|
+
# @param workspace_id [String] the workspace identifier
|
|
25
|
+
# @param content [String] the comment content as HTML (max 102400 chars)
|
|
26
|
+
# @param card_id [String, nil] the card identifier (required unless page_id provided)
|
|
27
|
+
# @param page_id [String, nil] the page identifier (required unless card_id provided)
|
|
28
|
+
# @param params [Hash{Symbol => Object}] optional comment parameters
|
|
29
|
+
# @option params [Hash{Symbol => Object}] :schema the content schema for structured content
|
|
30
|
+
# @option params [Hash{Symbol => Object}] :context additional context metadata
|
|
31
|
+
# @return [Superthread::Models::Comment] the created comment
|
|
32
|
+
def create(workspace_id, content:, card_id: nil, page_id: nil, **params)
|
|
33
|
+
ws = safe_id("workspace_id", workspace_id)
|
|
34
|
+
content = format_mentions(workspace_id, content)
|
|
35
|
+
body = compact_params(content: content, card_id: card_id, page_id: page_id, **params)
|
|
36
|
+
post_object("/#{ws}/comments", body: body,
|
|
37
|
+
object_class: Models::Comment, unwrap_key: :comment)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# Gets a specific comment.
|
|
41
|
+
#
|
|
42
|
+
# @param workspace_id [String] the workspace identifier
|
|
43
|
+
# @param comment_id [String] the comment identifier
|
|
44
|
+
# @return [Superthread::Models::Comment] the comment with all attributes
|
|
45
|
+
def find(workspace_id, comment_id)
|
|
46
|
+
ws = safe_id("workspace_id", workspace_id)
|
|
47
|
+
comment = safe_id("comment_id", comment_id)
|
|
48
|
+
get_object("/#{ws}/comments/#{comment}",
|
|
49
|
+
object_class: Models::Comment, unwrap_key: :comment)
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
# Updates a comment's attributes.
|
|
53
|
+
#
|
|
54
|
+
# @param workspace_id [String] the workspace identifier
|
|
55
|
+
# @param comment_id [String] the comment identifier
|
|
56
|
+
# @param params [Hash{Symbol => Object}] the attributes to update
|
|
57
|
+
# @option params [String] :content the new comment content as HTML
|
|
58
|
+
# @option params [String] :status the new comment status
|
|
59
|
+
# @option params [Hash{Symbol => Object}] :context updated context metadata
|
|
60
|
+
# @option params [Hash{Symbol => Object}] :schema updated content schema
|
|
61
|
+
# @return [Superthread::Models::Comment] the updated comment
|
|
62
|
+
def update(workspace_id, comment_id, **params)
|
|
63
|
+
ws = safe_id("workspace_id", workspace_id)
|
|
64
|
+
comment = safe_id("comment_id", comment_id)
|
|
65
|
+
params[:content] = format_mentions(workspace_id, params[:content]) if params[:content]
|
|
66
|
+
patch_object("/#{ws}/comments/#{comment}", body: compact_params(**params),
|
|
67
|
+
object_class: Models::Comment, unwrap_key: :comment)
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
# Deletes a comment permanently.
|
|
71
|
+
#
|
|
72
|
+
# @param workspace_id [String] the workspace identifier
|
|
73
|
+
# @param comment_id [String] the comment identifier to delete
|
|
74
|
+
# @return [Superthread::Object] a response object with success: true
|
|
75
|
+
def destroy(workspace_id, comment_id)
|
|
76
|
+
ws = safe_id("workspace_id", workspace_id)
|
|
77
|
+
comment = safe_id("comment_id", comment_id)
|
|
78
|
+
http_delete("/#{ws}/comments/#{comment}")
|
|
79
|
+
success_response
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
# Replies to a comment, creating a threaded response.
|
|
83
|
+
#
|
|
84
|
+
# @param workspace_id [String] the workspace identifier
|
|
85
|
+
# @param comment_id [String] the parent comment identifier
|
|
86
|
+
# @param content [String] the reply content as HTML
|
|
87
|
+
# @param params [Hash{Symbol => Object}] optional reply parameters
|
|
88
|
+
# @option params [Hash{Symbol => Object}] :schema the content schema for structured content
|
|
89
|
+
# @return [Superthread::Models::Comment] the created reply
|
|
90
|
+
def reply(workspace_id, comment_id, content:, **params)
|
|
91
|
+
ws = safe_id("workspace_id", workspace_id)
|
|
92
|
+
comment = safe_id("comment_id", comment_id)
|
|
93
|
+
content = format_mentions(workspace_id, content)
|
|
94
|
+
body = compact_params(content: content, **params)
|
|
95
|
+
post_object("/#{ws}/comments/#{comment}/children", body: body,
|
|
96
|
+
object_class: Models::Comment, unwrap_key: :child_comment)
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
# Gets replies to a comment.
|
|
100
|
+
#
|
|
101
|
+
# @param workspace_id [String] the workspace identifier
|
|
102
|
+
# @param comment_id [String] the parent comment identifier
|
|
103
|
+
# @return [Superthread::Objects::Collection<Superthread::Models::Comment>] the threaded replies
|
|
104
|
+
def replies(workspace_id, comment_id)
|
|
105
|
+
ws = safe_id("workspace_id", workspace_id)
|
|
106
|
+
comment = safe_id("comment_id", comment_id)
|
|
107
|
+
get_collection("/#{ws}/comments/#{comment}/children",
|
|
108
|
+
item_class: Models::Comment, items_key: :child_comments)
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
# Gets a specific reply by listing all replies on the parent comment
|
|
112
|
+
# and finding the matching one.
|
|
113
|
+
#
|
|
114
|
+
# @param workspace_id [String] the workspace identifier
|
|
115
|
+
# @param comment_id [String] the parent comment identifier
|
|
116
|
+
# @param reply_id [String] the reply identifier to find
|
|
117
|
+
# @return [Superthread::Models::Comment] the reply
|
|
118
|
+
# @raise [Superthread::NotFoundError] if the reply is not found
|
|
119
|
+
def find_reply(workspace_id, comment_id, reply_id)
|
|
120
|
+
all_replies = replies(workspace_id, comment_id)
|
|
121
|
+
found = all_replies.find { |r| r.id == reply_id }
|
|
122
|
+
unless found
|
|
123
|
+
raise Superthread::NotFoundError.new(
|
|
124
|
+
"Reply '#{reply_id}' not found on comment '#{comment_id}'"
|
|
125
|
+
)
|
|
126
|
+
end
|
|
127
|
+
found
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
# Updates a reply's attributes.
|
|
131
|
+
#
|
|
132
|
+
# @param workspace_id [String] the workspace identifier
|
|
133
|
+
# @param comment_id [String] the parent comment identifier
|
|
134
|
+
# @param reply_id [String] the reply identifier
|
|
135
|
+
# @param params [Hash{Symbol => Object}] the attributes to update
|
|
136
|
+
# @option params [String] :content the new reply content as HTML
|
|
137
|
+
# @option params [String] :status the new reply status
|
|
138
|
+
# @return [Superthread::Models::Comment] the updated reply
|
|
139
|
+
def update_reply(workspace_id, comment_id, reply_id, **params)
|
|
140
|
+
ws = safe_id("workspace_id", workspace_id)
|
|
141
|
+
comment = safe_id("comment_id", comment_id)
|
|
142
|
+
reply = safe_id("reply_id", reply_id)
|
|
143
|
+
params[:content] = format_mentions(workspace_id, params[:content]) if params[:content]
|
|
144
|
+
patch_object("/#{ws}/comments/#{comment}/children/#{reply}", body: compact_params(**params),
|
|
145
|
+
object_class: Models::Comment, unwrap_key: :child_comment)
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
# Deletes a reply permanently.
|
|
149
|
+
#
|
|
150
|
+
# @param workspace_id [String] the workspace identifier
|
|
151
|
+
# @param comment_id [String] the parent comment identifier
|
|
152
|
+
# @param reply_id [String] the reply identifier to delete
|
|
153
|
+
# @return [Superthread::Object] a response object with success: true
|
|
154
|
+
def delete_reply(workspace_id, comment_id, reply_id)
|
|
155
|
+
ws = safe_id("workspace_id", workspace_id)
|
|
156
|
+
comment = safe_id("comment_id", comment_id)
|
|
157
|
+
reply = safe_id("reply_id", reply_id)
|
|
158
|
+
http_delete("/#{ws}/comments/#{comment}/children/#{reply}")
|
|
159
|
+
success_response
|
|
160
|
+
end
|
|
161
|
+
end
|
|
162
|
+
end
|
|
163
|
+
end
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Superthread
|
|
4
|
+
module Resources
|
|
5
|
+
# API resource for note operations.
|
|
6
|
+
#
|
|
7
|
+
# Provides methods for listing, creating, and managing notes
|
|
8
|
+
# (meeting notes, transcripts) via the Superthread API.
|
|
9
|
+
class Notes < Base
|
|
10
|
+
# Lists all notes in a workspace.
|
|
11
|
+
#
|
|
12
|
+
# @param workspace_id [String] the workspace identifier
|
|
13
|
+
# @return [Superthread::Objects::Collection<Superthread::Models::Note>] the notes in the workspace
|
|
14
|
+
def list(workspace_id)
|
|
15
|
+
ws = safe_id("workspace_id", workspace_id)
|
|
16
|
+
get_collection("/#{ws}/notes",
|
|
17
|
+
item_class: Models::Note, items_key: :notes)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
# Gets a specific note.
|
|
21
|
+
#
|
|
22
|
+
# @param workspace_id [String] the workspace identifier
|
|
23
|
+
# @param note_id [String] the note identifier
|
|
24
|
+
# @return [Superthread::Models::Note] the note with all attributes
|
|
25
|
+
def find(workspace_id, note_id)
|
|
26
|
+
ws = safe_id("workspace_id", workspace_id)
|
|
27
|
+
note = safe_id("note_id", note_id)
|
|
28
|
+
get_object("/#{ws}/notes/#{note}",
|
|
29
|
+
object_class: Models::Note, unwrap_key: :note)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# Creates a new note.
|
|
33
|
+
#
|
|
34
|
+
# @param workspace_id [String] the workspace identifier
|
|
35
|
+
# @param title [String] the note title
|
|
36
|
+
# @param params [Hash{Symbol => Object}] optional note parameters
|
|
37
|
+
# @option params [String] :transcript the meeting transcript content
|
|
38
|
+
# @option params [Array<Hash{Symbol => Object}>] :transcripts multiple transcript segments
|
|
39
|
+
# @option params [String] :user_notes user-added notes content
|
|
40
|
+
# @return [Superthread::Models::Note] the created note
|
|
41
|
+
def create(workspace_id, title:, **params)
|
|
42
|
+
ws = safe_id("workspace_id", workspace_id)
|
|
43
|
+
body = compact_params(title: title, **params)
|
|
44
|
+
post_object("/#{ws}/notes", body: body,
|
|
45
|
+
object_class: Models::Note, unwrap_key: :note)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# Deletes a note permanently.
|
|
49
|
+
#
|
|
50
|
+
# @param workspace_id [String] the workspace identifier
|
|
51
|
+
# @param note_id [String] the note identifier to delete
|
|
52
|
+
# @return [Superthread::Object] a response object with success: true
|
|
53
|
+
def destroy(workspace_id, note_id)
|
|
54
|
+
ws = safe_id("workspace_id", workspace_id)
|
|
55
|
+
note = safe_id("note_id", note_id)
|
|
56
|
+
http_delete("/#{ws}/notes/#{note}")
|
|
57
|
+
success_response
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|