feat: pluggable profile tabs
Added ProfileTab class to represent a profile tab and made the profile page render the tabs specified in the hook `profile_tabs`. This allows plugging in new tabs in the profile page without makeing any changes to the community module.
This commit is contained in:
38
community/community/profile_tab.py
Normal file
38
community/community/profile_tab.py
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
"""
|
||||||
|
The profile_tab module provides a pluggable way to add tabs to user
|
||||||
|
profiles.
|
||||||
|
|
||||||
|
This is achieved by specifying the profile_tabs in the hooks.
|
||||||
|
|
||||||
|
profile_tabs = [
|
||||||
|
'myapp.myapp.profile_tabs.SketchesTab'
|
||||||
|
]
|
||||||
|
|
||||||
|
When a profile page is rendered, these classes specified in the
|
||||||
|
profile_hooks are instanciated with the user as argument and used to
|
||||||
|
render the tabs.
|
||||||
|
"""
|
||||||
|
|
||||||
|
class ProfileTab:
|
||||||
|
"""Base class for profile tabs.
|
||||||
|
|
||||||
|
Every subclass of ProfileTab must implement two methods:
|
||||||
|
- get_title()
|
||||||
|
- render()
|
||||||
|
"""
|
||||||
|
def __init__(self, user):
|
||||||
|
self.user = user
|
||||||
|
|
||||||
|
def get_title(self):
|
||||||
|
"""Returns the title of the tab.
|
||||||
|
|
||||||
|
Every subclass must implement this.
|
||||||
|
"""
|
||||||
|
raise NotImplementedError()
|
||||||
|
|
||||||
|
def render(self):
|
||||||
|
"""Renders the contents of the tab as HTML.
|
||||||
|
|
||||||
|
Every subclass must implement this.
|
||||||
|
"""
|
||||||
|
raise NotImplementedError()
|
||||||
@@ -72,29 +72,26 @@
|
|||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<ul class="nav nav-tabs mt-4" id="myTab" role="tablist">
|
<ul class="nav nav-tabs mt-4" id="myTab" role="tablist">
|
||||||
<li class="nav-item">
|
{% for tab in profile_tabs %}
|
||||||
<a class="nav-link active" id="home-tab" data-toggle="tab" href="#home" role="tab" aria-controls="home"
|
<li class="nav-item">
|
||||||
aria-selected="true">Sketches</a>
|
{% set slug = title.lower().replace(" ", "-") %}
|
||||||
</li>
|
{% set selected = loop.index == 1 %}
|
||||||
|
{% set active = 'active' if loop.index == 1 else '' %}
|
||||||
|
<a class="nav-link {{ active }}" id="{{ slug }}-tab" data-toggle="tab" href="#{{ slug }}" role="tab" aria-controls="{{ slug }}"
|
||||||
|
aria-selected="{{ selected }}">Sketches</a>
|
||||||
|
</li>
|
||||||
|
{% endfor %}
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<div class="tab-content">
|
{% for tab in profile_tabs %}
|
||||||
<div class="tab-pane fade py-4 show active" role="tabpanel" id="home">
|
{% set slug = title.lower().replace(" ", "-") %}
|
||||||
<div class="row">
|
<div class="tab-content">
|
||||||
{% if sketches %}
|
<div class="tab-pane fade py-4 show active" role="tabpanel" id="slug">
|
||||||
{% for sketch in sketches %}
|
{{ tab.render() }}
|
||||||
<div class="col-md-4 col-sm-6">
|
|
||||||
{{ widgets.SketchTeaser(sketch=sketch) }}
|
|
||||||
</div>
|
|
||||||
{% endfor %}
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
</div>
|
||||||
{% if not sketches %}
|
|
||||||
<p class="text-center">{{member.full_name}} has not created any skecth yet.</p>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -3,9 +3,20 @@ from community.lms.models import Sketch
|
|||||||
|
|
||||||
def get_context(context):
|
def get_context(context):
|
||||||
context.no_cache = 1
|
context.no_cache = 1
|
||||||
|
|
||||||
try:
|
try:
|
||||||
context.member = frappe.get_doc("User", {"username": frappe.form_dict["username"]})
|
context.member = frappe.get_doc("User", {"username": frappe.form_dict["username"]})
|
||||||
except:
|
except:
|
||||||
context.template = "www/404.html"
|
context.template = "www/404.html"
|
||||||
else:
|
return
|
||||||
context.sketches = Sketch.get_recent_sketches(owner=context.member.email)
|
|
||||||
|
context.profile_tabs = get_profile_tabs(context.member)
|
||||||
|
|
||||||
|
def get_profile_tabs(user):
|
||||||
|
"""Returns the enabled ProfileTab objects.
|
||||||
|
|
||||||
|
Each ProfileTab is rendered as a tab on the profile page and the
|
||||||
|
they are specified as profile_tabs hook.
|
||||||
|
"""
|
||||||
|
tabs = frappe.get_hooks("profile_tabs") or []
|
||||||
|
return [frappe.get_attr(tab)(user) for tab in tabs]
|
||||||
|
|||||||
Reference in New Issue
Block a user