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>.