monday_ruby 1.1.0 → 1.2.0

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 (82) hide show
  1. checksums.yaml +4 -4
  2. data/.env +1 -1
  3. data/.rubocop.yml +2 -1
  4. data/CHANGELOG.md +14 -0
  5. data/CONTRIBUTING.md +104 -0
  6. data/README.md +146 -142
  7. data/docs/.vitepress/config.mjs +255 -0
  8. data/docs/.vitepress/theme/index.js +4 -0
  9. data/docs/.vitepress/theme/style.css +43 -0
  10. data/docs/README.md +80 -0
  11. data/docs/explanation/architecture.md +507 -0
  12. data/docs/explanation/best-practices/errors.md +478 -0
  13. data/docs/explanation/best-practices/performance.md +1084 -0
  14. data/docs/explanation/best-practices/rate-limiting.md +630 -0
  15. data/docs/explanation/best-practices/testing.md +820 -0
  16. data/docs/explanation/column-values.md +857 -0
  17. data/docs/explanation/design.md +795 -0
  18. data/docs/explanation/graphql.md +356 -0
  19. data/docs/explanation/migration/v1.md +808 -0
  20. data/docs/explanation/pagination.md +447 -0
  21. data/docs/guides/advanced/batch.md +1274 -0
  22. data/docs/guides/advanced/complex-queries.md +1114 -0
  23. data/docs/guides/advanced/errors.md +818 -0
  24. data/docs/guides/advanced/pagination.md +934 -0
  25. data/docs/guides/advanced/rate-limiting.md +981 -0
  26. data/docs/guides/authentication.md +286 -0
  27. data/docs/guides/boards/create.md +386 -0
  28. data/docs/guides/boards/delete.md +405 -0
  29. data/docs/guides/boards/duplicate.md +511 -0
  30. data/docs/guides/boards/query.md +530 -0
  31. data/docs/guides/boards/update.md +453 -0
  32. data/docs/guides/columns/create.md +452 -0
  33. data/docs/guides/columns/metadata.md +492 -0
  34. data/docs/guides/columns/query.md +455 -0
  35. data/docs/guides/columns/update-multiple.md +459 -0
  36. data/docs/guides/columns/update-values.md +509 -0
  37. data/docs/guides/files/add-to-column.md +40 -0
  38. data/docs/guides/files/add-to-update.md +37 -0
  39. data/docs/guides/files/clear-column.md +33 -0
  40. data/docs/guides/first-request.md +285 -0
  41. data/docs/guides/folders/manage.md +750 -0
  42. data/docs/guides/groups/items.md +626 -0
  43. data/docs/guides/groups/manage.md +501 -0
  44. data/docs/guides/installation.md +169 -0
  45. data/docs/guides/items/create.md +493 -0
  46. data/docs/guides/items/delete.md +514 -0
  47. data/docs/guides/items/query.md +605 -0
  48. data/docs/guides/items/subitems.md +483 -0
  49. data/docs/guides/items/update.md +699 -0
  50. data/docs/guides/updates/manage.md +619 -0
  51. data/docs/guides/use-cases/dashboard.md +1421 -0
  52. data/docs/guides/use-cases/import.md +1962 -0
  53. data/docs/guides/use-cases/task-management.md +1381 -0
  54. data/docs/guides/workspaces/manage.md +502 -0
  55. data/docs/index.md +69 -0
  56. data/docs/package-lock.json +2468 -0
  57. data/docs/package.json +13 -0
  58. data/docs/reference/client.md +540 -0
  59. data/docs/reference/configuration.md +586 -0
  60. data/docs/reference/errors.md +693 -0
  61. data/docs/reference/resources/account.md +208 -0
  62. data/docs/reference/resources/activity-log.md +369 -0
  63. data/docs/reference/resources/board-view.md +359 -0
  64. data/docs/reference/resources/board.md +393 -0
  65. data/docs/reference/resources/column.md +543 -0
  66. data/docs/reference/resources/file.md +236 -0
  67. data/docs/reference/resources/folder.md +386 -0
  68. data/docs/reference/resources/group.md +507 -0
  69. data/docs/reference/resources/item.md +348 -0
  70. data/docs/reference/resources/subitem.md +267 -0
  71. data/docs/reference/resources/update.md +259 -0
  72. data/docs/reference/resources/workspace.md +213 -0
  73. data/docs/reference/response.md +560 -0
  74. data/docs/tutorial/first-integration.md +713 -0
  75. data/lib/monday/client.rb +24 -0
  76. data/lib/monday/configuration.rb +5 -0
  77. data/lib/monday/request.rb +15 -0
  78. data/lib/monday/resources/base.rb +4 -0
  79. data/lib/monday/resources/file.rb +56 -0
  80. data/lib/monday/util.rb +1 -0
  81. data/lib/monday/version.rb +1 -1
  82. metadata +87 -4
@@ -0,0 +1,605 @@
1
+ # Query Items
2
+
3
+ Retrieve and filter items from your monday.com boards.
4
+
5
+ ## Basic Query
6
+
7
+ Get items with default fields (ID, name, created_at):
8
+
9
+ ```ruby
10
+ require "monday_ruby"
11
+
12
+ Monday.configure do |config|
13
+ config.token = ENV["MONDAY_TOKEN"]
14
+ end
15
+
16
+ client = Monday::Client.new
17
+
18
+ response = client.item.query
19
+
20
+ if response.success?
21
+ items = response.body.dig("data", "items")
22
+ puts "Found #{items.length} items"
23
+ end
24
+ ```
25
+
26
+ ## Query by IDs
27
+
28
+ Retrieve specific items:
29
+
30
+ ```ruby
31
+ response = client.item.query(
32
+ args: { ids: [987654321, 987654322, 987654323] }
33
+ )
34
+
35
+ if response.success?
36
+ items = response.body.dig("data", "items")
37
+
38
+ items.each do |item|
39
+ puts "#{item['name']} (ID: #{item['id']})"
40
+ end
41
+ end
42
+ ```
43
+
44
+ ### Single Item
45
+
46
+ Query one item by ID:
47
+
48
+ ```ruby
49
+ response = client.item.query(
50
+ args: { ids: "987654321" }
51
+ )
52
+
53
+ if response.success?
54
+ items = response.body.dig("data", "items")
55
+ item = items.first
56
+
57
+ puts "Item: #{item['name']}"
58
+ puts "Created: #{item['created_at']}"
59
+ end
60
+ ```
61
+
62
+ ## Query with Pagination
63
+
64
+ Use limit and page for basic pagination:
65
+
66
+ ```ruby
67
+ # First page
68
+ response = client.item.query(
69
+ args: {
70
+ limit: 25,
71
+ page: 1
72
+ }
73
+ )
74
+
75
+ if response.success?
76
+ items = response.body.dig("data", "items")
77
+ puts "Page 1: #{items.length} items"
78
+ end
79
+
80
+ # Next page
81
+ response = client.item.query(
82
+ args: {
83
+ limit: 25,
84
+ page: 2
85
+ }
86
+ )
87
+ ```
88
+
89
+ ::: warning <span style="display: inline-flex; align-items: center; gap: 6px;"><svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M10.29 3.86L1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z"></path><line x1="12" y1="9" x2="12" y2="13"></line><line x1="12" y1="17" x2="12.01" y2="17"></line></svg>Pagination Limits</span>
90
+ The `items` query has a maximum return limit. For large datasets, use [`items_page`](/guides/advanced/pagination) or [`page_by_column_values`](#filter-by-column-values) instead.
91
+ :::
92
+
93
+ ## Sort Results
94
+
95
+ Order items by creation date:
96
+
97
+ ### Newest First
98
+
99
+ ```ruby
100
+ response = client.item.query(
101
+ args: { newest_first: true }
102
+ )
103
+
104
+ if response.success?
105
+ items = response.body.dig("data", "items")
106
+
107
+ puts "Most recent items:"
108
+ items.first(5).each do |item|
109
+ puts " • #{item['name']} (#{item['created_at']})"
110
+ end
111
+ end
112
+ ```
113
+
114
+ ### Oldest First
115
+
116
+ ```ruby
117
+ response = client.item.query(
118
+ args: { newest_first: false }
119
+ )
120
+ ```
121
+
122
+ ## Custom Fields Selection
123
+
124
+ Request specific fields:
125
+
126
+ ### Basic Fields
127
+
128
+ ```ruby
129
+ response = client.item.query(
130
+ args: { ids: [987654321] },
131
+ select: ["id", "name", "created_at", "state", "url"]
132
+ )
133
+
134
+ if response.success?
135
+ item = response.body.dig("data", "items", 0)
136
+
137
+ puts "Name: #{item['name']}"
138
+ puts "State: #{item['state']}"
139
+ puts "URL: #{item['url']}"
140
+ puts "Created: #{item['created_at']}"
141
+ end
142
+ ```
143
+
144
+ ### With Board Information
145
+
146
+ ```ruby
147
+ response = client.item.query(
148
+ args: { ids: [987654321] },
149
+ select: [
150
+ "id",
151
+ "name",
152
+ {
153
+ board: ["id", "name", "url"]
154
+ }
155
+ ]
156
+ )
157
+
158
+ if response.success?
159
+ item = response.body.dig("data", "items", 0)
160
+ board = item.dig("board")
161
+
162
+ puts "Item: #{item['name']}"
163
+ puts "Board: #{board['name']}"
164
+ puts "Board URL: #{board['url']}"
165
+ end
166
+ ```
167
+
168
+ ## Query with Column Values
169
+
170
+ Get item column data:
171
+
172
+ ```ruby
173
+ response = client.item.query(
174
+ args: { ids: [987654321] },
175
+ select: [
176
+ "id",
177
+ "name",
178
+ {
179
+ column_values: ["id", "text", "type", "value"]
180
+ }
181
+ ]
182
+ )
183
+
184
+ if response.success?
185
+ item = response.body.dig("data", "items", 0)
186
+
187
+ puts "Item: #{item['name']}"
188
+ puts "\nColumn Values:"
189
+
190
+ item["column_values"].each do |col_val|
191
+ next if col_val["text"].nil? || col_val["text"].empty?
192
+ puts " • #{col_val['id']}: #{col_val['text']} (#{col_val['type']})"
193
+ end
194
+ end
195
+ ```
196
+
197
+ **Example output:**
198
+ ```
199
+ Item: Marketing Campaign
200
+ Column Values:
201
+ • status__1: Done (color)
202
+ • date: 2024-12-31 (date)
203
+ • people: John Doe (people)
204
+ • text: High Priority (text)
205
+ ```
206
+
207
+ ## Query with Group Information
208
+
209
+ Get the group (section) an item belongs to:
210
+
211
+ ```ruby
212
+ response = client.item.query(
213
+ args: { ids: [987654321] },
214
+ select: [
215
+ "id",
216
+ "name",
217
+ {
218
+ group: ["id", "title", "color"]
219
+ }
220
+ ]
221
+ )
222
+
223
+ if response.success?
224
+ item = response.body.dig("data", "items", 0)
225
+ group = item.dig("group")
226
+
227
+ puts "Item: #{item['name']}"
228
+ puts "Group: #{group['title']} (#{group['color']})"
229
+ end
230
+ ```
231
+
232
+ ## Query with Subitems
233
+
234
+ Retrieve an item's subitems:
235
+
236
+ ```ruby
237
+ response = client.item.query(
238
+ args: { ids: [987654321] },
239
+ select: [
240
+ "id",
241
+ "name",
242
+ {
243
+ subitems: ["id", "name", "state"]
244
+ }
245
+ ]
246
+ )
247
+
248
+ if response.success?
249
+ item = response.body.dig("data", "items", 0)
250
+
251
+ puts "Item: #{item['name']}"
252
+ puts "Subitems:"
253
+
254
+ item["subitems"].each do |subitem|
255
+ puts " • #{subitem['name']} (#{subitem['state']})"
256
+ end
257
+ end
258
+ ```
259
+
260
+ ## Query with Updates
261
+
262
+ Get item update threads:
263
+
264
+ ```ruby
265
+ response = client.item.query(
266
+ args: { ids: [987654321] },
267
+ select: [
268
+ "id",
269
+ "name",
270
+ {
271
+ updates: ["id", "body", "created_at"]
272
+ }
273
+ ]
274
+ )
275
+
276
+ if response.success?
277
+ item = response.body.dig("data", "items", 0)
278
+
279
+ puts "Item: #{item['name']}"
280
+ puts "Updates: #{item['updates'].length}"
281
+
282
+ item["updates"].first(3).each do |update|
283
+ puts "\n [#{update['created_at']}]"
284
+ puts " #{update['body']}"
285
+ end
286
+ end
287
+ ```
288
+
289
+ ## Filter by Column Values
290
+
291
+ Use `page_by_column_values` for advanced filtering:
292
+
293
+ ::: warning <span style="display: inline-flex; align-items: center; gap: 6px;"><svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M10.29 3.86L1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z"></path><line x1="12" y1="9" x2="12" y2="13"></line><line x1="12" y1="17" x2="12.01" y2="17"></line></svg>Column IDs are Board-Specific</span>
294
+ **You must use your board's actual column IDs for filtering.** Query your board first to get column IDs:
295
+
296
+ ```ruby
297
+ response = client.board.query(
298
+ args: { ids: [1234567890] },
299
+ select: ["id", { columns: ["id", "title", "type"] }]
300
+ )
301
+
302
+ board = response.body.dig("data", "boards", 0)
303
+ board["columns"].each do |col|
304
+ puts "#{col['title']}: '#{col['id']}' (#{col['type']})"
305
+ end
306
+ ```
307
+
308
+ Use the exact column IDs (e.g., `status_1`, `date4`) from the output above.
309
+ :::
310
+
311
+ ### Single Column Filter
312
+
313
+ ```ruby
314
+ # āš ļø Replace 'status' with your actual status column ID
315
+ response = client.item.page_by_column_values(
316
+ board_id: 1234567890,
317
+ columns: [
318
+ { column_id: "status", column_values: ["Done"] } # Your column ID
319
+ ],
320
+ limit: 50
321
+ )
322
+
323
+ if response.success?
324
+ items_page = response.body.dig("data", "items_page_by_column_values")
325
+ items = items_page["items"]
326
+ cursor = items_page["cursor"]
327
+
328
+ puts "Found #{items.length} items with status 'Done'"
329
+
330
+ items.each do |item|
331
+ puts " • #{item['name']}"
332
+ end
333
+ end
334
+ ```
335
+
336
+ ### Multiple Column Filters (AND Logic)
337
+
338
+ Filter by multiple columns - all conditions must match:
339
+
340
+ ```ruby
341
+ # āš ļø Replace 'status' and 'priority' with your actual column IDs
342
+ response = client.item.page_by_column_values(
343
+ board_id: 1234567890,
344
+ columns: [
345
+ { column_id: "status", column_values: ["Done"] }, # Your status column ID
346
+ { column_id: "priority", column_values: ["High"] } # Your priority column ID
347
+ ]
348
+ )
349
+
350
+ if response.success?
351
+ items_page = response.body.dig("data", "items_page_by_column_values")
352
+ items = items_page["items"]
353
+
354
+ puts "High priority items that are done:"
355
+ items.each do |item|
356
+ puts " • #{item['name']}"
357
+ end
358
+ end
359
+ ```
360
+
361
+ ### Multiple Values (OR Logic Within Column)
362
+
363
+ Match any of several values in a column:
364
+
365
+ ```ruby
366
+ response = client.item.page_by_column_values(
367
+ board_id: 1234567890,
368
+ columns: [
369
+ { column_id: "status", column_values: ["Done", "Working on it", "Stuck"] }
370
+ ]
371
+ )
372
+
373
+ if response.success?
374
+ items_page = response.body.dig("data", "items_page_by_column_values")
375
+ items = items_page["items"]
376
+
377
+ puts "Items in active states: #{items.length}"
378
+ end
379
+ ```
380
+
381
+ ### With Cursor Pagination
382
+
383
+ Paginate through filtered results:
384
+
385
+ ```ruby
386
+ def fetch_all_filtered_items(client, board_id, columns)
387
+ all_items = []
388
+ cursor = nil
389
+
390
+ loop do
391
+ response = client.item.page_by_column_values(
392
+ board_id: board_id,
393
+ columns: cursor.nil? ? columns : nil,
394
+ cursor: cursor,
395
+ limit: 50
396
+ )
397
+
398
+ break unless response.success?
399
+
400
+ items_page = response.body.dig("data", "items_page_by_column_values")
401
+ items = items_page["items"]
402
+ break if items.empty?
403
+
404
+ all_items.concat(items)
405
+ cursor = items_page["cursor"]
406
+ break if cursor.nil?
407
+
408
+ puts "Fetched #{items.length} items, cursor: #{cursor[0..20]}..."
409
+ end
410
+
411
+ all_items
412
+ end
413
+
414
+ # Usage
415
+ items = fetch_all_filtered_items(
416
+ client,
417
+ 1234567890,
418
+ [{ column_id: "status", column_values: ["Done"] }]
419
+ )
420
+
421
+ puts "\nTotal filtered items: #{items.length}"
422
+ ```
423
+
424
+ ## Search Items by Name
425
+
426
+ Find items matching a name pattern:
427
+
428
+ ```ruby
429
+ def find_items_by_name(client, board_id, search_term)
430
+ # Note: 'name' is a standard column ID that exists on all boards
431
+ response = client.item.page_by_column_values(
432
+ board_id: board_id,
433
+ columns: [
434
+ { column_id: "name", column_values: [search_term] }
435
+ ],
436
+ limit: 100
437
+ )
438
+
439
+ return [] unless response.success?
440
+
441
+ items_page = response.body.dig("data", "items_page_by_column_values")
442
+ items_page["items"]
443
+ end
444
+
445
+ # Usage
446
+ matching_items = find_items_by_name(client, 1234567890, "Marketing")
447
+
448
+ puts "Items matching 'Marketing':"
449
+ matching_items.each do |item|
450
+ puts " • #{item['name']}"
451
+ end
452
+ ```
453
+
454
+ ## Get Item Count
455
+
456
+ Count items on a board:
457
+
458
+ ```ruby
459
+ response = client.item.query(
460
+ args: {
461
+ limit: 1 # We only need the count, not all items
462
+ },
463
+ select: ["id"]
464
+ )
465
+
466
+ if response.success?
467
+ items = response.body.dig("data", "items")
468
+ puts "Total items: #{items.length}"
469
+ end
470
+ ```
471
+
472
+ ::: tip <span style="display: inline-flex; align-items: center; gap: 6px;"><svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"></circle><line x1="12" y1="16" x2="12" y2="12"></line><line x1="12" y1="8" x2="12.01" y2="8"></line></svg>Better Counting</span>
473
+ For accurate counts on boards with many items, use `board.items_page` with minimal select fields instead.
474
+ :::
475
+
476
+ ## Complete Example
477
+
478
+ Comprehensive item querying:
479
+
480
+ ```ruby
481
+ require "monday_ruby"
482
+ require "dotenv/load"
483
+
484
+ Monday.configure do |config|
485
+ config.token = ENV["MONDAY_TOKEN"]
486
+ end
487
+
488
+ client = Monday::Client.new
489
+
490
+ # Query with detailed fields
491
+ response = client.item.query(
492
+ args: {
493
+ ids: [987654321, 987654322],
494
+ newest_first: true
495
+ },
496
+ select: [
497
+ "id",
498
+ "name",
499
+ "created_at",
500
+ "state",
501
+ "url",
502
+ {
503
+ board: ["id", "name"],
504
+ group: ["id", "title"],
505
+ column_values: ["id", "text", "type"],
506
+ creator: ["id", "name", "email"]
507
+ }
508
+ ]
509
+ )
510
+
511
+ if response.success?
512
+ items = response.body.dig("data", "items")
513
+
514
+ puts "\nšŸ“ Query Results\n#{'=' * 60}\n"
515
+
516
+ items.each do |item|
517
+ board = item.dig("board")
518
+ group = item.dig("group")
519
+ creator = item.dig("creator")
520
+
521
+ puts "\n#{item['name']}"
522
+ puts " ID: #{item['id']}"
523
+ puts " State: #{item['state']}"
524
+ puts " Board: #{board&.dig('name')}"
525
+ puts " Group: #{group&.dig('title')}"
526
+ puts " Creator: #{creator&.dig('name')} (#{creator&.dig('email')})"
527
+ puts " Created: #{item['created_at']}"
528
+ puts " URL: #{item['url']}"
529
+
530
+ puts "\n Column Values:"
531
+ item["column_values"].each do |col_val|
532
+ next if col_val["text"].nil? || col_val["text"].empty?
533
+ puts " • #{col_val['id']}: #{col_val['text']}"
534
+ end
535
+ end
536
+
537
+ puts "\n#{'=' * 60}"
538
+ puts "Total: #{items.length} items"
539
+ else
540
+ puts "āŒ Failed to query items"
541
+ puts "Status: #{response.status}"
542
+ end
543
+ ```
544
+
545
+ ## Export Items to CSV
546
+
547
+ Query and export items:
548
+
549
+ ```ruby
550
+ require "csv"
551
+
552
+ def export_items_to_csv(client, board_id, filename)
553
+ # Query items with column values
554
+ response = client.item.page_by_column_values(
555
+ board_id: board_id,
556
+ columns: nil,
557
+ limit: 500,
558
+ select: [
559
+ "id",
560
+ "name",
561
+ "created_at",
562
+ {
563
+ column_values: ["id", "text"]
564
+ }
565
+ ]
566
+ )
567
+
568
+ return unless response.success?
569
+
570
+ items_page = response.body.dig("data", "items_page_by_column_values")
571
+ items = items_page["items"]
572
+
573
+ CSV.open(filename, "w") do |csv|
574
+ # Header
575
+ csv << ["ID", "Name", "Created At", "Column Values"]
576
+
577
+ # Data
578
+ items.each do |item|
579
+ column_data = item["column_values"]
580
+ .map { |cv| "#{cv['id']}: #{cv['text']}" }
581
+ .join("; ")
582
+
583
+ csv << [
584
+ item["id"],
585
+ item["name"],
586
+ item["created_at"],
587
+ column_data
588
+ ]
589
+ end
590
+ end
591
+
592
+ puts "āœ“ Exported #{items.length} items to #{filename}"
593
+ end
594
+
595
+ # Usage
596
+ export_items_to_csv(client, 1234567890, "items_export.csv")
597
+ ```
598
+
599
+ ## Next Steps
600
+
601
+ - [Create items](/guides/items/create)
602
+ - [Update item values](/guides/items/update)
603
+ - [Advanced pagination](/guides/advanced/pagination)
604
+ - [Filter with complex queries](/guides/advanced/complex-queries)
605
+ - [Work with column values](/guides/columns/query)