diff --git a/forwardport/controllers.py b/forwardport/controllers.py
index af464dcb..620eab96 100644
--- a/forwardport/controllers.py
+++ b/forwardport/controllers.py
@@ -1,7 +1,14 @@
+import collections
+import datetime
import pathlib
+import werkzeug.urls
+
+from odoo.http import route, request
+from odoo.osv import expression
from odoo.addons.runbot_merge.controllers.dashboard import MergebotDashboard
+DEFAULT_DELTA = datetime.timedelta(days=7)
class Dashboard(MergebotDashboard):
def _entries(self):
changelog = pathlib.Path(__file__).parent / 'changelog'
@@ -13,3 +20,75 @@ class Dashboard(MergebotDashboard):
for d in changelog.iterdir()
]
+
+ @route('/forwardport/outstanding', type='http', methods=['GET'], auth="user", website=True, sitemap=False)
+ def outstanding(self, partner=0, authors=True, reviewers=True, group=0):
+ Partners = request.env['res.partner']
+ PullRequests = request.env['runbot_merge.pull_requests']
+ partner = Partners.browse(int(partner))
+ group = Partners.browse(int(group))
+ authors = int(authors)
+ reviewers = int(reviewers)
+ link = lambda **kw: '?' + werkzeug.urls.url_encode({'partner': partner.id or 0, 'authors': authors, 'reviewers': reviewers, **kw, })
+ groups = Partners.search([('is_company', '=', True), ('child_ids', '!=', False)])
+ if not (authors or reviewers):
+ return request.render('forwardport.outstanding', {
+ 'authors': 0,
+ 'reviewers': 0,
+ 'single': partner,
+ 'culprits': partner,
+ 'groups': groups,
+ 'current_group': group,
+ 'outstanding': [],
+ 'outstanding_per_author': {partner: 0},
+ 'outstanding_per_reviewer': {partner: 0},
+ 'link': link,
+ })
+
+ source_filter = [('merge_date', '<', datetime.datetime.now() - DEFAULT_DELTA)]
+ partner_filter = []
+ if partner or group:
+ if partner:
+ suffix = ''
+ arg = partner.id
+ else:
+ suffix = '.commercial_partner_id'
+ arg = group.id
+
+ if authors:
+ partner_filter.append([(f'author{suffix}', '=', arg)])
+ if reviewers:
+ partner_filter.append([(f'reviewed_by{suffix}', '=', arg)])
+
+ source_filter.extend(expression.OR(partner_filter))
+
+ outstanding = PullRequests.search([
+ ('state', 'in', ['opened', 'validated', 'approved', 'ready', 'error']),
+ ('source_id', 'in', PullRequests._search(source_filter)),
+ ])
+ outstanding_per_author = collections.Counter()
+ outstanding_per_reviewer = collections.Counter()
+ outstandings = []
+ for source in outstanding.mapped('source_id').sorted('merge_date'):
+ outstandings.append({
+ 'source': source,
+ 'prs': source.forwardport_ids.filtered(lambda p: p.state not in ['merged', 'closed']),
+ })
+ if authors:
+ outstanding_per_author[source.author] += 1
+ if reviewers and source:
+ outstanding_per_reviewer[source.reviewed_by] += 1
+
+ culprits = Partners.browse(p.id for p, _ in (outstanding_per_reviewer + outstanding_per_author).most_common())
+ return request.render('forwardport.outstanding', {
+ 'authors': authors,
+ 'reviewers': reviewers,
+ 'single': partner,
+ 'culprits': culprits,
+ 'groups': groups,
+ 'current_group': group,
+ 'outstanding_per_author': outstanding_per_author,
+ 'outstanding_per_reviewer': outstanding_per_reviewer,
+ 'outstanding': outstandings,
+ 'link': link,
+ })
diff --git a/forwardport/data/views.xml b/forwardport/data/views.xml
index c25bb311..1b6069c2 100644
--- a/forwardport/data/views.xml
+++ b/forwardport/data/views.xml
@@ -30,67 +30,101 @@
bg-warning
-
- Outstanding forward ports
- qweb
- /forwardport/outstanding
-
- True
- forwardport.outstanding_fp
-
-
-
-
-
-
-
List of pull requests with outstanding forward ports
-
-
-
- merged by
-
-
-
-
-
- -
-
- by
- merged
-
- by
-
-
- -
- Outstanding forward-ports:
-
-
+
+
+
+
+
+ by
+
+
+ both
+
+
+ creators
+
+
+ reviewers
+
+
-
-
-
+ List of pull requests with outstanding forward ports
+
+
+
+
+
+ -
+
+ created by
+ merged
+ by
+
+ -
+ Outstanding forward-ports:
+
+
+
+
+
+
+
diff --git a/forwardport/models/project.py b/forwardport/models/project.py
index 720000e7..51974020 100644
--- a/forwardport/models/project.py
+++ b/forwardport/models/project.py
@@ -1114,31 +1114,6 @@ stderr:
('source_id.merge_date', '<', cutoff),
], order='source_id, id'), lambda p: p.source_id)
- def _hall_of_shame(self):
- """Provides data for the HOS view
-
- * outstanding forward ports per reviewer
- * pull requests with outstanding forward ports, oldest-merged first
- """
- cutoff_dt = datetime.datetime.now() - DEFAULT_DELTA
- outstanding = self.env['runbot_merge.pull_requests'].search([
- ('source_id', '!=', False),
- ('state', 'not in', ['merged', 'closed']),
- ('source_id.merge_date', '<', cutoff_dt),
- ], order=None)
- # only keep merged because apparently some PRs are in a weird spot
- # where they're sources but closed?
- sources = outstanding.mapped('source_id').filtered('merge_date').sorted('merge_date')
- outstandings = []
- reviewers = collections.Counter()
- for source in sources:
- outstandings.append(Outstanding(source=source, prs=source.forwardport_ids & outstanding))
- reviewers[source.reviewed_by] += 1
- return HallOfShame(
- reviewers=reviewers.most_common(),
- outstanding=outstandings,
- )
-
def _reminder(self):
cutoff = self.env.context.get('forwardport_updated_before') \
or fields.Datetime.to_string(datetime.datetime.now() - DEFAULT_DELTA)
diff --git a/runbot_merge/models/pull_requests.py b/runbot_merge/models/pull_requests.py
index 19c63aef..d48ad505 100644
--- a/runbot_merge/models/pull_requests.py
+++ b/runbot_merge/models/pull_requests.py
@@ -527,7 +527,7 @@ class PullRequests(models.Model):
], default='opened', index=True)
number = fields.Integer(required=True, index=True, group_operator=None)
- author = fields.Many2one('res.partner')
+ author = fields.Many2one('res.partner', index=True)
head = fields.Char(required=True)
label = fields.Char(
required=True, index=True,
@@ -545,7 +545,7 @@ class PullRequests(models.Model):
], default=False)
method_warned = fields.Boolean(default=False)
- reviewed_by = fields.Many2one('res.partner')
+ reviewed_by = fields.Many2one('res.partner', index=True)
delegates = fields.Many2many('res.partner', help="Delegate reviewers, not intrinsically reviewers but can review this PR")
priority = fields.Integer(default=2, index=True, group_operator=None)
diff --git a/runbot_merge/static/scss/runbot_merge.scss b/runbot_merge/static/scss/runbot_merge.scss
index 2b98cf32..2e6577b3 100644
--- a/runbot_merge/static/scss/runbot_merge.scss
+++ b/runbot_merge/static/scss/runbot_merge.scss
@@ -110,3 +110,14 @@ dl.runbot-merge-fields {
.staging-statuses {
cursor: wait;
}
+
+/* forwardport */
+.outstanding-partners > * {
+ @extend .pt-1;
+ // because there's a trailing space which is annoying to remove, which plays
+ // the role of padding-right
+ @extend .pl-1;
+ @extend .text-nowrap;
+ // works better for the left edge of the *box*
+ @extend .border-left;
+}