From my previous post I've talked about colorbox approach for admin dashboard. If you want to try, visit my demo instance at http://melange-new-dashboard.appspot.com/ using the following account:
username: melangetestdashboard@gmail.com
password: melangetestdashboardpassword
There are some changes in the JS, CSS and template. Some of these were just new files. I'll talk about code that make a sense to review. Before that, I'll divide the topic into two sections so you can skip a topic that you don't want to read.
Changes in admin's view
If you've tried the admin dashboard from the link that I gave above. You should try to toggle the colorbox or click the "Program settings" link. If you click the "Program settings" link, the dashboard will change its content. The case is the same for "Manage organizations" link. If you inspect the page with firebug, you'll notice that it just switching between div elements. Let's call this a sub dashboard.
So, a link that have sub links at the bottom of its description will point to the div that hidden at that moment, that's a sub dashboard. When we clicked "Program settings", the div with id "program-settings-dashboard" will be shown, the "disabled" class was removed. And the "main-dashboard" will be hidden. I figured out what's the best solution to reorder the links or reorganizing sub dashboard without coupled too many files. So I came up with the idea that these links and sub dashboards should be managed inside soc.modules.gsoc.views.admin. I managed to create a new class named Dashboard that inherits Template class:
class Dashboard(Template):
"""Base dashboard for admin page
"""
def __init__(self, request, data, subpages=None):
"""Initializes the dashboard.
Args:
request: The HTTPRequest object
data: The RequestData object
subpages: Subpages of current dashboard
"""
self.request = request
self.data = data
self.subpages = subpages
def getSubpagesLink(self):
"""Returns the link to other dashboard that appears
on top of the dashboard.
"""
return self.subpages
def templatePath(self):
"""Returns the path to the template that should be used in render()
"""
return 'v2/modules/gsoc/admin/dashboard.html'
def _divideSubPages(self, subpages):
"""Returns the subpages divided into two columns.
"""
middle_ceil = int(math.ceil(float(len(subpages))/2))
return [
subpages[:middle_ceil],
subpages[middle_ceil:],
]
class MainDashboard(Dashboard):
"""Dashboard for admin's main-dashboard
"""
def __init__(self, request, data):
"""Initializes the dashboard.
Args:
request: The HTTPRequest object
data: The RequestData object
"""
super(MainDashboard, self).__init__(request, data)
def context(self):
"""Returns the context of main dashboard.
"""
r = self.data.redirect
r.program()
manage_orgs = ManageOrganizationsDashboard(self.request, self.data)
program_settings = ProgramSettigsDashboard(self.request, self.data)
subpages = [
{
'name': 'lookup_profile',
'description': ugettext(
'Lookup profile of mentor or student from various program.'),
'title': 'Lookup profile',
'link': r.urlOf('lookup_gsoc_profile')
},
{
'name': 'allocate_slots',
'description': ugettext(
'Allocate slots (number of acceptable projects) per '
'organization'),
'title': 'Allocate slots',
'link': r.urlOf('gsoc_slots')
},
{
'name': 'slots_transfer',
'description': ugettext(
'Transfer slots for organizations'),
'title': 'Slots transfer',
'link': r.urlOf('gsoc_admin_slots_transfer')
},
{
'name': 'duplicates',
'description': ugettext(
'Calculate how many duplicate proposals'),
'title': 'Duplicates',
'link': r.urlOf('gsoc_view_duplicates')
},
{
'name': 'manage_organizations',
'description': ugettext(
'Manage organizations from active program. You can allocate '
'slots for organizations, manage invitations for '
'org admin/mentors, and withdraw/accept students/mentors '
'from various organizations'),
'title': 'Manage organizations',
'link': '',
'subpage_links': manage_orgs.getSubpagesLink(),
},
{
'name': 'reminder_emails',
'description': ugettext(
'Send reminder emails for evaluations.'),
'title': 'Send reminder emails for evaluations',
'link': r.urlOf('gsoc_survey_reminder_admin')
},
{
'name': 'program_settings',
'description': ugettext(
'Edit program settings and timeline'),
'title': 'Program settings',
'link': '',
'subpage_links': program_settings.getSubpagesLink(),
},
{
'name': 'participant_locations',
'description': ugettext(
'Show all participants (students and mentors) in a '
'clusterer map. You can also view a single profile map '
'after clicking the marker.'),
'title': 'Participant Locations',
'link': '#'
},
{
'name': 'report_statistic',
'description': ugettext(
'Reports and statistics of program'),
'title': 'Report/statistic',
'link': '#'
},
]
return {
'title': 'Admin Dashboard',
'name': 'main',
'subpages': self._divideSubPages(subpages),
'enabled': True
}
class ProgramSettigsDashboard(Dashboard):
"""Dashboard for admin's program-settings-dashboard
"""
def __init__(self, request, data):
"""Initializes the dashboard.
Args:
request: The HTTPRequest object
data: The RequestData object
"""
r = data.redirect
r.program()
subpages = [
{
'name': 'edit_program',
'description': ugettext(
'Edit your program settings such as information, slots, '
'documents, etc.'),
'title': 'Edit program',
'link': r.urlOf('edit_gsoc_program')
},
{
'name': 'edit_timeline',
'description': ugettext(
'Edit your program timeline such as program start/end date, '
'student signup start/end date, etc.'),
'title': 'Edit timeline',
'link': r.urlOf('edit_gsoc_timeline')
},
]
super(ProgramSettigsDashboard, self).__init__(request, data, subpages)
def context(self):
"""Returns the context of manage organizations dashboard.
"""
subpages = self._divideSubPages(self.subpages)
return {
'title': 'Program Settings',
'name': 'program_settings',
'backlink': {
'to': 'main',
'title': 'Admin dashboard'
},
'subpages': subpages
}
To set the links, we need to set it into subpages context. If you want a link to another dashboard inside MainDashboard, such as "Program Settings", just create another class that inherits Dashboard, supply the backlink to refer back to the parent's dashboard and set the subpages of its own dashboard inside the new class. In the parent dashboard's subpages context supply the subpage_links to indicate this is a dashboard link. How about the icon itself? This is where the CSS rules. The name you supply for each link inside the subpages content will be rendered as a class name of the link's container. Everything's that related to the style of admin dashboard is defined inside v2/gsoc/admin.css file. I got the icons from Tango Desktop Project which is licensed under GPL.
The next thing that you might need to know is the addition of colorbox base layout. A colorbox base layout is minimalistic template without sidebarmenu and header. The rest is the same. To make any page rendered in colorbox layout, you need to pass cbox query string. The RequestHandler will take care the base layout. Each page that extends the base.html template need to change the extends tag to base_layout, {% extends base_layout %}. The rest of changes inside soc.modules.gsoc.views.admin were new handlers with list.
What's done and what needs to be done or in-progress
I promised to finish the admin dashboard before the mid-term. This means the code it self should be reviewed lately in this week. The scope for the deadline before the mid-term was a fully functional admin dashboard that the mockup already given before. Okay, here are what's done in the admin dashboard:
- New admin's view architecture that I've discussed in the previous section
- Handling colorbox template
- A few handlers inside soc.modules.gsos.views.admin
Here are what needs to be done and in-progress:
- Submit my code for review, possibly after writing this post.
- The test_slots was failed because I created new template and changed the list template for accepted organizations. I refactor the list for accepted organizations inside admin's view so other handlers can use it. I'll fix the test after my code being reviewed.
- Adding test for soc.modules.gsoc.admin. By looking at other view tests, it just a test case to make sure the template is rendered with the right context.
- A participant locations to mark all participant into a single map using MarkerClusterer. This is not a critical requirement and can be skipped.
- Refined toggleable list patch as suggested by Mario.
No comments:
Post a Comment