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,511 @@
1
+ # Duplicate Boards
2
+
3
+ Create copies of existing boards with different duplication options.
4
+
5
+ ## Basic Duplication
6
+
7
+ Duplicate a board's structure without items:
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
+ board_id = 1234567890
19
+
20
+ response = client.board.duplicate(
21
+ args: {
22
+ board_id: board_id,
23
+ duplicate_type: :duplicate_board_with_structure
24
+ }
25
+ )
26
+
27
+ if response.success?
28
+ duplicated = response.body.dig("data", "duplicate_board", "board")
29
+ puts "✓ Duplicated board"
30
+ puts " New ID: #{duplicated['id']}"
31
+ puts " Name: #{duplicated['name']}"
32
+ else
33
+ puts "✗ Duplication failed"
34
+ end
35
+ ```
36
+
37
+ ## Duplication Types
38
+
39
+ ### Structure Only
40
+
41
+ Copy columns, groups, and settings without items:
42
+
43
+ ```ruby
44
+ response = client.board.duplicate(
45
+ args: {
46
+ board_id: 1234567890,
47
+ duplicate_type: :duplicate_board_with_structure
48
+ }
49
+ )
50
+ ```
51
+
52
+ Perfect for creating new projects with the same structure.
53
+
54
+ ### Structure and Items
55
+
56
+ Copy everything including all items (but not updates):
57
+
58
+ ```ruby
59
+ response = client.board.duplicate(
60
+ args: {
61
+ board_id: 1234567890,
62
+ duplicate_type: :duplicate_board_with_pulses
63
+ }
64
+ )
65
+
66
+ if response.success?
67
+ duplicated = response.body.dig("data", "duplicate_board", "board")
68
+ puts "✓ Duplicated board with items"
69
+ puts " New ID: #{duplicated['id']}"
70
+ end
71
+ ```
72
+
73
+ ::: 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>Pulses = Items</span>
74
+ In monday.com's API, "pulses" is the legacy term for "items". Both refer to the same thing.
75
+ :::
76
+
77
+ ### Structure, Items, and Updates
78
+
79
+ Full duplication including all updates and comments:
80
+
81
+ ```ruby
82
+ response = client.board.duplicate(
83
+ args: {
84
+ board_id: 1234567890,
85
+ duplicate_type: :duplicate_board_with_pulses_and_updates
86
+ }
87
+ )
88
+
89
+ if response.success?
90
+ duplicated = response.body.dig("data", "duplicate_board", "board")
91
+ puts "✓ Full duplication complete"
92
+ puts " Includes: structure, items, updates"
93
+ end
94
+ ```
95
+
96
+ ## Custom Board Name
97
+
98
+ Specify a name for the duplicated board:
99
+
100
+ ```ruby
101
+ response = client.board.duplicate(
102
+ args: {
103
+ board_id: 1234567890,
104
+ duplicate_type: :duplicate_board_with_structure,
105
+ board_name: "Q2 2024 Sprint Planning"
106
+ }
107
+ )
108
+
109
+ if response.success?
110
+ duplicated = response.body.dig("data", "duplicate_board", "board")
111
+ puts "✓ Created: #{duplicated['name']}"
112
+ end
113
+ ```
114
+
115
+ If not specified, monday.com appends "copy of" to the original name.
116
+
117
+ ## Duplicate to Workspace
118
+
119
+ Place the duplicate in a specific workspace:
120
+
121
+ ```ruby
122
+ workspace_id = 9876543210
123
+
124
+ response = client.board.duplicate(
125
+ args: {
126
+ board_id: 1234567890,
127
+ duplicate_type: :duplicate_board_with_structure,
128
+ workspace_id: workspace_id
129
+ }
130
+ )
131
+
132
+ if response.success?
133
+ duplicated = response.body.dig("data", "duplicate_board", "board")
134
+ puts "✓ Duplicated to workspace: #{workspace_id}"
135
+ puts " Board ID: #{duplicated['id']}"
136
+ end
137
+ ```
138
+
139
+ ## Duplicate to Folder
140
+
141
+ Organize the duplicate in a folder:
142
+
143
+ ```ruby
144
+ folder_id = 5555555555
145
+
146
+ response = client.board.duplicate(
147
+ args: {
148
+ board_id: 1234567890,
149
+ duplicate_type: :duplicate_board_with_structure,
150
+ folder_id: folder_id
151
+ }
152
+ )
153
+
154
+ if response.success?
155
+ duplicated = response.body.dig("data", "duplicate_board", "board")
156
+ puts "✓ Duplicated to folder: #{folder_id}"
157
+ end
158
+ ```
159
+
160
+ ## Custom Response Fields
161
+
162
+ Request specific fields from the duplicated board:
163
+
164
+ ```ruby
165
+ response = client.board.duplicate(
166
+ args: {
167
+ board_id: 1234567890,
168
+ duplicate_type: :duplicate_board_with_structure
169
+ },
170
+ select: [
171
+ "id",
172
+ "name",
173
+ "description",
174
+ "url",
175
+ {
176
+ columns: ["id", "title", "type"],
177
+ groups: ["id", "title"]
178
+ }
179
+ ]
180
+ )
181
+
182
+ if response.success?
183
+ board = response.body.dig("data", "duplicate_board", "board")
184
+
185
+ puts "Duplicated Board:"
186
+ puts " ID: #{board['id']}"
187
+ puts " Name: #{board['name']}"
188
+ puts " URL: #{board['url']}"
189
+ puts " Columns: #{board['columns'].length}"
190
+ puts " Groups: #{board['groups'].length}"
191
+ end
192
+ ```
193
+
194
+ ## Verify Duplication
195
+
196
+ Confirm the duplicate was created successfully:
197
+
198
+ ```ruby
199
+ def duplicate_and_verify(client, board_id, duplicate_type)
200
+ # Duplicate
201
+ dup_response = client.board.duplicate(
202
+ args: {
203
+ board_id: board_id,
204
+ duplicate_type: duplicate_type
205
+ },
206
+ select: ["id", "name", { columns: ["id"] }]
207
+ )
208
+
209
+ unless dup_response.success?
210
+ puts "✗ Duplication failed"
211
+ return nil
212
+ end
213
+
214
+ duplicated = dup_response.body.dig("data", "duplicate_board", "board")
215
+
216
+ # Verify by querying
217
+ verify_response = client.board.query(
218
+ args: { ids: [duplicated['id']] },
219
+ select: ["id", "name", { columns: ["id"] }]
220
+ )
221
+
222
+ if verify_response.success?
223
+ board = verify_response.body.dig("data", "boards", 0)
224
+
225
+ puts "✓ Duplication verified"
226
+ puts " Name: #{board['name']}"
227
+ puts " Columns: #{board['columns'].length}"
228
+
229
+ duplicated['id']
230
+ else
231
+ puts "⚠ Duplication succeeded but verification failed"
232
+ duplicated['id']
233
+ end
234
+ end
235
+
236
+ # Usage
237
+ new_board_id = duplicate_and_verify(
238
+ client,
239
+ 1234567890,
240
+ :duplicate_board_with_structure
241
+ )
242
+ ```
243
+
244
+ ## Duplicate with Options
245
+
246
+ Full duplication with all options:
247
+
248
+ ```ruby
249
+ response = client.board.duplicate(
250
+ args: {
251
+ board_id: 1234567890,
252
+ duplicate_type: :duplicate_board_with_structure,
253
+ board_name: "Sprint 15 - Customer Portal",
254
+ workspace_id: 9876543210,
255
+ folder_id: 5555555555,
256
+ keep_subscribers: true
257
+ },
258
+ select: [
259
+ "id",
260
+ "name",
261
+ "url",
262
+ { workspace: ["id", "name"] }
263
+ ]
264
+ )
265
+
266
+ if response.success?
267
+ board = response.body.dig("data", "duplicate_board", "board")
268
+ workspace = board.dig("workspace")
269
+
270
+ puts "✓ Board duplicated successfully"
271
+ puts " Name: #{board['name']}"
272
+ puts " ID: #{board['id']}"
273
+ puts " Workspace: #{workspace&.dig('name')}"
274
+ puts " URL: #{board['url']}"
275
+ end
276
+ ```
277
+
278
+ ## Error Handling
279
+
280
+ Handle duplication errors:
281
+
282
+ ```ruby
283
+ def safe_duplicate(client, board_id, duplicate_type, board_name: nil)
284
+ response = client.board.duplicate(
285
+ args: {
286
+ board_id: board_id,
287
+ duplicate_type: duplicate_type,
288
+ board_name: board_name
289
+ }.compact
290
+ )
291
+
292
+ if response.success?
293
+ board = response.body.dig("data", "duplicate_board", "board")
294
+ puts "✓ Duplicated: #{board['name']} (ID: #{board['id']})"
295
+ board['id']
296
+ else
297
+ puts "✗ Duplication failed"
298
+ puts " Status: #{response.status}"
299
+
300
+ if response.body["error_message"]
301
+ puts " Error: #{response.body['error_message']}"
302
+ end
303
+
304
+ nil
305
+ end
306
+ rescue Monday::AuthorizationError
307
+ puts "✗ Board not found or no permission"
308
+ nil
309
+ rescue Monday::Error => e
310
+ if e.message.include?("invalid_type")
311
+ puts "✗ Invalid duplicate_type"
312
+ else
313
+ puts "✗ API error: #{e.message}"
314
+ end
315
+ nil
316
+ end
317
+
318
+ # Usage
319
+ safe_duplicate(
320
+ client,
321
+ 1234567890,
322
+ :duplicate_board_with_structure,
323
+ board_name: "New Sprint Board"
324
+ )
325
+ ```
326
+
327
+ ## Bulk Duplication
328
+
329
+ Duplicate multiple boards:
330
+
331
+ ```ruby
332
+ def bulk_duplicate(client, board_ids, duplicate_type)
333
+ results = { success: [], failed: [] }
334
+
335
+ board_ids.each do |board_id|
336
+ response = client.board.duplicate(
337
+ args: {
338
+ board_id: board_id,
339
+ duplicate_type: duplicate_type
340
+ }
341
+ )
342
+
343
+ if response.success?
344
+ board = response.body.dig("data", "duplicate_board", "board")
345
+ results[:success] << { original: board_id, duplicate: board['id'] }
346
+ puts "✓ Duplicated: #{board_id} → #{board['id']}"
347
+ else
348
+ results[:failed] << board_id
349
+ puts "✗ Failed: #{board_id}"
350
+ end
351
+ end
352
+
353
+ puts "\nResults:"
354
+ puts " Success: #{results[:success].length}"
355
+ puts " Failed: #{results[:failed].length}"
356
+
357
+ results
358
+ end
359
+
360
+ # Usage
361
+ boards_to_duplicate = [1234567890, 2345678901, 3456789012]
362
+
363
+ results = bulk_duplicate(
364
+ client,
365
+ boards_to_duplicate,
366
+ :duplicate_board_with_structure
367
+ )
368
+ ```
369
+
370
+ ## Template System
371
+
372
+ Create a template duplication system:
373
+
374
+ ```ruby
375
+ TEMPLATES = {
376
+ sprint: {
377
+ board_id: 1234567890,
378
+ duplicate_type: :duplicate_board_with_structure,
379
+ prefix: "Sprint"
380
+ },
381
+ project: {
382
+ board_id: 2345678901,
383
+ duplicate_type: :duplicate_board_with_structure,
384
+ prefix: "Project"
385
+ }
386
+ }.freeze
387
+
388
+ def create_from_template(client, template_name, name)
389
+ template = TEMPLATES[template_name]
390
+
391
+ unless template
392
+ puts "✗ Template '#{template_name}' not found"
393
+ return nil
394
+ end
395
+
396
+ board_name = "#{template[:prefix]} - #{name}"
397
+
398
+ response = client.board.duplicate(
399
+ args: {
400
+ board_id: template[:board_id],
401
+ duplicate_type: template[:duplicate_type],
402
+ board_name: board_name
403
+ }
404
+ )
405
+
406
+ if response.success?
407
+ board = response.body.dig("data", "duplicate_board", "board")
408
+ puts "✓ Created from template: #{board['name']}"
409
+ board['id']
410
+ else
411
+ puts "✗ Template duplication failed"
412
+ nil
413
+ end
414
+ end
415
+
416
+ # Usage
417
+ create_from_template(client, :sprint, "Customer Portal Feature")
418
+ # Creates: "Sprint - Customer Portal Feature"
419
+ ```
420
+
421
+ ## Duplication Types Comparison
422
+
423
+ | Type | Structure | Items | Updates | Use Case |
424
+ |------|-----------|-------|---------|----------|
425
+ | `duplicate_board_with_structure` | ✓ | ✗ | ✗ | New projects with same structure |
426
+ | `duplicate_board_with_pulses` | ✓ | ✓ | ✗ | Backup or fork with data |
427
+ | `duplicate_board_with_pulses_and_updates` | ✓ | ✓ | ✓ | Complete archive or clone |
428
+
429
+ ## Complete Example
430
+
431
+ Full-featured board duplication:
432
+
433
+ ```ruby
434
+ require "monday_ruby"
435
+ require "dotenv/load"
436
+
437
+ Monday.configure do |config|
438
+ config.token = ENV["MONDAY_TOKEN"]
439
+ end
440
+
441
+ client = Monday::Client.new
442
+
443
+ # Original board
444
+ original_board_id = 1234567890
445
+
446
+ # Step 1: Get original board info
447
+ puts "\n📋 Fetching original board..."
448
+ query_response = client.board.query(
449
+ args: { ids: [original_board_id] },
450
+ select: [
451
+ "id",
452
+ "name",
453
+ "description",
454
+ { items: ["id"], columns: ["id"] }
455
+ ]
456
+ )
457
+
458
+ unless query_response.success?
459
+ puts "❌ Original board not found"
460
+ exit
461
+ end
462
+
463
+ original = query_response.body.dig("data", "boards", 0)
464
+
465
+ puts "\nOriginal Board:"
466
+ puts " Name: #{original['name']}"
467
+ puts " Items: #{original['items'].length}"
468
+ puts " Columns: #{original['columns'].length}"
469
+
470
+ # Step 2: Duplicate
471
+ puts "\n🔄 Duplicating board..."
472
+
473
+ dup_response = client.board.duplicate(
474
+ args: {
475
+ board_id: original_board_id,
476
+ duplicate_type: :duplicate_board_with_structure,
477
+ board_name: "#{original['name']} - Copy"
478
+ },
479
+ select: [
480
+ "id",
481
+ "name",
482
+ "url",
483
+ { columns: ["id", "title"], groups: ["id", "title"] }
484
+ ]
485
+ )
486
+
487
+ unless dup_response.success?
488
+ puts "❌ Duplication failed"
489
+ exit
490
+ end
491
+
492
+ duplicated = dup_response.body.dig("data", "duplicate_board", "board")
493
+
494
+ # Step 3: Display results
495
+ puts "\n✓ Duplication Complete!"
496
+ puts "=" * 50
497
+ puts "New Board:"
498
+ puts " Name: #{duplicated['name']}"
499
+ puts " ID: #{duplicated['id']}"
500
+ puts " URL: #{duplicated['url']}"
501
+ puts " Columns: #{duplicated['columns'].length}"
502
+ puts " Groups: #{duplicated['groups'].length}"
503
+ puts "=" * 50
504
+ ```
505
+
506
+ ## Next Steps
507
+
508
+ - [Create boards from scratch](/guides/boards/create)
509
+ - [Update duplicated boards](/guides/boards/update)
510
+ - [Add items to duplicated boards](/guides/items/create)
511
+ - [Query boards](/guides/boards/query)