This is an automated email from the ASF dual-hosted git repository.

rubys pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/whimsy.git

commit d62a8d31340aba29fad461b6c45f420639019d4a
Author: Sam Ruby <ru...@intertwingly.net>
AuthorDate: Wed Oct 11 12:15:24 2017 -0400

    rough in a prod to non-responsive PMCs
---
 www/board/agenda/routes.rb                         |  2 +-
 www/board/agenda/templates/non-responsive.txt      | 43 ++++++++++++++++++++++
 .../agenda/views/actions/reminder-text.json.rb     |  1 +
 www/board/agenda/views/buttons/reminders.js.rb     | 32 ++++++++++++++--
 www/board/agenda/views/models/agenda.js.rb         |  7 ++++
 www/board/agenda/views/pages/missing.js.rb         | 38 +++++++++++++++----
 www/board/agenda/views/router.js.rb                | 10 +++--
 7 files changed, 118 insertions(+), 15 deletions(-)

diff --git a/www/board/agenda/routes.rb b/www/board/agenda/routes.rb
index 9805570..b76400d 100755
--- a/www/board/agenda/routes.rb
+++ b/www/board/agenda/routes.rb
@@ -290,7 +290,7 @@ get '/json/potential-actions' do
   _json :'actions/potential-actions'
 end
 
-get %r{/json/(reminder[12])} do |reminder|
+get %r{/json/(reminder[12]|non-responsive)} do |reminder|
   @reminder = reminder
   _json :'actions/reminder-text'
 end
diff --git a/www/board/agenda/templates/non-responsive.txt 
b/www/board/agenda/templates/non-responsive.txt
new file mode 100644
index 0000000..a01b8d3
--- /dev/null
+++ b/www/board/agenda/templates/non-responsive.txt
@@ -0,0 +1,43 @@
+Subject: ASF Board Report for [project] - Repeated Reminder for [month] [year]
+
+Dear [project] community,
+
+In the governance model at the ASF the board delegates responsibility for
+managing projects to PMCs. To enable to board to provide oversight across the
+foundation, the PMCs are tasked with providing the board with a quarterly
+report on the health of the project. The board has noticed that the reports
+for [project] have been missed for a number of months.
+
+The reports to the board are normally written by the PMC chair but all PMC
+members have an individual responsibility to ensure that a report is
+submitted. If the PMC chair is not available then any PMC member can submit
+the report. If you need help with this process, please reach out to
+bo...@apache.org
+
+Please ensure that a report for [project] is submitted to the board for the
+next meeting.
+
+If the PMC chair is not going to be available for an extended period of time
+it may make sense to rotate the PMC chair. Rotating the PMC chair does not
+mean the current chair has failed. People's situations and interests change,
+and rotation is good as it allows more people to become familiar with that
+role. Again, if assistance is required with this process, please feel free to
+reach out to bo...@apache.org
+
+As projects mature, they will naturally reach a point where activity reduces
+to a level that the project is no longer sustainable. At Apache, projects
+reach this stage when there are no longer 3 active PMC members providing
+oversight. Projects that reach this stage are placed in the attic[1].  If
+[project] has reached this point, please reach out to the Attic project to
+arrange transfer. On the other hand, if your project is mostly dormant but
+still has at least three active PMC members it can stay in that state for as
+long as needed. If your project is in such a state, please mention that in
+your report and verify the PMC's state at regular intervals.
+
+Finally, if you have any questions please feel free to reach out to
+bo...@apache.org.
+
+Thanks,
+The ASF Board
+
+[1] (http://attic.apache.org/
diff --git a/www/board/agenda/views/actions/reminder-text.json.rb 
b/www/board/agenda/views/actions/reminder-text.json.rb
index bffbc86..cc57c05 100644
--- a/www/board/agenda/views/actions/reminder-text.json.rb
+++ b/www/board/agenda/views/actions/reminder-text.json.rb
@@ -3,6 +3,7 @@ require 'active_support/core_ext/integer/inflections.rb'
 
 # read template for the reminders
 @reminder.untaint if @reminder =~ /^reminder\d$/
+@reminder.untaint if @reminder =~ /^non-responsive$/
 template = File.read("templates/#@reminder.txt")
 
 # find the latest agenda
diff --git a/www/board/agenda/views/buttons/reminders.js.rb 
b/www/board/agenda/views/buttons/reminders.js.rb
index bdccedc..8c4269b 100644
--- a/www/board/agenda/views/buttons/reminders.js.rb
+++ b/www/board/agenda/views/buttons/reminders.js.rb
@@ -15,6 +15,7 @@ class InitialReminder < Vue
     {
       text: 'send initial reminders',
       class: 'btn_primary',
+      disabled: true,
       data_toggle: 'modal',
       data_target: '#reminder-form'
     }
@@ -22,7 +23,9 @@ class InitialReminder < Vue
 
   # fetch email template
   def loadText(event)
-    if event.target.textContent == 'send initial reminders'
+    if event.target.textContent.include? 'non-responsive'
+      reminder = 'non-responsive'
+    elsif event.target.textContent.include? 'initial'
       reminder = 'reminder1'
     else
       reminder = 'reminder2'
@@ -32,14 +35,21 @@ class InitialReminder < Vue
       @subject = response.subject
       @message = response.body
       @disabled = false
+
+      if reminder == 'non-responsive'
+        @selection = 'inactive'
+      else
+        @selection = 'active'
+      end
     end
   end
 
   # wire up event handlers
   def mounted()
     Vue.nextTick do
-      Array(document.querySelectorAll('.btn-primary')).each do |button|
+      Array(document.querySelectorAll('button')).each do |button|
         if button.getAttribute('data-target') == '#reminder-form'
+          button.disabled = false
           button.addEventListener :click, self.loadText
         end
       end
@@ -69,6 +79,7 @@ class InitialReminder < Vue
 
   # on click, disable the input fields and buttons and submit
   def click(event)
+    event.target.disabled = true
     @disabled = true
     dryrun = (event.target.textContent == 'Dry Run')
 
@@ -83,7 +94,9 @@ class InitialReminder < Vue
 
     # collect up a list of PMCs that are checked
     Array(document.querySelectorAll('input[type=checkbox]')).each do |input|
-      data.pmcs << input.value if input.checked
+      if input.checked and input.classList.contains(@selection)
+        data.pmcs << input.value
+      end
     end
 
     post 'send-reminders', data do |response|
@@ -100,6 +113,7 @@ class InitialReminder < Vue
         alert("No reminders were sent")
       end
 
+      event.target.disabled = true
       @disabled = false
       jQuery('#reminder-form').modal(:hide)
       document.body.classList.remove('modal-open')
@@ -112,7 +126,17 @@ end
 #
 class FinalReminder < Vue
   def render
-    _button.btn.btn_primary 'send final reminders', 
+    _button.btn.btn_primary 'send final reminders', disabled: true,
+      data_toggle: 'modal', data_target: '#reminder-form'
+  end
+end
+
+#
+# A button for warning non-responsive PMCs
+#
+class ProdReminder < Vue
+  def render
+    _button.btn.btn_danger 'prod non-responsive PMCs', disabled: true,
       data_toggle: 'modal', data_target: '#reminder-form'
   end
 end
diff --git a/www/board/agenda/views/models/agenda.js.rb 
b/www/board/agenda/views/models/agenda.js.rb
index 4545cc7..575287b 100644
--- a/www/board/agenda/views/models/agenda.js.rb
+++ b/www/board/agenda/views/models/agenda.js.rb
@@ -164,10 +164,17 @@ class Agenda
     end
   end
 
+  # report was marked as NOT accepted during the meeting
   def rejected
     Minutes.rejected and Minutes.rejected.include?(@title)
   end
 
+  # PMC has missed two consecutive months
+  def nonresponsive
+    @notes and @notes.include? 'missing' and 
+      @notes.sub(/^.*missing/, '').split(',').length >= 2
+  end
+
   # compute href by taking the title and replacing all non alphanumeric
   # characters with dashes
   def href
diff --git a/www/board/agenda/views/pages/missing.js.rb 
b/www/board/agenda/views/pages/missing.js.rb
index 94c5682..05fb4f6 100644
--- a/www/board/agenda/views/pages/missing.js.rb
+++ b/www/board/agenda/views/pages/missing.js.rb
@@ -18,15 +18,39 @@ class Missing < Vue
     first = true
 
     Agenda.index.each do |item|
-      if item.missing and item.owner
+      if item.missing and item.owner and item.nonresponsive
+        _h2 'Non responsive PMCs' if first
+
+        _h3 class: item.color do
+          if item.attach =~ /^[A-Z]+/
+            _input.inactive type: 'checkbox', name: 'selected', 
+              value: item.title, checked: @checked[item.title]
+          end
+
+          _Link text: item.title, href: "flagged/#{item.href}",
+            class: ('default' if first)
+          first = false
+
+          _span.owner " [#{item.owner} / #{item.shepherd}]"
+
+          if item.flagged_by
+            flagged_by = Server.directors[item.flagged_by] || item.flagged_by
+            _span.owner " flagged by: #{flagged_by}"
+          end
+        end
+
+        _AdditionalInfo item: item, prefix: true
+      end
+    end
+
+    _h2 'Other missing reports' unless first
+
+    Agenda.index.each do |item|
+      if item.missing and item.owner and not item.nonresponsive
         _h3 class: item.color do
           if item.attach =~ /^[A-Z]+/
-            _input type: 'checkbox', name: 'selected', value: item.title,
-              checked: true, disabled: true, domPropsDisabled: false,
-              domPropsChecked: @checked[item.title], onClick:-> {
-                @checked[item.title] = !@checked[item.title]
-                Vue.forceUpdate()
-              }
+            _input.active type: 'checkbox', name: 'selected',
+              value: item.title, checked: @checked[item.title]
           end
 
           _Link text: item.title, href: "flagged/#{item.href}",
diff --git a/www/board/agenda/views/router.js.rb 
b/www/board/agenda/views/router.js.rb
index 02e4fb5..d884929 100644
--- a/www/board/agenda/views/router.js.rb
+++ b/www/board/agenda/views/router.js.rb
@@ -10,7 +10,6 @@ class Router
   # route request based on path and query from the window location (URL)
   def self.route(path, query)
     options = {}
-    buttons = []
 
     if not path or path == '.'
       item = Agenda
@@ -36,8 +35,13 @@ class Router
       item = {view: Rejected, title: 'Reports which were NOT accepted'}
 
     elsif path == 'missing'
-      item = {view: Missing, title: 'Missing reports',
-        buttons: [{form: InitialReminder}, {button: FinalReminder}]}
+      buttons = [{form: InitialReminder}, {button: FinalReminder}]
+
+      if Agenda.index.any? {|item| item.nonresponsive}
+        buttons << {form: ProdReminder}
+      end
+
+      item = {view: Missing, title: 'Missing reports', buttons: buttons}
 
     elsif path =~ %r{^flagged/[-\w]+$}
       item = Agenda.find(path[8..-1])

-- 
To stop receiving notification emails like this one, please contact
"commits@whimsical.apache.org" <commits@whimsical.apache.org>.

Reply via email to