Commits

PolCPP committed 4eac243

Initial implementation of the dashboard and it's plugins. It's restored from and ancient implementation i had on this, so except some minor tweaks you can expect some dragons in it. I'll rework/improve it pretty soon.

Dashboard settings documentation will be updated in the next commits

Cleaned some plugin code that was inside the prismriver views.

Updated the Readme with the pip install option from pypi instead from the repo.

Comments (0)

Files changed (17)

+*.pyc
 ------------
 
    - Put the prismriver directory into your Pythonpath/project folder or install it using pip using:
-       - pip install git+https://PolCPP@bitbucket.org/PolCPP/django-prismriver.git
+       - pip install django-prismriver
    - In settings.py make sure that:
        - You have staticfiles configured correctly.
        - You look for templates on a '/templates/'  directory.

prismriver/dashboard/__init__.py

Empty file added.

prismriver/dashboard/admin.py

+from django.contrib import admin
+from prismriver.dashboard.models import HomeScreen, Plugin
+
+class PluginInline(admin.TabularInline):
+    extra = 0
+    model = Plugin
+
+
+class HomeScreenAdmin(admin.ModelAdmin):
+    list_display = ('user',)
+    inlines = (PluginInline,)
+
+
+admin.site.register(HomeScreen, HomeScreenAdmin)

prismriver/dashboard/models.py

+from django.db import models
+from django.utils.translation import ugettext_lazy as _
+from prismriver.dashboard.settings import HOMESCREEN_PLUGIN_CHOICES
+from django.contrib.auth.models import User
+
+class HomeScreen(models.Model):
+    user = models.ForeignKey(User, unique=True)
+
+
+class Plugin(models.Model):
+    home_screen = models.ForeignKey(HomeScreen)
+    position = models.IntegerField(verbose_name=_("Plugin position"))
+    class_name = models.CharField(max_length=128,
+                                  choices=HOMESCREEN_PLUGIN_CHOICES,
+                                  verbose_name=_("Plugin Classname"))
+
+    class Meta:
+        verbose_name = _("Plugin")
+        verbose_name_plural = _("Plugins")
+

prismriver/dashboard/plugins/__init__.py

Empty file added.

prismriver/dashboard/plugins/dashplugins.py

+from django.core.urlresolvers import reverse
+from django.template.context import Context
+from django.template.loader import get_template
+from prismriver.dashboard.plugins import pluginbase
+from prismriver.settings import CUSTOM_MENU
+from prismriver.dashboard.settings import APP_MENU
+from prismriver.views import load_apps, load_custom_models
+from copy import deepcopy
+
+
+class AppList(pluginbase.DashboardPlugin):
+    def get_custom_menu(self, request):
+        apps = deepcopy(APP_MENU)
+        for app in apps:
+            app["models"], app["enabled"] = load_custom_models(request, app["items"])
+        c = Context({"apps": apps})
+        t = get_template('plugins/app_menu.html')
+        return t.render(c)
+
+    def get_menu(self, request):
+        current_url = request.path.replace(reverse('admin:index'), "").lower()
+        c = Context({"apps": load_apps(request)})
+        t = get_template('plugins/app_menu.html')
+        return t.render(c)
+
+    def render(self, request):
+        if CUSTOM_MENU:
+            return self.get_custom_menu(request)
+        else:
+            return self.get_menu(request)

prismriver/dashboard/plugins/pluginbase.py

+class DashboardPlugin(object):
+    def render(self, request):
+        raise NotImplementedError

prismriver/dashboard/settings.py

+from django.conf import settings
+
+# The app menu (this is used by the App menu site plugin:
+# Default: Joins Prismriver auth and sites in a menu named Users and settings
+if hasattr(settings, 'APP_MENU'):
+    APP_MENU = settings.APP_MENU
+else:
+    APP_MENU = [
+            {"name": "Users and Settings",
+             "items": ["auth", "prismriver", "sites"],
+             "icon": "users.png",
+             "big_icon": "users_big.png",
+             "description": "Manage everything about the users here",
+             },
+              ]
+
+#Plugin choices
+if hasattr(settings, 'HOMESCREEN_PLUGIN_CHOICES'):
+    HOMESCREEN_PLUGIN_CHOICES = settings.HOMESCREEN_PLUGIN_CHOICES
+else:
+    HOMESCREEN_PLUGIN_CHOICES = (('prismriver.dashboard.plugins.dashplugins.AppList', 'App list'),
+        )

prismriver/dashboard/static/admin/css/dash_override.css

+.language_button {
+    -moz-border-bottom-colors: none !important;
+    -moz-border-image: none !important;
+    -moz-border-left-colors: none !important;
+    -moz-border-right-colors: none !important;
+    -moz-border-top-colors: none !important;
+    background: none repeat scroll 0 0 #EEEEEE !important;
+    border-color: #AAAAAA !important;
+    border-radius: 5px 5px 0 0 !important;
+    border-style: solid solid none !important;
+    border-width: 1px 1px medium !important;
+    font-size: 11px;
+    font-weight: normal;
+    height: 26px;
+    margin-left: 2px;
+    margin-top: 10px;
+}
+
+#lang_tab_content h2.header {
+    background: none repeat scroll 0 0 #444444;
+    margin-top: 1px;
+}
+
+.language_button.selected {
+    background: none repeat scroll 0 0 #444444 !important;
+    border: 1px solid #444444 !important;
+    color: white;
+}
+
+.language_button.selected {
+}
+
+.language_button:hover {
+    cursor: pointer;
+    text-decoration: underline !important;
+}
+
+#page_form_lang_tabs {
+    margin-left: 10px;
+}
+
+.language_button.selected:hover {
+    text-decoration: none !important;
+}
+
+.plugged_app {
+    background: none repeat scroll 0 0 #F5F5F5;
+    border: 1px solid #CCCCCC;
+    float: left;
+    margin: 7px;
+    min-height: 90px;
+    width: 165px;
+    padding: 5px;
+    text-align: left;
+}
+
+.plugged_app .app_title img {
+    padding-bottom: 5px;
+    vertical-align: middle;
+}
+
+.plugged_app .app_title {
+    font-size: 14px;
+}
+
+.plugged_app .description {
+    color: #777777;
+    font-size: 11px;
+    font-style: italic;
+    width: 130px;
+}
+
+.plugged_app li {
+    list-style: circle;
+}
+
+.plugged_app ul {
+    color: #5B80B2;
+    padding-left: 25px;
+}
+

prismriver/dashboard/templates/admin/dashboard.html

+{% extends "admin/base_site.html" %}
+{% load admin_static admin_list i18n %}
+
+{% block extrastyle %}{{ block.super }}
+    <link rel="stylesheet" type="text/css"
+          href="{% static "admin/css/dash_override.css" %}"/>
+
+    {% if not media.js %}
+    	<script type="text/javascript" src="{% static "admin/js/core.js" %} "></script>
+        <script type="text/javascript" src="{% static "admin/js/jquery.min.js" %}"></script>
+        <script type="text/javascript" src="{% static "admin/js/jquery.init.js" %}"></script>
+    {% endif %}
+
+{% endblock %}
+
+{% block coltype %}colMS{% endblock %}
+
+{% block bodyclass %}dashboard{% endblock %}
+
+{% block breadcrumbs %}{% endblock %}
+
+{% block content %}
+<div id="content-main">
+    {% for plugin in plugins %}
+    {{ plugin }}
+
+    {% endfor %}
+</div>
+{% endblock %}
+
+{% block sidebar %}
+
+{% endblock %}

prismriver/dashboard/templates/plugins/app_menu.html

+{% load admin_static %}
+<div id="app plugin" style="clear: both;">
+    <h1 style="margin: 7px; border-bottom: 2px solid rgb(119, 119, 119);">Dashboard</h1>
+    {% if custom %}
+    {% for app in apps %}
+    <div class="plugged_app">
+        <a class="app_title" href="javascript:void(0)"> <img src="{% static "admin/img/app_icon/" %}{{ app.big_icon }}">
+            {{ app.name }}</a>
+
+        <div class="description"> {{ app.description }}</div>
+        <ul style="display:none">
+            {% for model in app.models %}
+            <li><a href="/admin/{{ model.admin_url }}">{{ model.name }}</a></li>
+            {% endfor %}
+        </ul>
+    </div>
+    {% endfor %}
+    {% else %}
+    {% for app in apps %}
+    <div class="plugged_app">
+        <a class="app_title" href="javascript:void(0)"><img src="{% static "admin/img/app_icon/" %}{{ app.big_icon }}">
+            {{ app.name }}</a>
+
+        <div class="description"> {{ app.description }}</div>
+        <ul style="display:none">
+            {% for model in app.models %}
+            <li><a href="/admin/{{ model.admin_url }}">{{ model.name }}</a></li>
+            {% endfor %}
+        </ul>
+    </div>
+    {% endfor %}
+    {% endif %}
+</div>

prismriver/dashboard/urls.py

+from django.conf.urls.defaults import *
+
+urlpatterns = patterns('', url(r'^$', 'prismriver.dashboard.views.dashboard'))

prismriver/dashboard/views.py

+from django.utils.translation import ugettext_lazy as _
+from django.shortcuts import render_to_response
+from django.contrib.admin.views.decorators import staff_member_required
+
+from django import template
+from django.core.urlresolvers import reverse
+from django.contrib import admin
+from django.utils.safestring import mark_safe
+from django.utils.text import capfirst
+from prismriver.settings import CUSTOM_MENU, DEFAULT_LABELS
+from prismriver.dashboard.models import Plugin
+
+def separate_class_path(class_path):
+    path = class_path.split(".")
+    class_name = path.pop()
+    class_path = ".".join([i for i in path])
+    return str(class_path), str(class_name)
+
+
+@staff_member_required
+def dashboard(request):
+    rendered_plugins = []
+    plugins = Plugin.objects.filter(home_screen__user__username=request.user.username).order_by("position")
+    for p in plugins:
+        class_path, class_name = separate_class_path(p.class_name)
+        plugin = getattr(__import__(class_path, globals(),
+                                    locals(), [class_name]), class_name)()
+        rendered_plugins.append(plugin.render(request))
+    context = {
+        'title': _('Site administration'),
+        'plugins': rendered_plugins,
+        }
+    context.update({})
+    context_instance = template.RequestContext(request)
+    return render_to_response('admin/dashboard.html', context,
+                              context_instance=context_instance)
+
+

prismriver/templates/admin/side_menu.html

         {% if app.enabled %}
             <div class="side_app side_selected">
             <img src="{% static "admin/img/app_icon/" %}{{ app.icon }}">
-            <a class="app_title" href="javascript:void()"> {{ app.name }}</a>
+            <a class="app_title" href="javascript:void(0)"> {{ app.name }}</a>
             <ul style="">
         {% else %}
             <div class="side_app">
 
             <img src="{% static "admin/img/app_icon/" %}{{ app.icon }}">
-            <a class="app_title" href="javascript:void()"> {{ app.name }}</a>
+            <a class="app_title" href="javascript:void(0)"> {{ app.name }}</a>
             <ul style="display:none">
         {% endif %}
 
     {% if app.enabled %}
         <div class="side_app side_selected">
         <img src="{% static "admin/img/app_icon/" %}{{ app.icon }}">
-        <a class="app_title" href="javascript:void()"> {{ app.name }}</a>
+        <a class="app_title" href="javascript:void(0)"> {{ app.name }}</a>
 
         <ul style="">
     {% else %}
         <div class="side_app">
         <img src="{% static "admin/img/app_icon/" %}{{ app.icon }}">
-        <a class="app_title" href="javascript:void()"> {{ app.name }}</a>
+        <a class="app_title" href="javascript:void(0)"> {{ app.name }}</a>
         <ul style="display:none">
     {% endif %}
 {% for model in app.models %}

prismriver/views.py

 from django.utils.safestring import mark_safe
 from django.utils.text import capfirst
 from prismriver.settings import CUSTOM_MENU, DEFAULT_LABELS
-#from prismriver.models import Plugin
-
-def separate_class_path(class_path):
-    path = class_path.split(".")
-    class_name = path.pop()
-    class_path = ".".join([i for i in path])
-    return str(class_path), str(class_name)
-
 
 def load_apps(request):
     current_url = request.path.replace(reverse('admin:index'), "")
 
 setup(
     name='django-prismriver',
-    version='0.1',
+    version='0.12',
     description='A light but cool Django admin theme',
     author=u'Pol Cámara',
     author_email='polcamara@soft10.es',
     keywords = "django admin",    
     long_description=open('README.MD').read(),
     zip_safe=False,
-)
+)