Auto status change to "Under Review"
Show More
@@ -76,7 +76,11 b' class TestMyAccountEdit(TestController):' | |||||
76 | 'requests requiring your participation.') |
|
76 | 'requests requiring your participation.') | |
77 |
|
77 | |||
78 | @pytest.mark.backends("git", "hg") |
|
78 | @pytest.mark.backends("git", "hg") | |
79 | def test_my_account_my_pullrequests_data(self, pr_util, xhr_header): |
|
79 | @pytest.mark.parametrize('params, expected_title', [ | |
|
80 | ({'closed': 1}, 'Closed'), | |||
|
81 | ({'awaiting_my_review': 1}, 'Awaiting my review'), | |||
|
82 | ]) | |||
|
83 | def test_my_account_my_pullrequests_data(self, pr_util, xhr_header, params, expected_title): | |||
80 | self.log_user() |
|
84 | self.log_user() | |
81 | response = self.app.get(route_path('my_account_pullrequests_data'), |
|
85 | response = self.app.get(route_path('my_account_pullrequests_data'), | |
82 | extra_environ=xhr_header) |
|
86 | extra_environ=xhr_header) |
@@ -43,7 +43,7 b' from rhodecode.model.comment import Comm' | |||||
43 | from rhodecode.model.db import ( |
|
43 | from rhodecode.model.db import ( | |
44 | IntegrityError, or_, in_filter_generator, |
|
44 | IntegrityError, or_, in_filter_generator, | |
45 | Repository, UserEmailMap, UserApiKeys, UserFollowing, |
|
45 | Repository, UserEmailMap, UserApiKeys, UserFollowing, | |
46 | PullRequest, UserBookmark, RepoGroup) |
|
46 | PullRequest, UserBookmark, RepoGroup, ChangesetStatus) | |
47 | from rhodecode.model.meta import Session |
|
47 | from rhodecode.model.meta import Session | |
48 | from rhodecode.model.pull_request import PullRequestModel |
|
48 | from rhodecode.model.pull_request import PullRequestModel | |
49 | from rhodecode.model.user import UserModel |
|
49 | from rhodecode.model.user import UserModel | |
@@ -654,21 +654,31 b' class MyAccountView(BaseAppView, DataGri' | |||||
654 | Session().commit() |
|
654 | Session().commit() | |
655 | return user.user_data['notification_status'] |
|
655 | return user.user_data['notification_status'] | |
656 |
|
656 | |||
657 | def _get_pull_requests_list(self, statuses): |
|
657 | def _get_pull_requests_list(self, statuses, filter_type=None): | |
658 | draw, start, limit = self._extract_chunk(self.request) |
|
658 | draw, start, limit = self._extract_chunk(self.request) | |
659 | search_q, order_by, order_dir = self._extract_ordering(self.request) |
|
659 | search_q, order_by, order_dir = self._extract_ordering(self.request) | |
660 |
|
660 | |||
661 | _render = self.request.get_partial_renderer( |
|
661 | _render = self.request.get_partial_renderer( | |
662 | 'rhodecode:templates/data_table/_dt_elements.mako') |
|
662 | 'rhodecode:templates/data_table/_dt_elements.mako') | |
663 |
|
663 | |||
664 | pull_requests = PullRequestModel().get_im_participating_in( |
|
664 | if filter_type == 'awaiting_my_review': | |
665 | user_id=self._rhodecode_user.user_id, |
|
665 | pull_requests = PullRequestModel().get_im_participating_in_for_review( | |
666 | statuses=statuses, query=search_q, |
|
666 | user_id=self._rhodecode_user.user_id, | |
667 | offset=start, length=limit, order_by=order_by, |
|
667 | statuses=statuses, query=search_q, | |
668 | order_dir=order_dir) |
|
668 | offset=start, length=limit, order_by=order_by, | |
|
669 | order_dir=order_dir) | |||
669 |
|
670 | |||
670 | pull_requests_total_count = PullRequestModel().count_im_participating_in( |
|
671 | pull_requests_total_count = PullRequestModel().count_im_participating_in_for_review( | |
671 | user_id=self._rhodecode_user.user_id, statuses=statuses, query=search_q) |
|
672 | user_id=self._rhodecode_user.user_id, statuses=statuses, query=search_q) | |
|
673 | else: | |||
|
674 | pull_requests = PullRequestModel().get_im_participating_in( | |||
|
675 | user_id=self._rhodecode_user.user_id, | |||
|
676 | statuses=statuses, query=search_q, | |||
|
677 | offset=start, length=limit, order_by=order_by, | |||
|
678 | order_dir=order_dir) | |||
|
679 | ||||
|
680 | pull_requests_total_count = PullRequestModel().count_im_participating_in( | |||
|
681 | user_id=self._rhodecode_user.user_id, statuses=statuses, query=search_q) | |||
672 |
|
682 | |||
673 | data = [] |
|
683 | data = [] | |
674 | comments_model = CommentsModel() |
|
684 | comments_model = CommentsModel() | |
@@ -678,6 +688,12 b' class MyAccountView(BaseAppView, DataGri' | |||||
678 | repo_id, pull_request=pr, include_drafts=False, count_only=True) |
|
688 | repo_id, pull_request=pr, include_drafts=False, count_only=True) | |
679 | owned = pr.user_id == self._rhodecode_user.user_id |
|
689 | owned = pr.user_id == self._rhodecode_user.user_id | |
680 |
|
690 | |||
|
691 | review_statuses = pr.reviewers_statuses(user=self._rhodecode_db_user) | |||
|
692 | my_review_status = ChangesetStatus.STATUS_NOT_REVIEWED | |||
|
693 | if review_statuses and review_statuses[4]: | |||
|
694 | _review_obj, _user, _reasons, _mandatory, statuses = review_statuses | |||
|
695 | my_review_status = statuses[0][1].status | |||
|
696 | ||||
681 | data.append({ |
|
697 | data.append({ | |
682 | 'target_repo': _render('pullrequest_target_repo', |
|
698 | 'target_repo': _render('pullrequest_target_repo', | |
683 | pr.target_repo.repo_name), |
|
699 | pr.target_repo.repo_name), | |
@@ -688,6 +704,8 b' class MyAccountView(BaseAppView, DataGri' | |||||
688 | 'name_raw': pr.pull_request_id, |
|
704 | 'name_raw': pr.pull_request_id, | |
689 | 'status': _render('pullrequest_status', |
|
705 | 'status': _render('pullrequest_status', | |
690 | pr.calculated_review_status()), |
|
706 | pr.calculated_review_status()), | |
|
707 | 'my_status': _render('pullrequest_status', | |||
|
708 | my_review_status), | |||
691 | 'title': _render('pullrequest_title', pr.title, pr.description), |
|
709 | 'title': _render('pullrequest_title', pr.title, pr.description), | |
692 | 'description': h.escape(pr.description), |
|
710 | 'description': h.escape(pr.description), | |
693 | 'updated_on': _render('pullrequest_updated_on', |
|
711 | 'updated_on': _render('pullrequest_updated_on', | |
@@ -723,7 +741,14 b' class MyAccountView(BaseAppView, DataGri' | |||||
723 | c.active = 'pullrequests' |
|
741 | c.active = 'pullrequests' | |
724 | req_get = self.request.GET |
|
742 | req_get = self.request.GET | |
725 |
|
743 | |||
726 |
c.closed = str2bool(req_get.get(' |
|
744 | c.closed = str2bool(req_get.get('closed')) | |
|
745 | c.awaiting_my_review = str2bool(req_get.get('awaiting_my_review')) | |||
|
746 | ||||
|
747 | c.selected_filter = 'all' | |||
|
748 | if c.closed: | |||
|
749 | c.selected_filter = 'all_closed' | |||
|
750 | if c.awaiting_my_review: | |||
|
751 | c.selected_filter = 'awaiting_my_review' | |||
727 |
|
752 | |||
728 | return self._get_template_context(c) |
|
753 | return self._get_template_context(c) | |
729 |
|
754 | |||
@@ -732,13 +757,19 b' class MyAccountView(BaseAppView, DataGri' | |||||
732 | def my_account_pullrequests_data(self): |
|
757 | def my_account_pullrequests_data(self): | |
733 | self.load_default_context() |
|
758 | self.load_default_context() | |
734 | req_get = self.request.GET |
|
759 | req_get = self.request.GET | |
|
760 | ||||
|
761 | awaiting_my_review = str2bool(req_get.get('awaiting_my_review')) | |||
735 | closed = str2bool(req_get.get('closed')) |
|
762 | closed = str2bool(req_get.get('closed')) | |
736 |
|
763 | |||
737 | statuses = [PullRequest.STATUS_NEW, PullRequest.STATUS_OPEN] |
|
764 | statuses = [PullRequest.STATUS_NEW, PullRequest.STATUS_OPEN] | |
738 | if closed: |
|
765 | if closed: | |
739 | statuses += [PullRequest.STATUS_CLOSED] |
|
766 | statuses += [PullRequest.STATUS_CLOSED] | |
740 |
|
767 | |||
741 | data = self._get_pull_requests_list(statuses=statuses) |
|
768 | filter_type = \ | |
|
769 | 'awaiting_my_review' if awaiting_my_review \ | |||
|
770 | else None | |||
|
771 | ||||
|
772 | data = self._get_pull_requests_list(statuses=statuses, filter_type=filter_type) | |||
742 | return data |
|
773 | return data | |
743 |
|
774 | |||
744 | @LoginRequired() |
|
775 | @LoginRequired() |
@@ -41,7 +41,7 b' class TestPullRequestList(object):' | |||||
41 |
|
41 | |||
42 | @pytest.mark.parametrize('params, expected_title', [ |
|
42 | @pytest.mark.parametrize('params, expected_title', [ | |
43 | ({'source': 0, 'closed': 1}, 'Closed'), |
|
43 | ({'source': 0, 'closed': 1}, 'Closed'), | |
44 |
({'source': 0, 'my': 1}, ' |
|
44 | ({'source': 0, 'my': 1}, 'Created by me'), | |
45 | ({'source': 0, 'awaiting_review': 1}, 'Awaiting review'), |
|
45 | ({'source': 0, 'awaiting_review': 1}, 'Awaiting review'), | |
46 | ({'source': 0, 'awaiting_my_review': 1}, 'Awaiting my review'), |
|
46 | ({'source': 0, 'awaiting_my_review': 1}, 'Awaiting my review'), | |
47 | ({'source': 1}, 'From this repo'), |
|
47 | ({'source': 1}, 'From this repo'), |
@@ -79,21 +79,20 b' class RepoPullRequestsView(RepoAppView, ' | |||||
79 |
|
79 | |||
80 | if filter_type == 'awaiting_review': |
|
80 | if filter_type == 'awaiting_review': | |
81 | pull_requests = PullRequestModel().get_awaiting_review( |
|
81 | pull_requests = PullRequestModel().get_awaiting_review( | |
82 | repo_name, search_q=search_q, source=source, opened_by=opened_by, |
|
82 | repo_name, | |
83 | statuses=statuses, offset=start, length=limit, |
|
83 | search_q=search_q, statuses=statuses, | |
84 | order_by=order_by, order_dir=order_dir) |
|
84 | offset=start, length=limit, order_by=order_by, order_dir=order_dir) | |
85 | pull_requests_total_count = PullRequestModel().count_awaiting_review( |
|
85 | pull_requests_total_count = PullRequestModel().count_awaiting_review( | |
86 | repo_name, search_q=search_q, source=source, statuses=statuses, |
|
86 | repo_name, | |
87 | opened_by=opened_by) |
|
87 | search_q=search_q, statuses=statuses) | |
88 | elif filter_type == 'awaiting_my_review': |
|
88 | elif filter_type == 'awaiting_my_review': | |
89 | pull_requests = PullRequestModel().get_awaiting_my_review( |
|
89 | pull_requests = PullRequestModel().get_awaiting_my_review( | |
90 | repo_name, search_q=search_q, source=source, opened_by=opened_by, |
|
90 | repo_name, self._rhodecode_user.user_id, | |
91 |
|
|
91 | search_q=search_q, statuses=statuses, | |
92 | offset=start, length=limit, order_by=order_by, |
|
92 | offset=start, length=limit, order_by=order_by, order_dir=order_dir) | |
93 | order_dir=order_dir) |
|
|||
94 | pull_requests_total_count = PullRequestModel().count_awaiting_my_review( |
|
93 | pull_requests_total_count = PullRequestModel().count_awaiting_my_review( | |
95 |
repo_name, |
|
94 | repo_name, self._rhodecode_user.user_id, | |
96 |
statuses=statuses |
|
95 | search_q=search_q, statuses=statuses) | |
97 | else: |
|
96 | else: | |
98 | pull_requests = PullRequestModel().get_all( |
|
97 | pull_requests = PullRequestModel().get_all( | |
99 | repo_name, search_q=search_q, source=source, opened_by=opened_by, |
|
98 | repo_name, search_q=search_q, source=source, opened_by=opened_by, | |
@@ -110,6 +109,12 b' class RepoPullRequestsView(RepoAppView, ' | |||||
110 | self.db_repo.repo_id, pull_request=pr, |
|
109 | self.db_repo.repo_id, pull_request=pr, | |
111 | include_drafts=False, count_only=True) |
|
110 | include_drafts=False, count_only=True) | |
112 |
|
111 | |||
|
112 | review_statuses = pr.reviewers_statuses(user=self._rhodecode_db_user) | |||
|
113 | my_review_status = ChangesetStatus.STATUS_NOT_REVIEWED | |||
|
114 | if review_statuses and review_statuses[4]: | |||
|
115 | _review_obj, _user, _reasons, _mandatory, statuses = review_statuses | |||
|
116 | my_review_status = statuses[0][1].status | |||
|
117 | ||||
113 | data.append({ |
|
118 | data.append({ | |
114 | 'name': _render('pullrequest_name', |
|
119 | 'name': _render('pullrequest_name', | |
115 | pr.pull_request_id, pr.pull_request_state, |
|
120 | pr.pull_request_id, pr.pull_request_state, | |
@@ -118,6 +123,8 b' class RepoPullRequestsView(RepoAppView, ' | |||||
118 | 'name_raw': pr.pull_request_id, |
|
123 | 'name_raw': pr.pull_request_id, | |
119 | 'status': _render('pullrequest_status', |
|
124 | 'status': _render('pullrequest_status', | |
120 | pr.calculated_review_status()), |
|
125 | pr.calculated_review_status()), | |
|
126 | 'my_status': _render('pullrequest_status', | |||
|
127 | my_review_status), | |||
121 | 'title': _render('pullrequest_title', pr.title, pr.description), |
|
128 | 'title': _render('pullrequest_title', pr.title, pr.description), | |
122 | 'description': h.escape(pr.description), |
|
129 | 'description': h.escape(pr.description), | |
123 | 'updated_on': _render('pullrequest_updated_on', |
|
130 | 'updated_on': _render('pullrequest_updated_on', |
@@ -354,7 +354,7 b' class ChangesetStatusModel(BaseModel):' | |||||
354 | Session().add(new_status) |
|
354 | Session().add(new_status) | |
355 | return new_statuses |
|
355 | return new_statuses | |
356 |
|
356 | |||
357 | def aggregate_votes_by_user(self, commit_statuses, reviewers_data): |
|
357 | def aggregate_votes_by_user(self, commit_statuses, reviewers_data, user=None): | |
358 |
|
358 | |||
359 | commit_statuses_map = collections.defaultdict(list) |
|
359 | commit_statuses_map = collections.defaultdict(list) | |
360 | for st in commit_statuses: |
|
360 | for st in commit_statuses: | |
@@ -368,6 +368,10 b' class ChangesetStatusModel(BaseModel):' | |||||
368 | for obj in reviewers_data: |
|
368 | for obj in reviewers_data: | |
369 | if not obj.user: |
|
369 | if not obj.user: | |
370 | continue |
|
370 | continue | |
|
371 | if user and obj.user.username != user.username: | |||
|
372 | # single user filter | |||
|
373 | continue | |||
|
374 | ||||
371 | statuses = commit_statuses_map.get(obj.user.username, None) |
|
375 | statuses = commit_statuses_map.get(obj.user.username, None) | |
372 | if statuses: |
|
376 | if statuses: | |
373 | status_groups = itertools.groupby( |
|
377 | status_groups = itertools.groupby( | |
@@ -376,16 +380,19 b' class ChangesetStatusModel(BaseModel):' | |||||
376 |
|
380 | |||
377 | reviewers.append((obj, obj.user, obj.reasons, obj.mandatory, statuses)) |
|
381 | reviewers.append((obj, obj.user, obj.reasons, obj.mandatory, statuses)) | |
378 |
|
382 | |||
379 | return reviewers |
|
383 | if user: | |
|
384 | return reviewers[0] if reviewers else reviewers | |||
|
385 | else: | |||
|
386 | return reviewers | |||
380 |
|
387 | |||
381 | def reviewers_statuses(self, pull_request): |
|
388 | def reviewers_statuses(self, pull_request, user=None): | |
382 | _commit_statuses = self.get_statuses( |
|
389 | _commit_statuses = self.get_statuses( | |
383 | pull_request.source_repo, |
|
390 | pull_request.source_repo, | |
384 | pull_request=pull_request, |
|
391 | pull_request=pull_request, | |
385 | with_revisions=True) |
|
392 | with_revisions=True) | |
386 | reviewers = pull_request.get_pull_request_reviewers( |
|
393 | reviewers = pull_request.get_pull_request_reviewers( | |
387 | role=PullRequestReviewers.ROLE_REVIEWER) |
|
394 | role=PullRequestReviewers.ROLE_REVIEWER) | |
388 | return self.aggregate_votes_by_user(_commit_statuses, reviewers) |
|
395 | return self.aggregate_votes_by_user(_commit_statuses, reviewers, user=user) | |
389 |
|
396 | |||
390 | def calculated_review_status(self, pull_request): |
|
397 | def calculated_review_status(self, pull_request): | |
391 | """ |
|
398 | """ |
@@ -41,10 +41,10 b' from sqlalchemy import (' | |||||
41 | Index, Sequence, UniqueConstraint, ForeignKey, CheckConstraint, Column, |
|
41 | Index, Sequence, UniqueConstraint, ForeignKey, CheckConstraint, Column, | |
42 | Boolean, String, Unicode, UnicodeText, DateTime, Integer, LargeBinary, |
|
42 | Boolean, String, Unicode, UnicodeText, DateTime, Integer, LargeBinary, | |
43 | Text, Float, PickleType, BigInteger) |
|
43 | Text, Float, PickleType, BigInteger) | |
44 | from sqlalchemy.sql.expression import true, false, case |
|
44 | from sqlalchemy.sql.expression import true, false, case, null | |
45 | from sqlalchemy.sql.functions import coalesce, count # pragma: no cover |
|
45 | from sqlalchemy.sql.functions import coalesce, count # pragma: no cover | |
46 | from sqlalchemy.orm import ( |
|
46 | from sqlalchemy.orm import ( | |
47 | relationship, joinedload, class_mapper, validates, aliased) |
|
47 | relationship, lazyload, joinedload, class_mapper, validates, aliased) | |
48 | from sqlalchemy.ext.declarative import declared_attr |
|
48 | from sqlalchemy.ext.declarative import declared_attr | |
49 | from sqlalchemy.ext.hybrid import hybrid_property |
|
49 | from sqlalchemy.ext.hybrid import hybrid_property | |
50 | from sqlalchemy.exc import IntegrityError # pragma: no cover |
|
50 | from sqlalchemy.exc import IntegrityError # pragma: no cover | |
@@ -4479,9 +4479,9 b' class PullRequest(Base, _PullRequestBase' | |||||
4479 | from rhodecode.model.changeset_status import ChangesetStatusModel |
|
4479 | from rhodecode.model.changeset_status import ChangesetStatusModel | |
4480 | return ChangesetStatusModel().calculated_review_status(self) |
|
4480 | return ChangesetStatusModel().calculated_review_status(self) | |
4481 |
|
4481 | |||
4482 | def reviewers_statuses(self): |
|
4482 | def reviewers_statuses(self, user=None): | |
4483 | from rhodecode.model.changeset_status import ChangesetStatusModel |
|
4483 | from rhodecode.model.changeset_status import ChangesetStatusModel | |
4484 | return ChangesetStatusModel().reviewers_statuses(self) |
|
4484 | return ChangesetStatusModel().reviewers_statuses(self, user=user) | |
4485 |
|
4485 | |||
4486 | def get_pull_request_reviewers(self, role=None): |
|
4486 | def get_pull_request_reviewers(self, role=None): | |
4487 | qry = PullRequestReviewers.query()\ |
|
4487 | qry = PullRequestReviewers.query()\ |
@@ -56,7 +56,7 b' from rhodecode.model import BaseModel' | |||||
56 | from rhodecode.model.changeset_status import ChangesetStatusModel |
|
56 | from rhodecode.model.changeset_status import ChangesetStatusModel | |
57 | from rhodecode.model.comment import CommentsModel |
|
57 | from rhodecode.model.comment import CommentsModel | |
58 | from rhodecode.model.db import ( |
|
58 | from rhodecode.model.db import ( | |
59 | or_, String, cast, PullRequest, PullRequestReviewers, ChangesetStatus, |
|
59 | aliased, null, lazyload, and_, or_, func, String, cast, PullRequest, PullRequestReviewers, ChangesetStatus, | |
60 | PullRequestVersion, ChangesetComment, Repository, RepoReviewRule, User) |
|
60 | PullRequestVersion, ChangesetComment, Repository, RepoReviewRule, User) | |
61 | from rhodecode.model.meta import Session |
|
61 | from rhodecode.model.meta import Session | |
62 | from rhodecode.model.notification import NotificationModel, \ |
|
62 | from rhodecode.model.notification import NotificationModel, \ | |
@@ -319,7 +319,7 b' class PullRequestModel(BaseModel):' | |||||
319 |
|
319 | |||
320 | if search_q: |
|
320 | if search_q: | |
321 | like_expression = u'%{}%'.format(safe_unicode(search_q)) |
|
321 | like_expression = u'%{}%'.format(safe_unicode(search_q)) | |
322 | q = q.join(User) |
|
322 | q = q.join(User, User.user_id == PullRequest.user_id) | |
323 | q = q.filter(or_( |
|
323 | q = q.filter(or_( | |
324 | cast(PullRequest.pull_request_id, String).ilike(like_expression), |
|
324 | cast(PullRequest.pull_request_id, String).ilike(like_expression), | |
325 | User.username.ilike(like_expression), |
|
325 | User.username.ilike(like_expression), | |
@@ -405,36 +405,30 b' class PullRequestModel(BaseModel):' | |||||
405 |
|
405 | |||
406 | return pull_requests |
|
406 | return pull_requests | |
407 |
|
407 | |||
408 |
def count_awaiting_review(self, repo_name, search_q=None, |
|
408 | def count_awaiting_review(self, repo_name, search_q=None, statuses=None): | |
409 | opened_by=None): |
|
|||
410 | """ |
|
409 | """ | |
411 | Count the number of pull requests for a specific repository that are |
|
410 | Count the number of pull requests for a specific repository that are | |
412 | awaiting review. |
|
411 | awaiting review. | |
413 |
|
412 | |||
414 | :param repo_name: target or source repo |
|
413 | :param repo_name: target or source repo | |
415 | :param search_q: filter by text |
|
414 | :param search_q: filter by text | |
416 | :param source: boolean flag to specify if repo_name refers to source |
|
|||
417 | :param statuses: list of pull request statuses |
|
415 | :param statuses: list of pull request statuses | |
418 | :param opened_by: author user of the pull request |
|
|||
419 | :returns: int number of pull requests |
|
416 | :returns: int number of pull requests | |
420 | """ |
|
417 | """ | |
421 | pull_requests = self.get_awaiting_review( |
|
418 | pull_requests = self.get_awaiting_review( | |
422 |
repo_name, search_q=search_q, |
|
419 | repo_name, search_q=search_q, statuses=statuses) | |
423 |
|
420 | |||
424 | return len(pull_requests) |
|
421 | return len(pull_requests) | |
425 |
|
422 | |||
426 |
def get_awaiting_review(self, repo_name, search_q=None, |
|
423 | def get_awaiting_review(self, repo_name, search_q=None, statuses=None, | |
427 |
|
|
424 | offset=0, length=None, order_by=None, order_dir='desc'): | |
428 | order_by=None, order_dir='desc'): |
|
|||
429 | """ |
|
425 | """ | |
430 | Get all pull requests for a specific repository that are awaiting |
|
426 | Get all pull requests for a specific repository that are awaiting | |
431 | review. |
|
427 | review. | |
432 |
|
428 | |||
433 | :param repo_name: target or source repo |
|
429 | :param repo_name: target or source repo | |
434 | :param search_q: filter by text |
|
430 | :param search_q: filter by text | |
435 | :param source: boolean flag to specify if repo_name refers to source |
|
|||
436 | :param statuses: list of pull request statuses |
|
431 | :param statuses: list of pull request statuses | |
437 | :param opened_by: author user of the pull request |
|
|||
438 | :param offset: pagination offset |
|
432 | :param offset: pagination offset | |
439 | :param length: length of returned list |
|
433 | :param length: length of returned list | |
440 | :param order_by: order of the returned list |
|
434 | :param order_by: order of the returned list | |
@@ -442,8 +436,8 b' class PullRequestModel(BaseModel):' | |||||
442 | :returns: list of pull requests |
|
436 | :returns: list of pull requests | |
443 | """ |
|
437 | """ | |
444 | pull_requests = self.get_all( |
|
438 | pull_requests = self.get_all( | |
445 |
repo_name, search_q=search_q, |
|
439 | repo_name, search_q=search_q, statuses=statuses, | |
446 |
|
|
440 | order_by=order_by, order_dir=order_dir) | |
447 |
|
441 | |||
448 | _filtered_pull_requests = [] |
|
442 | _filtered_pull_requests = [] | |
449 | for pr in pull_requests: |
|
443 | for pr in pull_requests: | |
@@ -456,68 +450,117 b' class PullRequestModel(BaseModel):' | |||||
456 | else: |
|
450 | else: | |
457 | return _filtered_pull_requests |
|
451 | return _filtered_pull_requests | |
458 |
|
452 | |||
459 | def count_awaiting_my_review(self, repo_name, search_q=None, source=False, statuses=None, |
|
453 | def _prepare_awaiting_my_review_review_query( | |
460 | opened_by=None, user_id=None): |
|
454 | self, repo_name, user_id, search_q=None, statuses=None, | |
|
455 | order_by=None, order_dir='desc'): | |||
|
456 | ||||
|
457 | for_review_statuses = [ | |||
|
458 | ChangesetStatus.STATUS_UNDER_REVIEW, ChangesetStatus.STATUS_NOT_REVIEWED | |||
|
459 | ] | |||
|
460 | ||||
|
461 | pull_request_alias = aliased(PullRequest) | |||
|
462 | status_alias = aliased(ChangesetStatus) | |||
|
463 | reviewers_alias = aliased(PullRequestReviewers) | |||
|
464 | repo_alias = aliased(Repository) | |||
|
465 | ||||
|
466 | last_ver_subq = Session()\ | |||
|
467 | .query(func.min(ChangesetStatus.version)) \ | |||
|
468 | .filter(ChangesetStatus.pull_request_id == reviewers_alias.pull_request_id)\ | |||
|
469 | .filter(ChangesetStatus.user_id == reviewers_alias.user_id) \ | |||
|
470 | .subquery() | |||
|
471 | ||||
|
472 | q = Session().query(pull_request_alias) \ | |||
|
473 | .options(lazyload(pull_request_alias.author)) \ | |||
|
474 | .join(reviewers_alias, | |||
|
475 | reviewers_alias.pull_request_id == pull_request_alias.pull_request_id) \ | |||
|
476 | .join(repo_alias, | |||
|
477 | repo_alias.repo_id == pull_request_alias.target_repo_id) \ | |||
|
478 | .outerjoin(status_alias, | |||
|
479 | and_(status_alias.user_id == reviewers_alias.user_id, | |||
|
480 | status_alias.pull_request_id == reviewers_alias.pull_request_id)) \ | |||
|
481 | .filter(or_(status_alias.version == null(), | |||
|
482 | status_alias.version == last_ver_subq)) \ | |||
|
483 | .filter(reviewers_alias.user_id == user_id) \ | |||
|
484 | .filter(repo_alias.repo_name == repo_name) \ | |||
|
485 | .filter(or_(status_alias.status == null(), status_alias.status.in_(for_review_statuses))) \ | |||
|
486 | .group_by(pull_request_alias) | |||
|
487 | ||||
|
488 | # closed,opened | |||
|
489 | if statuses: | |||
|
490 | q = q.filter(pull_request_alias.status.in_(statuses)) | |||
|
491 | ||||
|
492 | if search_q: | |||
|
493 | like_expression = u'%{}%'.format(safe_unicode(search_q)) | |||
|
494 | q = q.join(User, User.user_id == pull_request_alias.user_id) | |||
|
495 | q = q.filter(or_( | |||
|
496 | cast(pull_request_alias.pull_request_id, String).ilike(like_expression), | |||
|
497 | User.username.ilike(like_expression), | |||
|
498 | pull_request_alias.title.ilike(like_expression), | |||
|
499 | pull_request_alias.description.ilike(like_expression), | |||
|
500 | )) | |||
|
501 | ||||
|
502 | if order_by: | |||
|
503 | order_map = { | |||
|
504 | 'name_raw': pull_request_alias.pull_request_id, | |||
|
505 | 'title': pull_request_alias.title, | |||
|
506 | 'updated_on_raw': pull_request_alias.updated_on, | |||
|
507 | 'target_repo': pull_request_alias.target_repo_id | |||
|
508 | } | |||
|
509 | if order_dir == 'asc': | |||
|
510 | q = q.order_by(order_map[order_by].asc()) | |||
|
511 | else: | |||
|
512 | q = q.order_by(order_map[order_by].desc()) | |||
|
513 | ||||
|
514 | return q | |||
|
515 | ||||
|
516 | def count_awaiting_my_review(self, repo_name, user_id, search_q=None, statuses=None): | |||
461 | """ |
|
517 | """ | |
462 | Count the number of pull requests for a specific repository that are |
|
518 | Count the number of pull requests for a specific repository that are | |
463 | awaiting review from a specific user. |
|
519 | awaiting review from a specific user. | |
464 |
|
520 | |||
465 | :param repo_name: target or source repo |
|
521 | :param repo_name: target or source repo | |
|
522 | :param user_id: reviewer user of the pull request | |||
466 | :param search_q: filter by text |
|
523 | :param search_q: filter by text | |
467 | :param source: boolean flag to specify if repo_name refers to source |
|
|||
468 | :param statuses: list of pull request statuses |
|
524 | :param statuses: list of pull request statuses | |
469 | :param opened_by: author user of the pull request |
|
|||
470 | :param user_id: reviewer user of the pull request |
|
|||
471 | :returns: int number of pull requests |
|
525 | :returns: int number of pull requests | |
472 | """ |
|
526 | """ | |
473 |
|
|
527 | q = self._prepare_awaiting_my_review_review_query( | |
474 |
repo_name, search_q=search_q, |
|
528 | repo_name, user_id, search_q=search_q, statuses=statuses) | |
475 | opened_by=opened_by, user_id=user_id) |
|
529 | return q.count() | |
476 |
|
530 | |||
477 | return len(pull_requests) |
|
531 | def get_awaiting_my_review(self, repo_name, user_id, search_q=None, statuses=None, | |
478 |
|
532 | offset=0, length=None, order_by=None, order_dir='desc'): | ||
479 | def get_awaiting_my_review(self, repo_name, search_q=None, source=False, statuses=None, |
|
|||
480 | opened_by=None, user_id=None, offset=0, |
|
|||
481 | length=None, order_by=None, order_dir='desc'): |
|
|||
482 | """ |
|
533 | """ | |
483 | Get all pull requests for a specific repository that are awaiting |
|
534 | Get all pull requests for a specific repository that are awaiting | |
484 | review from a specific user. |
|
535 | review from a specific user. | |
485 |
|
536 | |||
486 | :param repo_name: target or source repo |
|
537 | :param repo_name: target or source repo | |
|
538 | :param user_id: reviewer user of the pull request | |||
487 | :param search_q: filter by text |
|
539 | :param search_q: filter by text | |
488 | :param source: boolean flag to specify if repo_name refers to source |
|
|||
489 | :param statuses: list of pull request statuses |
|
540 | :param statuses: list of pull request statuses | |
490 | :param opened_by: author user of the pull request |
|
|||
491 | :param user_id: reviewer user of the pull request |
|
|||
492 | :param offset: pagination offset |
|
541 | :param offset: pagination offset | |
493 | :param length: length of returned list |
|
542 | :param length: length of returned list | |
494 | :param order_by: order of the returned list |
|
543 | :param order_by: order of the returned list | |
495 | :param order_dir: 'asc' or 'desc' ordering direction |
|
544 | :param order_dir: 'asc' or 'desc' ordering direction | |
496 | :returns: list of pull requests |
|
545 | :returns: list of pull requests | |
497 | """ |
|
546 | """ | |
498 | pull_requests = self.get_all( |
|
|||
499 | repo_name, search_q=search_q, source=source, statuses=statuses, |
|
|||
500 | opened_by=opened_by, order_by=order_by, order_dir=order_dir) |
|
|||
501 |
|
547 | |||
502 | _my = PullRequestModel().get_not_reviewed(user_id) |
|
548 | q = self._prepare_awaiting_my_review_review_query( | |
503 | my_participation = [] |
|
549 | repo_name, user_id, search_q=search_q, statuses=statuses, | |
504 | for pr in pull_requests: |
|
550 | order_by=order_by, order_dir=order_dir) | |
505 | if pr in _my: |
|
551 | ||
506 | my_participation.append(pr) |
|
|||
507 | _filtered_pull_requests = my_participation |
|
|||
508 | if length: |
|
552 | if length: | |
509 | return _filtered_pull_requests[offset:offset+length] |
|
553 | pull_requests = q.limit(length).offset(offset).all() | |
510 | else: |
|
554 | else: | |
511 |
|
|
555 | pull_requests = q.all() | |
|
556 | ||||
|
557 | return pull_requests | |||
512 |
|
558 | |||
513 | def get_not_reviewed(self, user_id): |
|
559 | def _prepare_im_participating_query(self, user_id=None, statuses=None, query='', | |
514 | return [ |
|
560 | order_by=None, order_dir='desc'): | |
515 | x.pull_request for x in PullRequestReviewers.query().filter( |
|
561 | """ | |
516 | PullRequestReviewers.user_id == user_id).all() |
|
562 | return a query of pull-requests user is an creator, or he's added as a reviewer | |
517 |
|
|
563 | """ | |
518 |
|
||||
519 | def _prepare_participating_query(self, user_id=None, statuses=None, query='', |
|
|||
520 | order_by=None, order_dir='desc'): |
|
|||
521 | q = PullRequest.query() |
|
564 | q = PullRequest.query() | |
522 | if user_id: |
|
565 | if user_id: | |
523 | reviewers_subquery = Session().query( |
|
566 | reviewers_subquery = Session().query( | |
@@ -535,7 +578,7 b' class PullRequestModel(BaseModel):' | |||||
535 |
|
578 | |||
536 | if query: |
|
579 | if query: | |
537 | like_expression = u'%{}%'.format(safe_unicode(query)) |
|
580 | like_expression = u'%{}%'.format(safe_unicode(query)) | |
538 | q = q.join(User) |
|
581 | q = q.join(User, User.user_id == PullRequest.user_id) | |
539 | q = q.filter(or_( |
|
582 | q = q.filter(or_( | |
540 | cast(PullRequest.pull_request_id, String).ilike(like_expression), |
|
583 | cast(PullRequest.pull_request_id, String).ilike(like_expression), | |
541 | User.username.ilike(like_expression), |
|
584 | User.username.ilike(like_expression), | |
@@ -557,17 +600,97 b' class PullRequestModel(BaseModel):' | |||||
557 | return q |
|
600 | return q | |
558 |
|
601 | |||
559 | def count_im_participating_in(self, user_id=None, statuses=None, query=''): |
|
602 | def count_im_participating_in(self, user_id=None, statuses=None, query=''): | |
560 | q = self._prepare_participating_query(user_id, statuses=statuses, query=query) |
|
603 | q = self._prepare_im_participating_query(user_id, statuses=statuses, query=query) | |
561 | return q.count() |
|
604 | return q.count() | |
562 |
|
605 | |||
563 | def get_im_participating_in( |
|
606 | def get_im_participating_in( | |
564 | self, user_id=None, statuses=None, query='', offset=0, |
|
607 | self, user_id=None, statuses=None, query='', offset=0, | |
565 | length=None, order_by=None, order_dir='desc'): |
|
608 | length=None, order_by=None, order_dir='desc'): | |
566 | """ |
|
609 | """ | |
567 | Get all Pull requests that i'm participating in, or i have opened |
|
610 | Get all Pull requests that i'm participating in as a reviewer, or i have opened | |
568 | """ |
|
611 | """ | |
569 |
|
612 | |||
570 | q = self._prepare_participating_query( |
|
613 | q = self._prepare_im_participating_query( | |
|
614 | user_id, statuses=statuses, query=query, order_by=order_by, | |||
|
615 | order_dir=order_dir) | |||
|
616 | ||||
|
617 | if length: | |||
|
618 | pull_requests = q.limit(length).offset(offset).all() | |||
|
619 | else: | |||
|
620 | pull_requests = q.all() | |||
|
621 | ||||
|
622 | return pull_requests | |||
|
623 | ||||
|
624 | def _prepare_participating_in_for_review_query( | |||
|
625 | self, user_id, statuses=None, query='', order_by=None, order_dir='desc'): | |||
|
626 | ||||
|
627 | for_review_statuses = [ | |||
|
628 | ChangesetStatus.STATUS_UNDER_REVIEW, ChangesetStatus.STATUS_NOT_REVIEWED | |||
|
629 | ] | |||
|
630 | ||||
|
631 | pull_request_alias = aliased(PullRequest) | |||
|
632 | status_alias = aliased(ChangesetStatus) | |||
|
633 | reviewers_alias = aliased(PullRequestReviewers) | |||
|
634 | ||||
|
635 | last_ver_subq = Session()\ | |||
|
636 | .query(func.min(ChangesetStatus.version)) \ | |||
|
637 | .filter(ChangesetStatus.pull_request_id == reviewers_alias.pull_request_id)\ | |||
|
638 | .filter(ChangesetStatus.user_id == reviewers_alias.user_id) \ | |||
|
639 | .subquery() | |||
|
640 | ||||
|
641 | q = Session().query(pull_request_alias) \ | |||
|
642 | .options(lazyload(pull_request_alias.author)) \ | |||
|
643 | .join(reviewers_alias, | |||
|
644 | reviewers_alias.pull_request_id == pull_request_alias.pull_request_id) \ | |||
|
645 | .outerjoin(status_alias, | |||
|
646 | and_(status_alias.user_id == reviewers_alias.user_id, | |||
|
647 | status_alias.pull_request_id == reviewers_alias.pull_request_id)) \ | |||
|
648 | .filter(or_(status_alias.version == null(), | |||
|
649 | status_alias.version == last_ver_subq)) \ | |||
|
650 | .filter(reviewers_alias.user_id == user_id) \ | |||
|
651 | .filter(or_(status_alias.status == null(), status_alias.status.in_(for_review_statuses))) \ | |||
|
652 | .group_by(pull_request_alias) | |||
|
653 | ||||
|
654 | # closed,opened | |||
|
655 | if statuses: | |||
|
656 | q = q.filter(pull_request_alias.status.in_(statuses)) | |||
|
657 | ||||
|
658 | if query: | |||
|
659 | like_expression = u'%{}%'.format(safe_unicode(query)) | |||
|
660 | q = q.join(User, User.user_id == pull_request_alias.user_id) | |||
|
661 | q = q.filter(or_( | |||
|
662 | cast(pull_request_alias.pull_request_id, String).ilike(like_expression), | |||
|
663 | User.username.ilike(like_expression), | |||
|
664 | pull_request_alias.title.ilike(like_expression), | |||
|
665 | pull_request_alias.description.ilike(like_expression), | |||
|
666 | )) | |||
|
667 | ||||
|
668 | if order_by: | |||
|
669 | order_map = { | |||
|
670 | 'name_raw': pull_request_alias.pull_request_id, | |||
|
671 | 'title': pull_request_alias.title, | |||
|
672 | 'updated_on_raw': pull_request_alias.updated_on, | |||
|
673 | 'target_repo': pull_request_alias.target_repo_id | |||
|
674 | } | |||
|
675 | if order_dir == 'asc': | |||
|
676 | q = q.order_by(order_map[order_by].asc()) | |||
|
677 | else: | |||
|
678 | q = q.order_by(order_map[order_by].desc()) | |||
|
679 | ||||
|
680 | return q | |||
|
681 | ||||
|
682 | def count_im_participating_in_for_review(self, user_id, statuses=None, query=''): | |||
|
683 | q = self._prepare_participating_in_for_review_query(user_id, statuses=statuses, query=query) | |||
|
684 | return q.count() | |||
|
685 | ||||
|
686 | def get_im_participating_in_for_review( | |||
|
687 | self, user_id, statuses=None, query='', offset=0, | |||
|
688 | length=None, order_by=None, order_dir='desc'): | |||
|
689 | """ | |||
|
690 | Get all Pull requests that needs user approval or rejection | |||
|
691 | """ | |||
|
692 | ||||
|
693 | q = self._prepare_participating_in_for_review_query( | |||
571 | user_id, statuses=statuses, query=query, order_by=order_by, |
|
694 | user_id, statuses=statuses, query=query, order_by=order_by, | |
572 | order_dir=order_dir) |
|
695 | order_dir=order_dir) | |
573 |
|
696 |
@@ -618,13 +618,13 b' input[type="reset"] {' | |||||
618 | text-align: right; |
|
618 | text-align: right; | |
619 |
|
619 | |||
620 | li { |
|
620 | li { | |
621 |
|
621 | list-style: none; | ||
622 |
|
622 | text-align: right; | ||
|
623 | display: inline-block; | |||
623 | } |
|
624 | } | |
624 |
|
625 | |||
625 |
|
|
626 | a.active { | |
626 | background-color: @grey6; |
|
627 | border: 2px solid @rcblue; | |
627 | .border ( @border-thickness, @grey4 ); |
|
|||
628 | } |
|
628 | } | |
629 |
|
629 | |||
630 | } |
|
630 | } |
@@ -44,7 +44,7 b'' | |||||
44 | padding: @panel-padding; |
|
44 | padding: @panel-padding; | |
45 |
|
45 | |||
46 | &.panel-body-min-height { |
|
46 | &.panel-body-min-height { | |
47 |
min-height: |
|
47 | min-height: 200px | |
48 | } |
|
48 | } | |
49 | } |
|
49 | } | |
50 |
|
50 |
@@ -1,17 +1,29 b'' | |||||
1 | <%namespace name="base" file="/base/base.mako"/> |
|
1 | <%namespace name="base" file="/base/base.mako"/> | |
2 |
|
2 | |||
3 | <div class="panel panel-default"> |
|
3 | <div class="panel panel-default"> | |
4 |
<div class="panel- |
|
4 | <div class="panel-heading"> | |
5 | <div style="height: 35px"> |
|
5 | <h3 class="panel-title">${_('Pull Requests You Participate In')}</h3> | |
6 | <% |
|
6 | </div> | |
7 | selected_filter = 'all' |
|
|||
8 | if c.closed: |
|
|||
9 | selected_filter = 'all_closed' |
|
|||
10 | %> |
|
|||
11 |
|
7 | |||
|
8 | <div class="panel-body panel-body-min-height"> | |||
|
9 | <div class="title"> | |||
12 | <ul class="button-links"> |
|
10 | <ul class="button-links"> | |
13 |
<li class="btn ${h.is_active('all', selected_filter)}" |
|
11 | <li><a class="btn ${h.is_active('all', c.selected_filter)}" | |
14 | <li class="btn ${h.is_active('all_closed', selected_filter)}"><a href="${h.route_path('my_account_pullrequests', _query={'pr_show_closed':1})}">${_('All + Closed')}</a></li> |
|
12 | href="${h.route_path('my_account_pullrequests', _query={})}"> | |
|
13 | ${_('Open')} | |||
|
14 | </a> | |||
|
15 | </li> | |||
|
16 | <li><a class="btn ${h.is_active('all_closed', c.selected_filter)}" | |||
|
17 | href="${h.route_path('my_account_pullrequests', _query={'closed':1})}"> | |||
|
18 | ${_('All + Closed')} | |||
|
19 | </a> | |||
|
20 | </li> | |||
|
21 | <li><a class="btn ${h.is_active('awaiting_my_review', c.selected_filter)}" | |||
|
22 | href="${h.route_path('my_account_pullrequests', _query={'awaiting_my_review':1})}"> | |||
|
23 | ||||
|
24 | ${_('Awaiting my review')} | |||
|
25 | </a> | |||
|
26 | </li> | |||
15 | </ul> |
|
27 | </ul> | |
16 |
|
28 | |||
17 | <div class="grid-quick-filter"> |
|
29 | <div class="grid-quick-filter"> | |
@@ -20,19 +32,13 b'' | |||||
20 | <i class="icon-search"></i> |
|
32 | <i class="icon-search"></i> | |
21 | </li> |
|
33 | </li> | |
22 | <li class="grid-filter-box-input"> |
|
34 | <li class="grid-filter-box-input"> | |
23 |
<input class="q_filter_box" id="q_filter" size="15" type="text" name="filter" |
|
35 | <input class="q_filter_box" id="q_filter" size="15" type="text" name="filter" | |
|
36 | placeholder="${_('quick filter...')}" value=""/> | |||
24 | </li> |
|
37 | </li> | |
25 | </ul> |
|
38 | </ul> | |
26 | </div> |
|
39 | </div> | |
27 | </div> |
|
40 | </div> | |
28 | </div> |
|
|||
29 | </div> |
|
|||
30 |
|
41 | |||
31 | <div class="panel panel-default"> |
|
|||
32 | <div class="panel-heading"> |
|
|||
33 | <h3 class="panel-title">${_('Pull Requests You Participate In')}</h3> |
|
|||
34 | </div> |
|
|||
35 | <div class="panel-body panel-body-min-height"> |
|
|||
36 | <table id="pull_request_list_table" class="rctable table-bordered"></table> |
|
42 | <table id="pull_request_list_table" class="rctable table-bordered"></table> | |
37 | </div> |
|
43 | </div> | |
38 | </div> |
|
44 | </div> | |
@@ -52,6 +58,7 b'' | |||||
52 | "url": "${h.route_path('my_account_pullrequests_data')}", |
|
58 | "url": "${h.route_path('my_account_pullrequests_data')}", | |
53 | "data": function (d) { |
|
59 | "data": function (d) { | |
54 | d.closed = "${c.closed}"; |
|
60 | d.closed = "${c.closed}"; | |
|
61 | d.awaiting_my_review = "${c.awaiting_my_review}"; | |||
55 | }, |
|
62 | }, | |
56 | "dataSrc": function (json) { |
|
63 | "dataSrc": function (json) { | |
57 | return json.data; |
|
64 | return json.data; | |
@@ -60,13 +67,19 b'' | |||||
60 |
|
67 | |||
61 | dom: 'rtp', |
|
68 | dom: 'rtp', | |
62 | pageLength: ${c.visual.dashboard_items}, |
|
69 | pageLength: ${c.visual.dashboard_items}, | |
63 |
order: [[ |
|
70 | order: [[2, "desc"]], | |
64 | columns: [ |
|
71 | columns: [ | |
65 | { |
|
72 | { | |
66 | data: { |
|
73 | data: { | |
67 | "_": "status", |
|
74 | "_": "status", | |
68 | "sort": "status" |
|
75 | "sort": "status" | |
69 | }, title: "", className: "td-status", orderable: false |
|
76 | }, title: "PR", className: "td-status", orderable: false | |
|
77 | }, | |||
|
78 | { | |||
|
79 | data: { | |||
|
80 | "_": "my_status", | |||
|
81 | "sort": "status" | |||
|
82 | }, title: "You", className: "td-status", orderable: false | |||
70 | }, |
|
83 | }, | |
71 | { |
|
84 | { | |
72 | data: { |
|
85 | data: { |
@@ -23,13 +23,14 b'' | |||||
23 |
|
23 | |||
24 | <div class="box"> |
|
24 | <div class="box"> | |
25 | <div class="title"> |
|
25 | <div class="title"> | |
|
26 | ||||
26 | <ul class="button-links"> |
|
27 | <ul class="button-links"> | |
27 |
<li class="btn ${h.is_active('open', c.active)}" |
|
28 | <li><a class="btn ${h.is_active('open', c.active)}" href="${h.route_path('pullrequest_show_all',repo_name=c.repo_name, _query={'source':0,'open':1})}">${_('Open')}</a></li> | |
28 |
<li class="btn ${h.is_active('my', c.active)}" |
|
29 | <li><a class="btn ${h.is_active('my', c.active)}" href="${h.route_path('pullrequest_show_all',repo_name=c.repo_name, _query={'source':0,'my':1})}">${_('Created by me')}</a></li> | |
29 |
<li class="btn ${h.is_active('awaiting', c.active)}" |
|
30 | <li><a class="btn ${h.is_active('awaiting', c.active)}" href="${h.route_path('pullrequest_show_all',repo_name=c.repo_name, _query={'source':0,'awaiting_review':1})}">${_('Awaiting review')}</a></li> | |
30 |
<li class="btn ${h.is_active('awaiting_my', c.active)}" |
|
31 | <li><a class="btn ${h.is_active('awaiting_my', c.active)}" href="${h.route_path('pullrequest_show_all',repo_name=c.repo_name, _query={'source':0,'awaiting_my_review':1})}">${_('Awaiting my review')}</a></li> | |
31 |
<li class="btn ${h.is_active('closed', c.active)}" |
|
32 | <li><a class="btn ${h.is_active('closed', c.active)}" href="${h.route_path('pullrequest_show_all',repo_name=c.repo_name, _query={'source':0,'closed':1})}">${_('Closed')}</a></li> | |
32 |
<li class="btn ${h.is_active('source', c.active)}" |
|
33 | <li><a class="btn ${h.is_active('source', c.active)}" href="${h.route_path('pullrequest_show_all',repo_name=c.repo_name, _query={'source':1})}">${_('From this repo')}</a></li> | |
33 | </ul> |
|
34 | </ul> | |
34 |
|
35 | |||
35 | <ul class="links"> |
|
36 | <ul class="links"> | |
@@ -88,20 +89,50 b'' | |||||
88 | }, |
|
89 | }, | |
89 | dom: 'rtp', |
|
90 | dom: 'rtp', | |
90 | pageLength: ${c.visual.dashboard_items}, |
|
91 | pageLength: ${c.visual.dashboard_items}, | |
91 |
order: [[ |
|
92 | order: [[ 2, "desc" ]], | |
92 | columns: [ |
|
93 | columns: [ | |
93 | { data: {"_": "status", |
|
94 | { | |
94 | "sort": "status"}, title: "", className: "td-status", orderable: false}, |
|
95 | data: { | |
95 |
|
|
96 | "_": "status", | |
96 | "sort": "name_raw"}, title: "${_('Id')}", className: "td-componentname", "type": "num" }, |
|
97 | "sort": "status" | |
97 | { data: {"_": "title", |
|
98 | }, title: "PR", className: "td-status", orderable: false | |
98 | "sort": "title"}, title: "${_('Title')}", className: "td-description" }, |
|
99 | }, | |
99 | { data: {"_": "author", |
|
100 | { | |
100 | "sort": "author_raw"}, title: "${_('Author')}", className: "td-user", orderable: false }, |
|
101 | data: { | |
101 |
|
|
102 | "_": "my_status", | |
102 | "sort": "comments_raw"}, title: "", className: "td-comments", orderable: false}, |
|
103 | "sort": "status" | |
103 | { data: {"_": "updated_on", |
|
104 | }, title: "You", className: "td-status", orderable: false | |
104 | "sort": "updated_on_raw"}, title: "${_('Last Update')}", className: "td-time" } |
|
105 | }, | |
|
106 | { | |||
|
107 | data: { | |||
|
108 | "_": "name", | |||
|
109 | "sort": "name_raw" | |||
|
110 | }, title: "${_('Id')}", className: "td-componentname", "type": "num" | |||
|
111 | }, | |||
|
112 | { | |||
|
113 | data: { | |||
|
114 | "_": "title", | |||
|
115 | "sort": "title" | |||
|
116 | }, title: "${_('Title')}", className: "td-description" | |||
|
117 | }, | |||
|
118 | { | |||
|
119 | data: { | |||
|
120 | "_": "author", | |||
|
121 | "sort": "author_raw" | |||
|
122 | }, title: "${_('Author')}", className: "td-user", orderable: false | |||
|
123 | }, | |||
|
124 | { | |||
|
125 | data: { | |||
|
126 | "_": "comments", | |||
|
127 | "sort": "comments_raw" | |||
|
128 | }, title: "", className: "td-comments", orderable: false | |||
|
129 | }, | |||
|
130 | { | |||
|
131 | data: { | |||
|
132 | "_": "updated_on", | |||
|
133 | "sort": "updated_on_raw" | |||
|
134 | }, title: "${_('Last Update')}", className: "td-time" | |||
|
135 | } | |||
105 | ], |
|
136 | ], | |
106 | language: { |
|
137 | language: { | |
107 | paginate: DEFAULT_GRID_PAGINATION, |
|
138 | paginate: DEFAULT_GRID_PAGINATION, |
General Comments 1
You need to be logged in to leave comments.
Login now