plan_my_stuff 0.1.0 → 1.0.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 (113) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +595 -0
  3. data/CONFIGURATION.md +487 -0
  4. data/README.md +612 -88
  5. data/app/controllers/plan_my_stuff/application_controller.rb +27 -5
  6. data/app/controllers/plan_my_stuff/comments_controller.rb +50 -19
  7. data/app/controllers/plan_my_stuff/issues/approvals_controller.rb +127 -0
  8. data/app/controllers/plan_my_stuff/issues/closures_controller.rb +53 -0
  9. data/app/controllers/plan_my_stuff/issues/links_controller.rb +129 -0
  10. data/app/controllers/plan_my_stuff/issues/takes_controller.rb +161 -0
  11. data/app/controllers/plan_my_stuff/issues/testings_controller.rb +82 -0
  12. data/app/controllers/plan_my_stuff/issues/viewers_controller.rb +62 -0
  13. data/app/controllers/plan_my_stuff/issues/waitings_controller.rb +55 -0
  14. data/app/controllers/plan_my_stuff/issues_controller.rb +53 -70
  15. data/app/controllers/plan_my_stuff/labels_controller.rb +32 -10
  16. data/app/controllers/plan_my_stuff/project_items/assignments_controller.rb +88 -0
  17. data/app/controllers/plan_my_stuff/project_items/statuses_controller.rb +44 -0
  18. data/app/controllers/plan_my_stuff/project_items_controller.rb +32 -69
  19. data/app/controllers/plan_my_stuff/projects_controller.rb +81 -3
  20. data/app/controllers/plan_my_stuff/testing_project_items/results_controller.rb +67 -0
  21. data/app/controllers/plan_my_stuff/testing_project_items_controller.rb +49 -0
  22. data/app/controllers/plan_my_stuff/testing_projects_controller.rb +121 -0
  23. data/app/controllers/plan_my_stuff/webhooks/aws_controller.rb +202 -0
  24. data/app/controllers/plan_my_stuff/webhooks/github_controller.rb +371 -0
  25. data/app/jobs/plan_my_stuff/application_job.rb +8 -0
  26. data/app/jobs/plan_my_stuff/reminders_sweep_job.rb +75 -0
  27. data/app/views/plan_my_stuff/comments/edit.html.erb +1 -3
  28. data/app/views/plan_my_stuff/comments/partials/_form.html.erb +8 -0
  29. data/app/views/plan_my_stuff/issues/edit.html.erb +2 -4
  30. data/app/views/plan_my_stuff/issues/index.html.erb +5 -5
  31. data/app/views/plan_my_stuff/issues/new.html.erb +2 -4
  32. data/app/views/plan_my_stuff/issues/partials/_approvals.html.erb +108 -0
  33. data/app/views/plan_my_stuff/issues/partials/_form.html.erb +11 -6
  34. data/app/views/plan_my_stuff/issues/partials/_labels.html.erb +4 -3
  35. data/app/views/plan_my_stuff/issues/partials/_links.html.erb +113 -0
  36. data/app/views/plan_my_stuff/issues/partials/_viewers.html.erb +4 -3
  37. data/app/views/plan_my_stuff/issues/show.html.erb +67 -6
  38. data/app/views/plan_my_stuff/partials/_flash.html.erb +3 -0
  39. data/app/views/plan_my_stuff/projects/edit.html.erb +5 -0
  40. data/app/views/plan_my_stuff/projects/index.html.erb +18 -2
  41. data/app/views/plan_my_stuff/projects/new.html.erb +5 -0
  42. data/app/views/plan_my_stuff/projects/partials/_form.html.erb +30 -0
  43. data/app/views/plan_my_stuff/projects/show.html.erb +30 -11
  44. data/app/views/plan_my_stuff/testing_project_items/new.html.erb +10 -0
  45. data/app/views/plan_my_stuff/testing_project_items/results/new.html.erb +20 -0
  46. data/app/views/plan_my_stuff/testing_projects/edit.html.erb +5 -0
  47. data/app/views/plan_my_stuff/testing_projects/new.html.erb +5 -0
  48. data/app/views/plan_my_stuff/testing_projects/partials/_form.html.erb +40 -0
  49. data/app/views/plan_my_stuff/testing_projects/partials/_item.html.erb +52 -0
  50. data/app/views/plan_my_stuff/testing_projects/partials/items/_form.html.erb +36 -0
  51. data/app/views/plan_my_stuff/testing_projects/show.html.erb +65 -0
  52. data/config/routes.rb +43 -15
  53. data/lib/generators/plan_my_stuff/install/templates/initializer.rb +302 -20
  54. data/lib/plan_my_stuff/application_record.rb +158 -1
  55. data/lib/plan_my_stuff/approval.rb +88 -0
  56. data/lib/plan_my_stuff/archive/sweep.rb +85 -0
  57. data/lib/plan_my_stuff/archive.rb +12 -0
  58. data/lib/plan_my_stuff/attachment.rb +83 -0
  59. data/lib/plan_my_stuff/attachment_uploader.rb +245 -0
  60. data/lib/plan_my_stuff/aws_sns_simulator.rb +116 -0
  61. data/lib/plan_my_stuff/base_metadata.rb +25 -28
  62. data/lib/plan_my_stuff/base_project.rb +502 -0
  63. data/lib/plan_my_stuff/base_project_extractions/graphql_hydration.rb +186 -0
  64. data/lib/plan_my_stuff/base_project_item.rb +588 -0
  65. data/lib/plan_my_stuff/base_project_metadata.rb +16 -0
  66. data/lib/plan_my_stuff/cache.rb +197 -0
  67. data/lib/plan_my_stuff/client.rb +139 -64
  68. data/lib/plan_my_stuff/comment.rb +225 -100
  69. data/lib/plan_my_stuff/comment_metadata.rb +68 -5
  70. data/lib/plan_my_stuff/configuration.rb +459 -28
  71. data/lib/plan_my_stuff/custom_fields.rb +96 -12
  72. data/lib/plan_my_stuff/engine.rb +14 -2
  73. data/lib/plan_my_stuff/errors.rb +65 -5
  74. data/lib/plan_my_stuff/graphql/queries.rb +454 -0
  75. data/lib/plan_my_stuff/issue.rb +1097 -166
  76. data/lib/plan_my_stuff/issue_extractions/approvals.rb +370 -0
  77. data/lib/plan_my_stuff/issue_extractions/links.rb +525 -0
  78. data/lib/plan_my_stuff/issue_extractions/viewers.rb +75 -0
  79. data/lib/plan_my_stuff/issue_extractions/waiting.rb +171 -0
  80. data/lib/plan_my_stuff/issue_field.rb +126 -0
  81. data/lib/plan_my_stuff/issue_field_translation.rb +67 -0
  82. data/lib/plan_my_stuff/issue_field_value_set.rb +68 -0
  83. data/lib/plan_my_stuff/issue_metadata.rb +132 -21
  84. data/lib/plan_my_stuff/label.rb +100 -13
  85. data/lib/plan_my_stuff/link.rb +144 -0
  86. data/lib/plan_my_stuff/markdown.rb +13 -7
  87. data/lib/plan_my_stuff/metadata_parser.rb +51 -12
  88. data/lib/plan_my_stuff/notifications.rb +148 -0
  89. data/lib/plan_my_stuff/pipeline/completed_sweep.rb +46 -0
  90. data/lib/plan_my_stuff/pipeline/issue_linker.rb +62 -0
  91. data/lib/plan_my_stuff/pipeline/status.rb +40 -0
  92. data/lib/plan_my_stuff/pipeline/testing.rb +23 -0
  93. data/lib/plan_my_stuff/pipeline.rb +310 -0
  94. data/lib/plan_my_stuff/project.rb +63 -465
  95. data/lib/plan_my_stuff/project_item.rb +3 -409
  96. data/lib/plan_my_stuff/project_item_metadata.rb +55 -0
  97. data/lib/plan_my_stuff/project_metadata.rb +47 -0
  98. data/lib/plan_my_stuff/reminders/closer.rb +70 -0
  99. data/lib/plan_my_stuff/reminders/fire.rb +129 -0
  100. data/lib/plan_my_stuff/reminders/sweep.rb +54 -0
  101. data/lib/plan_my_stuff/reminders.rb +12 -0
  102. data/lib/plan_my_stuff/repo.rb +145 -0
  103. data/lib/plan_my_stuff/test_helpers.rb +265 -25
  104. data/lib/plan_my_stuff/testing_project.rb +292 -0
  105. data/lib/plan_my_stuff/testing_project_item.rb +218 -0
  106. data/lib/plan_my_stuff/testing_project_metadata.rb +94 -0
  107. data/lib/plan_my_stuff/user_resolver.rb +24 -3
  108. data/lib/plan_my_stuff/verifier.rb +10 -0
  109. data/lib/plan_my_stuff/version.rb +2 -2
  110. data/lib/plan_my_stuff/webhook_replayer.rb +292 -0
  111. data/lib/plan_my_stuff.rb +55 -20
  112. data/lib/tasks/plan_my_stuff.rake +331 -0
  113. metadata +99 -4
@@ -1,11 +1,12 @@
1
- <% if issue.labels.any? %>
1
+ <%# locals: (issue:) %>
2
+ <% if issue.labels.present? %>
2
3
  <% issue.labels.each do |label| %>
3
4
  <span>
4
5
  <%= label %>
5
6
  <%=
6
7
  button_to(
7
8
  'x',
8
- plan_my_stuff.issue_remove_label_path(issue.number, label),
9
+ plan_my_stuff.issue_label_path(issue.number, label),
9
10
  method: :delete,
10
11
  form: { style: 'display:inline' }
11
12
  )
@@ -16,7 +17,7 @@
16
17
  <em>No labels</em>
17
18
  <% end %>
18
19
 
19
- <%= form_with(url: plan_my_stuff.issue_add_label_path(issue.number), method: :post, local: true) do |form| %>
20
+ <%= form_with(url: plan_my_stuff.issue_labels_path(issue.number), method: :post, local: true) do |form| %>
20
21
  <%= form.label(:label_name, 'Add label') %>
21
22
  <%= form.text_field(:label_name) %>
22
23
  <%= form.submit('Add') %>
@@ -0,0 +1,113 @@
1
+ <%# locals: (issue:, support_user:) %>
2
+ <%
3
+ # read_only sections have no add form; remove_only sections allow X but
4
+ # no add (blocking is created from the blocked side; duplicate_of is
5
+ # created via mark_duplicate! and cleared by reopening on GitHub).
6
+ sections = [
7
+ {
8
+ type: 'parent',
9
+ label: 'Parent',
10
+ single: true,
11
+ add_form: true,
12
+ removable: true,
13
+ targets: [issue.parent].compact
14
+ },
15
+ {
16
+ type: 'sub_ticket',
17
+ label: 'Sub-tickets',
18
+ single: false,
19
+ add_form: true,
20
+ removable: true,
21
+ targets: issue.sub_tickets
22
+ },
23
+ {
24
+ type: 'blocked_by',
25
+ label: 'Blocked by',
26
+ single: false,
27
+ add_form: true,
28
+ removable: true,
29
+ targets: issue.blocked_by
30
+ },
31
+ {
32
+ type: 'blocking',
33
+ label: 'Blocking',
34
+ single: false,
35
+ add_form: false,
36
+ removable: false,
37
+ targets: issue.blocking
38
+ },
39
+ {
40
+ type: 'related',
41
+ label: 'Related',
42
+ single: false,
43
+ add_form: true,
44
+ removable: true,
45
+ targets: issue.related
46
+ },
47
+ {
48
+ type: 'duplicate_of',
49
+ label: 'Duplicate of',
50
+ single: true,
51
+ add_form: false,
52
+ removable: false,
53
+ targets: [issue.duplicate_of].compact
54
+ },
55
+ ]
56
+ visible_sections = support_user ? sections : sections.select { |s| s[:type] == 'related' }
57
+ %>
58
+
59
+ <section aria-label="Ticket links">
60
+ <h3>Links</h3>
61
+ <% visible_sections.each do |section| %>
62
+ <div>
63
+ <h4><%= section[:label] %></h4>
64
+ <% if section[:targets].present? %>
65
+ <ul>
66
+ <% section[:targets].each do |target| %>
67
+ <li>
68
+ <%=
69
+ link_to(
70
+ "#{target.repo.full_name}##{target.number} - #{target.title}",
71
+ plan_my_stuff.issue_path(target),
72
+ )
73
+ %>
74
+ <% if section[:removable] %>
75
+ <%
76
+ link_id = "#{section[:type]}:#{target.repo.full_name}:#{target.number}"
77
+ %>
78
+ <%=
79
+ button_to(
80
+ 'Remove',
81
+ plan_my_stuff.issue_link_path(issue, link_id),
82
+ method: :delete,
83
+ form: { style: 'display:inline' },
84
+ )
85
+ %>
86
+ <% end %>
87
+ </li>
88
+ <% end %>
89
+ </ul>
90
+ <% else %>
91
+ <p><em>None</em></p>
92
+ <% end %>
93
+
94
+ <% if section[:add_form] && (!section[:single] || section[:targets].empty?) %>
95
+ <%=
96
+ form_with(
97
+ scope: :link,
98
+ url: plan_my_stuff.issue_links_path(issue),
99
+ method: :post,
100
+ local: true,
101
+ ) do |form|
102
+ %>
103
+ <%= form.hidden_field(:type, value: section[:type]) %>
104
+ <%= form.label(:issue_number, 'Issue #') %>
105
+ <%= form.number_field(:issue_number) %>
106
+ <%= form.label(:repo, 'Repo (optional)') %>
107
+ <%= form.text_field(:repo, placeholder: issue.repo.full_name) %>
108
+ <%= form.submit("Add #{section[:label].downcase}") %>
109
+ <% end %>
110
+ <% end %>
111
+ </div>
112
+ <% end %>
113
+ </section>
@@ -1,7 +1,8 @@
1
+ <%# locals: (issue:) %>
1
2
  <h2>Manage Viewers</h2>
2
3
 
3
4
  <% viewers = issue.metadata.visibility_allowlist %>
4
- <% if viewers.any? %>
5
+ <% if viewers.present? %>
5
6
  <ul>
6
7
  <% viewers.each do |viewer_id| %>
7
8
  <li>
@@ -9,7 +10,7 @@
9
10
  <%=
10
11
  button_to(
11
12
  'Remove',
12
- plan_my_stuff.remove_viewer_issue_path(issue.number, viewer_id: viewer_id),
13
+ plan_my_stuff.issue_viewer_path(issue, viewer_id),
13
14
  method: :delete
14
15
  )
15
16
  %>
@@ -20,7 +21,7 @@
20
21
  <p>No viewers added.</p>
21
22
  <% end %>
22
23
 
23
- <%= form_with(url: plan_my_stuff.add_viewers_issue_path(issue.number), method: :post) do |form| %>
24
+ <%= form_with(url: plan_my_stuff.issue_viewers_path(issue), method: :post) do |form| %>
24
25
  <div>
25
26
  <%= form.label(:viewer_ids, 'Add viewer IDs (comma-separated)') %>
26
27
  <%= form.text_field(:viewer_ids) %>
@@ -1,11 +1,45 @@
1
1
  <h1><%= @issue.title %> <small>#<%= @issue.number %></small></h1>
2
2
 
3
3
  <p>
4
- <%= link_to('Edit', plan_my_stuff.edit_issue_path(@issue.number)) %>
4
+ <%= link_to('Edit', plan_my_stuff.edit_issue_path(@issue)) %>
5
+ <% if @support_user && @issue.html_url.present? %>
6
+ <%= link_to('View on GitHub', @issue.html_url, target: '_blank', rel: 'noopener') %>
7
+ <% end %>
5
8
  <% if @issue.state == 'open' %>
6
- <%= button_to('Close Issue', plan_my_stuff.close_issue_path(@issue.number), method: :patch) %>
9
+ <%= button_to('Close Issue', plan_my_stuff.issue_closure_path(@issue), method: :post) %>
7
10
  <% else %>
8
- <%= button_to('Reopen Issue', plan_my_stuff.reopen_issue_path(@issue.number), method: :patch) %>
11
+ <%= button_to('Reopen Issue', plan_my_stuff.issue_closure_path(@issue), method: :delete) %>
12
+ <% end %>
13
+ <% if @support_user && @issue.state == 'open' %>
14
+ <% if @issue.metadata.waiting_on_user_at.present? %>
15
+ <%= button_to('Mark replied', plan_my_stuff.issue_waiting_path(@issue), method: :delete) %>
16
+ <% else %>
17
+ <%= button_to('Mark waiting', plan_my_stuff.issue_waiting_path(@issue), method: :post) %>
18
+ <% end %>
19
+ <% end %>
20
+ <% if @support_user && @pipeline_enabled && @pipeline_item.nil? && @issue.assignees.blank? %>
21
+ <%= button_to('Take', plan_my_stuff.issue_take_path(@issue), method: :post) %>
22
+ <% end %>
23
+ <%
24
+ show_unassign =
25
+ @support_user &&
26
+ @pipeline_enabled &&
27
+ @current_user_login.present? &&
28
+ @issue.assignees.include?(@current_user_login)
29
+ %>
30
+ <% if show_unassign %>
31
+ <%= button_to('Unassign', plan_my_stuff.issue_take_path(@issue), method: :delete) %>
32
+ <% end %>
33
+ <% if @support_user && @pipeline_enabled && @pipeline_item.present? %>
34
+ <% testing_value = @pipeline_item.field_values[PlanMyStuff.configuration.pipeline_testing_field_name] %>
35
+ <% if testing_value == PlanMyStuff.configuration.pipeline_testing_values[:active] %>
36
+ <%= button_to('Clear testing', plan_my_stuff.issue_testing_path(@issue), method: :delete) %>
37
+ <% else %>
38
+ <%= button_to('Request testing', plan_my_stuff.issue_testing_path(@issue), method: :post) %>
39
+ <% end %>
40
+ <% end %>
41
+ <% if @support_user %>
42
+ <%= link_to('Start Testing Project', plan_my_stuff.new_testing_project_path(subject_url: @issue.html_url)) %>
9
43
  <% end %>
10
44
  </p>
11
45
 
@@ -27,15 +61,42 @@
27
61
 
28
62
  <hr>
29
63
 
64
+ <%=
65
+ render({
66
+ partial: 'plan_my_stuff/issues/partials/links',
67
+ locals: { issue: @issue, support_user: @support_user },
68
+ })
69
+ %>
70
+
71
+ <hr>
72
+
73
+ <%=
74
+ render({
75
+ partial: 'plan_my_stuff/issues/partials/approvals',
76
+ locals: {
77
+ issue: @issue,
78
+ support_user: @support_user,
79
+ current_user_id_local: @current_user_id,
80
+ },
81
+ })
82
+ %>
83
+
84
+ <hr>
85
+
30
86
  <h2>Comments (<%= @comments.size %>)</h2>
31
87
 
32
- <% if @comments.any? %>
88
+ <% if @comments.present? %>
33
89
  <% @comments.each do |comment| %>
34
90
  <div>
35
91
  <%= PlanMyStuff::Markdown.render(comment.body || '').html_safe %>
36
92
  <% if comment.pms_comment? && (@support_user || comment.metadata.created_by == @current_user_id) %>
37
93
  <p>
38
- <%= link_to('Edit', plan_my_stuff.edit_issue_comment_path(@issue.number, comment.id)) %>
94
+ <%= link_to('Edit', plan_my_stuff.edit_issue_comment_path(@issue, comment.id)) %>
95
+ </p>
96
+ <% end %>
97
+ <% if @support_user && comment.html_url.present? %>
98
+ <p>
99
+ <%= link_to('View on GitHub', comment.html_url, target: '_blank', rel: 'noopener') %>
39
100
  </p>
40
101
  <% end %>
41
102
  </div>
@@ -51,7 +112,7 @@
51
112
  partial: 'plan_my_stuff/comments/partials/form',
52
113
  locals: {
53
114
  issue: @issue,
54
- comment: PlanMyStuff::Comment.new,
115
+ comment: PlanMyStuff::Comment.new(visibility: :public),
55
116
  support_user: @support_user,
56
117
  },
57
118
  })
@@ -0,0 +1,3 @@
1
+ <% if flash[:error].present? %>
2
+ <p role="alert" style="color: red;"><%= flash[:error] %></p>
3
+ <% end %>
@@ -0,0 +1,5 @@
1
+ <h1>Edit Project #<%= @project.number %></h1>
2
+
3
+ <%= render({ partial: 'plan_my_stuff/partials/flash' }) %>
4
+
5
+ <%= render({ partial: 'plan_my_stuff/projects/partials/form', locals: { project: @project } }) %>
@@ -1,13 +1,29 @@
1
1
  <h1>Projects</h1>
2
2
 
3
- <% if @projects.any? %>
3
+ <p>
4
+ <%= link_to('All', plan_my_stuff.projects_path(filter: 'all')) %>
5
+ <%= link_to('Regular', plan_my_stuff.projects_path(filter: 'regular')) %>
6
+ <%= link_to('Testing', plan_my_stuff.projects_path(filter: 'testing')) %>
7
+ </p>
8
+
9
+ <% if @projects.present? %>
4
10
  <ul>
5
11
  <% @projects.each do |project| %>
6
12
  <li>
7
- <%= link_to(project.title, plan_my_stuff.project_path(project.number)) %>
13
+ <% if project.is_a?(PlanMyStuff::TestingProject) %>
14
+ <%= link_to(project.title, plan_my_stuff.testing_project_path(project.number)) %>
15
+ <span>[Testing]</span>
16
+ <% else %>
17
+ <%= link_to(project.title, plan_my_stuff.project_path(project.number)) %>
18
+ <% end %>
8
19
  </li>
9
20
  <% end %>
10
21
  </ul>
11
22
  <% else %>
12
23
  <p>No projects found.</p>
13
24
  <% end %>
25
+
26
+ <p><%= link_to('New Project', plan_my_stuff.new_project_path) %></p>
27
+ <% if @support_user %>
28
+ <p><%= link_to('New Testing Project', plan_my_stuff.new_testing_project_path) %></p>
29
+ <% end %>
@@ -0,0 +1,5 @@
1
+ <h1>New Project</h1>
2
+
3
+ <%= render({ partial: 'plan_my_stuff/partials/flash' }) %>
4
+
5
+ <%= render({ partial: 'plan_my_stuff/projects/partials/form', locals: { project: @project } }) %>
@@ -0,0 +1,30 @@
1
+ <%# locals: (project:) %>
2
+ <%
3
+ persisted = project.persisted?
4
+ url =
5
+ if persisted
6
+ plan_my_stuff.project_path(project.number)
7
+ else
8
+ plan_my_stuff.projects_path
9
+ end
10
+ %>
11
+ <%= form_with(url: url, method: persisted ? :patch : :post, scope: :project) do |form| %>
12
+ <div>
13
+ <%= form.label(:title, 'Title') %>
14
+ <%= form.text_field(:title, value: project.title, required: true) %>
15
+ </div>
16
+
17
+ <div>
18
+ <%= form.label(:description, 'Description') %>
19
+ <%= form.text_field(:description, value: project.description) %>
20
+ </div>
21
+
22
+ <div>
23
+ <%= form.label(:readme, 'Readme') %>
24
+ <%= form.text_area(:readme, rows: 8, value: project.readme) %>
25
+ </div>
26
+
27
+ <div>
28
+ <%= form.submit(persisted ? 'Update Project' : 'Create Project') %>
29
+ </div>
30
+ <% end %>
@@ -1,6 +1,13 @@
1
1
  <h1><%= @project.title %></h1>
2
2
 
3
- <% if @statuses.any? %>
3
+ <p>
4
+ <%= link_to('Edit', plan_my_stuff.edit_project_path(@project.number)) %>
5
+ <% if @support_user && @project.url.present? %>
6
+ <%= link_to('View on GitHub', @project.url, target: '_blank', rel: 'noopener') %>
7
+ <% end %>
8
+ </p>
9
+
10
+ <% if @statuses.present? %>
4
11
  <table>
5
12
  <thead>
6
13
  <tr>
@@ -16,18 +23,20 @@
16
23
  <% items = @items_by_status[status] || [] %>
17
24
  <% items.each do |item| %>
18
25
  <div style="border: 1px solid black; margin: 1em">
19
- <% if item.number.present? %>
20
- <strong><%= link_to(item.title, plan_my_stuff.issue_path(item.number)) %></strong>
26
+ <% unless item.draft? %>
27
+ <strong>
28
+ <%= link_to(item.title, plan_my_stuff.issue_path(item.issue.to_param)) %>
29
+ </strong>
21
30
  <% else %>
22
31
  <strong><%= item.title %></strong>
23
32
  <% end %>
24
- <% if item.number.present? %>
33
+ <% unless item.draft? %>
25
34
  <small>#<%= item.number %></small>
26
35
  <% end %>
27
36
 
28
37
  <%=
29
38
  form_with(
30
- url: plan_my_stuff.move_project_item_path(@project.number, item.id),
39
+ url: plan_my_stuff.project_item_status_path(@project.number, item.id),
31
40
  method: :patch,
32
41
  local: true,
33
42
  ) do |form|
@@ -36,21 +45,21 @@
36
45
  <% end %>
37
46
 
38
47
  <% assignees = item.field_values['Assignees'] || [] %>
39
- <% if assignees.any? %>
48
+ <% if assignees.present? %>
40
49
  <div>
41
50
  <% assignees.each do |username| %>
42
51
  <span>
43
52
  <%= username %>
44
53
  <%=
45
54
  form_with(
46
- url: plan_my_stuff.unassign_project_item_path(@project.number, item.id),
47
- method: :patch,
55
+ url: plan_my_stuff.project_item_assignment_path(@project.number, item.id),
56
+ method: :delete,
48
57
  local: true,
49
- style: 'display: inline',
58
+ html: { style: 'display: inline' },
50
59
  ) do |form|
51
60
  %>
52
61
  <%= form.hidden_field(:username, value: username) %>
53
- <%= form.submit('×', title: "Unassign #{username}") %>
62
+ <%= form.submit('x', title: "Unassign #{username}") %>
54
63
  <% end %>
55
64
  </span>
56
65
  <% end %>
@@ -59,7 +68,7 @@
59
68
 
60
69
  <%=
61
70
  form_with(
62
- url: plan_my_stuff.assign_project_item_path(@project.number, item.id),
71
+ url: plan_my_stuff.project_item_assignment_path(@project.number, item.id),
63
72
  method: :patch,
64
73
  local: true,
65
74
  ) do |form|
@@ -67,6 +76,16 @@
67
76
  <%= form.text_field(:assignee, placeholder: 'GitHub username') %>
68
77
  <%= form.submit('Assign') %>
69
78
  <% end %>
79
+
80
+ <%=
81
+ form_with(
82
+ url: plan_my_stuff.project_item_path(@project.number, item.id),
83
+ method: :delete,
84
+ local: true,
85
+ ) do |form|
86
+ %>
87
+ <%= form.submit('Remove from project') %>
88
+ <% end %>
70
89
  </div>
71
90
  <% end %>
72
91
  <% if items.empty? %>
@@ -0,0 +1,10 @@
1
+ <h1>Add Item to <%= @project.title %></h1>
2
+
3
+ <%= render({ partial: 'plan_my_stuff/partials/flash' }) %>
4
+
5
+ <%=
6
+ render({
7
+ partial: 'plan_my_stuff/testing_projects/partials/items/form',
8
+ locals: { project: @project },
9
+ })
10
+ %>
@@ -0,0 +1,20 @@
1
+ <h1>Fail Item</h1>
2
+
3
+ <%= render({ partial: 'plan_my_stuff/partials/flash' }) %>
4
+
5
+ <%= form_with(
6
+ url: plan_my_stuff.testing_project_item_result_path(@project_number, @item_id),
7
+ method: :post,
8
+ local: true,
9
+ ) do |form| %>
10
+ <%= form.hidden_field(:result, value: 'fail') %>
11
+
12
+ <div>
13
+ <%= form.label(:result_notes, 'Result Notes') %>
14
+ <%= form.text_area(:result_notes, rows: 5, required: true) %>
15
+ </div>
16
+
17
+ <div>
18
+ <%= form.submit('Submit Failure') %>
19
+ </div>
20
+ <% end %>
@@ -0,0 +1,5 @@
1
+ <h1>Edit Testing Project #<%= @project.number %></h1>
2
+
3
+ <%= render({ partial: 'plan_my_stuff/partials/flash' }) %>
4
+
5
+ <%= render({ partial: 'plan_my_stuff/testing_projects/partials/form', locals: { project: @project } }) %>
@@ -0,0 +1,5 @@
1
+ <h1>New Testing Project</h1>
2
+
3
+ <%= render({ partial: 'plan_my_stuff/partials/flash' }) %>
4
+
5
+ <%= render({ partial: 'plan_my_stuff/testing_projects/partials/form', locals: { project: @project } }) %>
@@ -0,0 +1,40 @@
1
+ <%# locals: (project:) %>
2
+ <%
3
+ persisted = project.persisted?
4
+ url =
5
+ if persisted
6
+ plan_my_stuff.testing_project_path(project.number)
7
+ else
8
+ plan_my_stuff.testing_projects_path
9
+ end
10
+ %>
11
+ <%= form_with(url: url, method: persisted ? :patch : :post, scope: :testing_project) do |form| %>
12
+ <div>
13
+ <%= form.label(:title, 'Title') %>
14
+ <%= form.text_field(:title, value: project.title, required: true) %>
15
+ </div>
16
+
17
+ <div>
18
+ <%= form.label(:description, 'Description') %>
19
+ <%= form.text_field(:description, value: project.description) %>
20
+ </div>
21
+
22
+ <div>
23
+ <%= form.label(:subject_urls, 'Subject URLs (one per line)') %>
24
+ <%= form.text_area(:subject_urls, rows: 4, value: Array.wrap(project.metadata&.subject_urls).join("\n")) %>
25
+ </div>
26
+
27
+ <div>
28
+ <%= form.label(:due_date, 'Due Date') %>
29
+ <%= form.date_field(:due_date, value: project.metadata&.due_date&.strftime('%F')) %>
30
+ </div>
31
+
32
+ <div>
33
+ <%= form.label(:deadline_miss_reason, 'Deadline Miss Reason') %>
34
+ <%= form.text_field(:deadline_miss_reason, value: project.metadata&.deadline_miss_reason) %>
35
+ </div>
36
+
37
+ <div>
38
+ <%= form.submit(persisted ? 'Update Testing Project' : 'Create Testing Project') %>
39
+ </div>
40
+ <% end %>
@@ -0,0 +1,52 @@
1
+ <%# locals: (item:, project:, statuses:) %>
2
+ <div style="border: 1px solid black; margin: 1em; padding: 0.5em">
3
+ <% if item.draft? %>
4
+ <strong><%= item.title %></strong>
5
+ <% else %>
6
+ <strong><%= link_to(item.title, plan_my_stuff.issue_path(item.issue.to_param)) %></strong>
7
+ <small>#<%= item.number %></small>
8
+ <% end %>
9
+
10
+ <%=
11
+ form_with(
12
+ url: plan_my_stuff.testing_project_item_status_path(project.number, item.id),
13
+ method: :patch,
14
+ local: true,
15
+ ) do |form|
16
+ %>
17
+ <%= form.select(:status, statuses, { selected: item.status }, { onchange: 'this.form.requestSubmit();' }) %>
18
+ <% end %>
19
+
20
+ <% if item.field_values['Testers'].present? %>
21
+ <div><strong>Testers:</strong> <%= item.field_values['Testers'] %></div>
22
+ <% end %>
23
+
24
+ <% if item.field_values['Watchers'].present? %>
25
+ <div><strong>Watchers:</strong> <%= item.field_values['Watchers'] %></div>
26
+ <% end %>
27
+
28
+ <% if item.field_values['Due Date'].present? %>
29
+ <div><strong>Due:</strong> <%= item.field_values['Due Date'] %></div>
30
+ <% end %>
31
+
32
+ <% if item.field_values['Result Notes'].present? %>
33
+ <div><strong>Notes:</strong> <%= item.field_values['Result Notes'] %></div>
34
+ <% end %>
35
+
36
+ <% if item.field_values['Passed At'].present? %>
37
+ <div><strong>Passed at:</strong> <%= item.field_values['Passed At'] %></div>
38
+ <% end %>
39
+
40
+ <div>
41
+ <%=
42
+ button_to(
43
+ 'Pass',
44
+ plan_my_stuff.testing_project_item_result_path(project.number, item.id),
45
+ method: :post,
46
+ params: { result: 'pass' },
47
+ )
48
+ %>
49
+
50
+ <%= link_to('Fail', plan_my_stuff.new_testing_project_item_result_path(project.number, item.id)) %>
51
+ </div>
52
+ </div>
@@ -0,0 +1,36 @@
1
+ <%# locals: (project:) %>
2
+ <%= form_with(url: plan_my_stuff.testing_project_items_path(project.number), method: :post, local: true) do |form| %>
3
+ <div>
4
+ <%= form.label(:title, 'Title') %>
5
+ <%= form.text_field(:title, required: true) %>
6
+ </div>
7
+
8
+ <div>
9
+ <%= form.label(:body, 'Body') %>
10
+ <%= form.text_area(:body, rows: 4) %>
11
+ </div>
12
+
13
+ <div>
14
+ <%= form.label(:testers, 'Testers (user ids, comma separated)') %>
15
+ <%= form.text_field(:testers) %>
16
+ </div>
17
+
18
+ <div>
19
+ <%= form.label(:watchers, 'Watchers (user ids, comma separated)') %>
20
+ <%= form.text_field(:watchers) %>
21
+ </div>
22
+
23
+ <div>
24
+ <%= form.label(:pass_mode, 'Pass Mode') %>
25
+ <%= form.select(:pass_mode, [['All testers must pass', 'all'], ['Any tester can pass', 'any']], { selected: 'all' }) %>
26
+ </div>
27
+
28
+ <div>
29
+ <%= form.label(:due_date, 'Due Date') %>
30
+ <%= form.date_field(:due_date) %>
31
+ </div>
32
+
33
+ <div>
34
+ <%= form.submit('Add Item') %>
35
+ </div>
36
+ <% end %>