Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .TRACFREEZE.txt
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ trac.wiki.web_api.wikirenderer
trac.wiki.web_ui.defaultwikipolicy
tracdjangoplugin.plugins.customnavigationbar
tracdjangoplugin.plugins.customnewticket
tracdjangoplugin.plugins.customsubnavigationbar
tracdjangoplugin.plugins.customtheme
tracdjangoplugin.plugins.customwikimodule
tracdjangoplugin.plugins.githubbrowserwithsvnchangesets
Expand Down
78 changes: 78 additions & 0 deletions DjangoPlugin/tracdjangoplugin/plugins.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,84 @@ def get_navigation_items(self, req):
]


class CustomSubNavigationBar(Component):
"""Add queue items for the sub navigation bar."""

implements(INavigationContributor)

queues = [
{
"name": "unreviewed",
"label": "Needs Triage",
"params": "stage=Unreviewed&status=!closed&order=changetime&desc=1",
},
{
"name": "needs_patch",
"label": "Needs Patch",
"params": "has_patch=0&stage=Accepted&status=!closed&order=changetime&desc=1",
},
{
"name": "needs_pr_review",
"label": "Needs PR Review",
"params": (
"has_patch=1&needs_better_patch=0&needs_docs=0&needs_tests=0&stage=Accepted"
"&status=!closed&order=changetime&desc=1"
),
},
{
"name": "waiting_on_author",
"label": "Waiting On Author",
"params": (
"has_patch=1&needs_better_patch=1&stage=Accepted&status=assigned&status=new"
"&or&has_patch=1&needs_docs=1&stage=Accepted&status=assigned&status=new"
"&or&has_patch=1&needs_tests=1&stage=Accepted&status=assigned&status=new"
"&order=changetime&desc=1"
),
},
{
"name": "ready_for_checkin",
"label": "Ready For Checkin",
"params": "stage=Ready+for+checkin&status=!closed&order=changetime&desc=1",
},
]

def get_active_navigation_item(self, req):
stage = req.args.get("stage")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tried to get this going locally, would you know anything about this error?

Cannot find an implementation of the IRequestHandler interface named CustomWikiModule. Please check that the Component is enabled or update the option [trac] default_handler in trac.ini.

Copy link
Contributor Author

@ontowhee ontowhee Sep 19, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where are you seeing the error? I'm not seeing it. I'm running the project in the docker container, and I have default_handler = CustomWikiModule in trac.ini. Is there a library version mismatch?

Is the error happening at lines 94-97, which is for CustomSubNavigationBar? I wonder why the message reports CustomWikiModule.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did see this error when the project was reloading after some changes. I noticed the css wasn't loading properly either. The error didn't appear after I restarted the container and refreshed the page.

Screenshot 2025-09-19 at 3 45 50 PM

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for checking. Restarting the container didn't help. I must have missed some necessary setup?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Huzzah! cd DjangoPlugin && setup.py seemed to do the trick.


if stage == "Unreviewed":
return "unreviewed"
if stage == "Ready for checkin":
return "ready_for_checkin"
if stage == "Accepted":
if req.query_string == self.queues[1]["params"]:
return "needs_patch"
elif req.query_string == self.queues[2]["params"]:
return "needs_pr_review"
elif req.query_string == self.queues[3]["params"]:
return "waiting_on_author"

return ""

def _get_active_class(self, active_item, subnav_name):
return "active" if active_item == subnav_name else None

def get_navigation_items(self, req):
if req.path_info.startswith("/query"):
active_item = self.get_active_navigation_item(req)
return [
(
"subnav",
queue["name"],
tag.a(
queue["label"],
href="/query?" + queue["params"],
class_=self._get_active_class(active_item, queue["name"]),
),
)
for queue in self.queues
]


class GitHubBrowserWithSVNChangesets(GitHubBrowser):
def _format_changeset_link(self, formatter, ns, chgset, label, fullmatch=None):
# Dead-simple version for SVN changesets.
Expand Down
16 changes: 16 additions & 0 deletions scss/trachacks.scss
Original file line number Diff line number Diff line change
Expand Up @@ -330,6 +330,22 @@ div[role="main"]{
}
}

#subnav {
@include sans-serif;

ul {
text-align: left;

li {
a {
&.active {
font-weight: bold;
}
}
}
}
}

#main {
@include sans-serif;

Expand Down
7 changes: 7 additions & 0 deletions trac-env/conf/trac.ini
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,13 @@ tickets.order = 2.0
timeline.order = 4.0
wiki.order = 5.0

[subnav]
unreviewed.order = 1.0
needs_patch.order = 2.0
needs_pr_review.order = 3.0
waiting_on_author.order = 4.0
ready_for_checkin.order = 5.0

[metanav]
; The metanav is hardcoded in templates/django_theme.html
; because it was too hard to make the login plugins play nice with each other
Expand Down
1 change: 1 addition & 0 deletions trac-env/templates/django_theme.html
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
</ul>
</div>
${navigation('mainnav')}
${navigation('subnav')}
<div id="main" ${{'class': {
'uisymbols': req.session.get('ui.use_symbols'),
'uinohelp': req.session.get('ui.hide_help'),
Expand Down
Loading