Browse Source

Merge branch 'feature/dashboard-detach' into dev

Denis K 9 years ago
parent
commit
cfc6765e6d
68 changed files with 1786 additions and 977 deletions
  1. 1 0
      CHANGELOG.rst
  2. 0 0
      jet/dashboard/__init__.py
  3. 4 4
      jet/dashboard/dashboard.py
  4. 0 0
      jet/dashboard/dashboard_modules/__init__.py
  5. 19 13
      jet/dashboard/dashboard_modules/google_analytics.py
  6. 7 7
      jet/dashboard/dashboard_modules/google_analytics_views.py
  7. 22 12
      jet/dashboard/dashboard_modules/yandex_metrika.py
  8. 5 5
      jet/dashboard/dashboard_modules/yandex_metrika_views.py
  9. 130 0
      jet/dashboard/forms.py
  10. 33 0
      jet/dashboard/migrations/0001_initial.py
  11. 0 0
      jet/dashboard/migrations/__init__.py
  12. 57 0
      jet/dashboard/models.py
  13. 6 6
      jet/dashboard/modules.py
  14. 5 0
      jet/dashboard/settings.py
  15. 0 0
      jet/dashboard/static/jet.dashboard/dashboard_modules/google_analytics.js
  16. 0 0
      jet/dashboard/static/jet.dashboard/dashboard_modules/yandex_metrika.js
  17. 0 0
      jet/dashboard/static/jet.dashboard/vendor/chart.js/CONTRIBUTING.md
  18. 0 0
      jet/dashboard/static/jet.dashboard/vendor/chart.js/Chart.js
  19. 0 0
      jet/dashboard/static/jet.dashboard/vendor/chart.js/Chart.min.js
  20. 0 0
      jet/dashboard/static/jet.dashboard/vendor/chart.js/LICENSE.md
  21. 0 0
      jet/dashboard/static/jet.dashboard/vendor/chart.js/README.md
  22. 2 2
      jet/dashboard/templates/admin/app_index.html
  23. 35 0
      jet/dashboard/templates/admin/index.html
  24. 4 4
      jet/dashboard/templates/jet.dashboard/dashboard.html
  25. 1 1
      jet/dashboard/templates/jet.dashboard/dashboard_tools.html
  26. 2 2
      jet/dashboard/templates/jet.dashboard/module.html
  27. 0 0
      jet/dashboard/templates/jet.dashboard/modules/app_list.html
  28. 0 0
      jet/dashboard/templates/jet.dashboard/modules/feed.html
  29. 0 0
      jet/dashboard/templates/jet.dashboard/modules/google_analytics_period_visitors.html
  30. 0 0
      jet/dashboard/templates/jet.dashboard/modules/google_analytics_visitors_chart.html
  31. 0 0
      jet/dashboard/templates/jet.dashboard/modules/google_analytics_visitors_totals.html
  32. 0 0
      jet/dashboard/templates/jet.dashboard/modules/link_list.html
  33. 0 0
      jet/dashboard/templates/jet.dashboard/modules/model_list.html
  34. 0 0
      jet/dashboard/templates/jet.dashboard/modules/recent_actions.html
  35. 0 0
      jet/dashboard/templates/jet.dashboard/modules/yandex_metrika_period_visitors.html
  36. 0 0
      jet/dashboard/templates/jet.dashboard/modules/yandex_metrika_visitors_chart.html
  37. 0 0
      jet/dashboard/templates/jet.dashboard/modules/yandex_metrika_visitors_totals.html
  38. 4 4
      jet/dashboard/templates/jet.dashboard/update_module.html
  39. 0 0
      jet/dashboard/templates/jet.dashboard/update_module_fieldset.html
  40. 0 0
      jet/dashboard/templatetags/__init__.py
  41. 12 0
      jet/dashboard/templatetags/jet_dashboard_tags.py
  42. 53 0
      jet/dashboard/urls.py
  43. 17 0
      jet/dashboard/utils.py
  44. 223 0
      jet/dashboard/views.py
  45. 5 129
      jet/forms.py
  46. BIN
      jet/locale/en/LC_MESSAGES/django.mo
  47. 476 199
      jet/locale/en/LC_MESSAGES/django.po
  48. BIN
      jet/locale/ru/LC_MESSAGES/django.mo
  49. 492 205
      jet/locale/ru/LC_MESSAGES/django.po
  50. 17 0
      jet/migrations/0002_delete_userdashboardmodule.py
  51. 0 50
      jet/models.py
  52. 0 4
      jet/settings.py
  53. 7 3
      jet/static/jet/css/_content.scss
  54. 6 3
      jet/static/jet/css/themes/default/base.css
  55. 0 0
      jet/static/jet/css/themes/default/base.css.map
  56. 6 3
      jet/static/jet/css/themes/green/base.css
  57. 0 0
      jet/static/jet/css/themes/green/base.css.map
  58. 6 4
      jet/templates/admin/base.html
  59. 101 26
      jet/templates/admin/index.html
  60. 1 8
      jet/templatetags/jet_tags.py
  61. 2 2
      jet/tests/dashboard.py
  62. 1 0
      jet/tests/settings.py
  63. 4 4
      jet/tests/test_dashboard.py
  64. 15 14
      jet/tests/test_views.py
  65. 1 0
      jet/tests/urls.py
  66. 1 36
      jet/urls.py
  67. 0 15
      jet/utils.py
  68. 3 212
      jet/views.py

+ 1 - 0
CHANGELOG.rst

@@ -25,6 +25,7 @@ Changelog
 * [Fix] Fixed double shadow for tables in dashboard modules
 * [Fix] Fixed tables forced alignment
 * [Fix] Fixed dashboard ul layout
+* [Fix] Fixed language code formatting for js
 
 
 0.0.6

+ 0 - 0
jet/dashboard_modules/__init__.py → jet/dashboard/__init__.py


+ 4 - 4
jet/dashboard.py → jet/dashboard/dashboard.py

@@ -1,8 +1,8 @@
 from importlib import import_module
 from django.core.urlresolvers import resolve, reverse
 from django.template.loader import render_to_string
-from jet import modules
-from jet.models import UserDashboardModule
+from jet.dashboard import modules
+from jet.dashboard.models import UserDashboardModule
 from django.core.context_processors import csrf
 from django.utils.translation import ugettext_lazy as _
 from jet.ordered_set import OrderedSet
@@ -99,7 +99,7 @@ class Dashboard(object):
         })
         context.update(csrf(context['request']))
 
-        return render_to_string('jet/dashboard/dashboard.html', context)
+        return render_to_string('jet.dashboard/dashboard.html', context)
 
     def render_tools(self):
         context = self.context
@@ -110,7 +110,7 @@ class Dashboard(object):
         })
         context.update(csrf(context['request']))
 
-        return render_to_string('jet/dashboard/dashboard_tools.html', context)
+        return render_to_string('jet.dashboard/dashboard_tools.html', context)
 
     def media(self):
         unique_css = OrderedSet()

+ 0 - 0
jet/dashboard/dashboard_modules/__init__.py


+ 19 - 13
jet/dashboard_modules/google_analytics.py → jet/dashboard/dashboard_modules/google_analytics.py

@@ -9,7 +9,7 @@ from django.utils.html import format_html
 from django.utils.safestring import mark_safe
 from googleapiclient.discovery import build
 import httplib2
-from jet.modules import DashboardModule
+from jet.dashboard.modules import DashboardModule
 from oauth2client.client import flow_from_clientsecrets, OAuth2Credentials, AccessTokenRefreshError, Storage
 from django.utils.translation import ugettext_lazy as _
 from django.conf import settings
@@ -138,21 +138,27 @@ class CredentialWidget(Widget):
 
     def render(self, name, value, attrs=None):
         if value and len(value) > 0:
-            link = '<a href="%s">Revoke access</a>' % reverse('jet:google-analytics-revoke', kwargs={'pk': self.module.model.pk})
+            link = '<a href="%s">%s</a>' % (
+                reverse('jet-dashboard:google-analytics-revoke', kwargs={'pk': self.module.model.pk}),
+                _('Revoke access')
+            )
         else:
-            link = '<a href="%s">Grant access</a>' % reverse('jet:google-analytics-grant', kwargs={'pk': self.module.model.pk})
+            link = '<a href="%s">%s</a>' % (
+                reverse('jet-dashboard:google-analytics-grant', kwargs={'pk': self.module.model.pk}),
+                _('Grant access')
+            )
 
         attrs = self.build_attrs({
             'type': 'hidden',
             'name': 'credential',
         })
-        attrs['value'] = force_unicode(value)
+        attrs['value'] = force_unicode(value) if value else ''
 
         return format_html('%s<input{} />' % link, flatatt(attrs))
 
 
 class GoogleAnalyticsSettingsForm(forms.Form):
-    credential = forms.CharField(label=_('Credential'), widget=CredentialWidget)
+    credential = forms.CharField(label=_('Access'), widget=CredentialWidget)
     counter = forms.ChoiceField(label=_('Counter'))
     period = forms.ChoiceField(label=_('Statistics period'), choices=(
         (0, _('Today')),
@@ -169,7 +175,7 @@ class GoogleAnalyticsSettingsForm(forms.Form):
     def set_counter_choices(self, module):
         counters = module.counters()
         if counters is not None:
-            self.fields['counter'].choices = (('', _('-- none --')),)
+            self.fields['counter'].choices = (('', '-- %s --' % _('none')),)
             self.fields['counter'].choices.extend(map(lambda x: (x['id'], x['websiteUrl']), counters))
         else:
             label = _('grant access first') if module.credential is None else _('counters loading failed')
@@ -266,10 +272,10 @@ class GoogleAnalyticsBase(DashboardModule):
 
     def counter_attached(self):
         if self.credential is None:
-            self.error = mark_safe(_('Please <a href="%s">attach Google account and choose Google Analytics counter</a> to start using widget') % reverse('jet:update_module', kwargs={'pk': self.model.pk}))
+            self.error = mark_safe(_('Please <a href="%s">attach Google account and choose Google Analytics counter</a> to start using widget') % reverse('jet-dashboard:update_module', kwargs={'pk': self.model.pk}))
             return False
         elif self.counter is None:
-            self.error = mark_safe(_('Please <a href="%s">select Google Analytics counter</a> to start using widget') % reverse('jet:update_module', kwargs={'pk': self.model.pk}))
+            self.error = mark_safe(_('Please <a href="%s">select Google Analytics counter</a> to start using widget') % reverse('jet-dashboard:update_module', kwargs={'pk': self.model.pk}))
             return False
         else:
             return True
@@ -290,13 +296,13 @@ class GoogleAnalyticsBase(DashboardModule):
             except Exception as e:
                 error = _('API request failed.')
                 if isinstance(e, AccessTokenRefreshError):
-                    error += _(' Try to <a href="%s">revoke and grant access</a> again') % reverse('jet:update_module', kwargs={'pk': self.model.pk})
+                    error += _(' Try to <a href="%s">revoke and grant access</a> again') % reverse('jet-dashboard:update_module', kwargs={'pk': self.model.pk})
                 self.error = mark_safe(error)
 
 
 class GoogleAnalyticsVisitorsTotals(GoogleAnalyticsBase):
     title = _('Google Analytics visitors totals')
-    template = 'jet/dashboard/modules/google_analytics_visitors_totals.html'
+    template = 'jet.dashboard/modules/google_analytics_visitors_totals.html'
 
     def __init__(self, title=None, period=None, **kwargs):
         kwargs.update({'period': period})
@@ -316,14 +322,14 @@ class GoogleAnalyticsVisitorsTotals(GoogleAnalyticsBase):
 
 class GoogleAnalyticsVisitorsChart(GoogleAnalyticsBase):
     title = _('Google Analytics visitors chart')
-    template = 'jet/dashboard/modules/google_analytics_visitors_chart.html'
+    template = 'jet.dashboard/modules/google_analytics_visitors_chart.html'
     style = 'overflow-x: auto;'
     show = None
     group = None
     settings_form = GoogleAnalyticsChartSettingsForm
 
     class Media:
-        js = ('jet/vendor/chart.js/Chart.min.js', 'jet/dashboard_modules/google_analytics.js')
+        js = ('jet.dashboard/vendor/chart.js/Chart.min.js', 'jet.dashboard/dashboard_modules/google_analytics.js')
 
     def __init__(self, title=None, period=None, show=None, group=None, **kwargs):
         kwargs.update({'period': period, 'show': show, 'group': group})
@@ -361,7 +367,7 @@ class GoogleAnalyticsVisitorsChart(GoogleAnalyticsBase):
 
 class GoogleAnalyticsPeriodVisitors(GoogleAnalyticsBase):
     title = _('Google Analytics period visitors')
-    template = 'jet/dashboard/modules/google_analytics_period_visitors.html'
+    template = 'jet.dashboard/modules/google_analytics_period_visitors.html'
     group = None
     contrast = False
     settings_form = GoogleAnalyticsPeriodVisitorsSettingsForm

+ 7 - 7
jet/dashboard_modules/google_analytics_views.py → jet/dashboard/dashboard_modules/google_analytics_views.py

@@ -3,16 +3,16 @@ from django.conf.urls import url
 from django.contrib import messages
 from django.shortcuts import redirect
 from httplib2 import ServerNotFoundError
-from jet.dashboard_modules.google_analytics import GoogleAnalyticsClient, ModuleCredentialStorage
-from jet.models import UserDashboardModule
-from jet import dashboard
+from jet.dashboard.dashboard_modules.google_analytics import GoogleAnalyticsClient, ModuleCredentialStorage
+from jet.dashboard.models import UserDashboardModule
+from jet.dashboard import dashboard
 from django.http import HttpResponse
 from oauth2client.client import FlowExchangeError
 from django.utils.translation import ugettext_lazy as _
 
 
 def google_analytics_grant_view(request, pk):
-    redirect_uri = request.build_absolute_uri(reverse('jet:google-analytics-callback'))
+    redirect_uri = request.build_absolute_uri(reverse('jet-dashboard:google-analytics-callback'))
     client = GoogleAnalyticsClient(redirect_uri=redirect_uri)
     return redirect(client.get_oauth_authorize_url(pk))
 
@@ -21,7 +21,7 @@ def google_analytics_revoke_view(request, pk):
     try:
         module = UserDashboardModule.objects.get(pk=pk)
         ModuleCredentialStorage(module).delete()
-        return redirect(reverse('jet:update_module', kwargs={'pk': module.pk}))
+        return redirect(reverse('jet-dashboard:update_module', kwargs={'pk': module.pk}))
     except UserDashboardModule.DoesNotExist:
         return HttpResponse(_('Module not found'))
 
@@ -33,7 +33,7 @@ def google_analytics_callback_view(request):
         state = request.GET['state']
         module = UserDashboardModule.objects.get(pk=state)
 
-        redirect_uri = request.build_absolute_uri(reverse('jet:google-analytics-callback'))
+        redirect_uri = request.build_absolute_uri(reverse('jet-dashboard:google-analytics-callback'))
         client = GoogleAnalyticsClient(redirect_uri=redirect_uri)
         client.set_credential_from_request(request)
 
@@ -45,7 +45,7 @@ def google_analytics_callback_view(request):
     except UserDashboardModule.DoesNotExist:
         return HttpResponse(_('Module not found'))
 
-    return redirect(reverse('jet:update_module', kwargs={'pk': module.pk}))
+    return redirect(reverse('jet-dashboard:update_module', kwargs={'pk': module.pk}))
 
 dashboard.urls.register_urls([
     url(r'^google-analytics/grant/(?P<pk>\d+)/$', google_analytics_grant_view, name='google-analytics-grant'),

+ 22 - 12
jet/dashboard_modules/yandex_metrika.py → jet/dashboard/dashboard_modules/yandex_metrika.py

@@ -7,7 +7,7 @@ from django.forms import Widget
 from django.utils import formats
 from django.utils.html import format_html
 from django.utils.safestring import mark_safe
-from jet.modules import DashboardModule
+from jet.dashboard.modules import DashboardModule
 from django.utils.translation import ugettext_lazy as _
 from django.conf import settings
 
@@ -96,14 +96,24 @@ class AccessTokenWidget(Widget):
 
     def render(self, name, value, attrs=None):
         if value and len(value) > 0:
-            link = '<a href="%s">Revoke access</a>' % reverse('jet:yandex-metrika-revoke', kwargs={'pk': self.module.model.pk})
+            link = '<a href="%s">%s</a>' % (
+                reverse('jet-dashboard:yandex-metrika-revoke', kwargs={'pk': self.module.model.pk}),
+                _('Revoke access')
+            )
         else:
-            link = '<a href="%s">Grant access</a>' % reverse('jet:yandex-metrika-grant', kwargs={'pk': self.module.model.pk})
+            link = '<a href="%s">%s</a>' % (
+                reverse('jet-dashboard:yandex-metrika-grant', kwargs={'pk': self.module.model.pk}),
+                _('Grant access')
+            )
+
+        if value is None:
+            value = ''
+
         return format_html('%s<input type="hidden" name="access_token" value="%s">' % (link, value))
 
 
 class YandexMetrikaSettingsForm(forms.Form):
-    access_token = forms.CharField(label=_('Token'), widget=AccessTokenWidget)
+    access_token = forms.CharField(label=_('Access'), widget=AccessTokenWidget)
     counter = forms.ChoiceField(label=_('Counter'))
     period = forms.ChoiceField(label=_('Statistics period'), choices=(
         (0, _('Today')),
@@ -120,7 +130,7 @@ class YandexMetrikaSettingsForm(forms.Form):
     def set_counter_choices(self, module):
         counters = module.counters()
         if counters is not None:
-            self.fields['counter'].choices = (('', _('-- none --')),)
+            self.fields['counter'].choices = (('', '-- %s --' % _('none')),)
             self.fields['counter'].choices.extend(map(lambda x: (x['id'], x['site']), counters))
         else:
             label = _('grant access first') if module.access_token is None else _('counters loading failed')
@@ -204,10 +214,10 @@ class YandexMetrikaBase(DashboardModule):
 
     def counter_attached(self):
         if self.access_token is None:
-            self.error = mark_safe(_('Please <a href="%s">attach Yandex account and choose Yandex Metrika counter</a> to start using widget') % reverse('jet:update_module', kwargs={'pk': self.model.pk}))
+            self.error = mark_safe(_('Please <a href="%s">attach Yandex account and choose Yandex Metrika counter</a> to start using widget') % reverse('jet-dashboard:update_module', kwargs={'pk': self.model.pk}))
             return False
         elif self.counter is None:
-            self.error = mark_safe(_('Please <a href="%s">select Yandex Metrika counter</a> to start using widget') % reverse('jet:update_module', kwargs={'pk': self.model.pk}))
+            self.error = mark_safe(_('Please <a href="%s">select Yandex Metrika counter</a> to start using widget') % reverse('jet-dashboard:update_module', kwargs={'pk': self.model.pk}))
             return False
         else:
             return True
@@ -223,7 +233,7 @@ class YandexMetrikaBase(DashboardModule):
             if exception is not None:
                 error = _('API request failed.')
                 if isinstance(exception, HTTPError) and exception.code == 403:
-                    error += _(' Try to <a href="%s">revoke and grant access</a> again') % reverse('jet:update_module', kwargs={'pk': self.model.pk})
+                    error += _(' Try to <a href="%s">revoke and grant access</a> again') % reverse('jet-dashboard:update_module', kwargs={'pk': self.model.pk})
                 self.error = mark_safe(error)
             else:
                 return result
@@ -231,7 +241,7 @@ class YandexMetrikaBase(DashboardModule):
 
 class YandexMetrikaVisitorsTotals(YandexMetrikaBase):
     title = _('Yandex Metrika visitors totals')
-    template = 'jet/dashboard/modules/yandex_metrika_visitors_totals.html'
+    template = 'jet.dashboard/modules/yandex_metrika_visitors_totals.html'
 
     def __init__(self, title=None, period=None, **kwargs):
         kwargs.update({'period': period})
@@ -251,14 +261,14 @@ class YandexMetrikaVisitorsTotals(YandexMetrikaBase):
 
 class YandexMetrikaVisitorsChart(YandexMetrikaBase):
     title = _('Yandex Metrika visitors chart')
-    template = 'jet/dashboard/modules/yandex_metrika_visitors_chart.html'
+    template = 'jet.dashboard/modules/yandex_metrika_visitors_chart.html'
     style = 'overflow-x: auto;'
     show = None
     group = None
     settings_form = YandexMetrikaChartSettingsForm
 
     class Media:
-        js = ('jet/vendor/chart.js/Chart.min.js', 'jet/dashboard_modules/yandex_metrika.js')
+        js = ('jet.dashboard/vendor/chart.js/Chart.min.js', 'jet.dashboard/dashboard_modules/yandex_metrika.js')
 
     def __init__(self, title=None, period=None, show=None, group=None, **kwargs):
         kwargs.update({'period': period, 'show': show, 'group': group})
@@ -290,7 +300,7 @@ class YandexMetrikaVisitorsChart(YandexMetrikaBase):
 
 class YandexMetrikaPeriodVisitors(YandexMetrikaBase):
     title = _('Yandex Metrika period visitors')
-    template = 'jet/dashboard/modules/yandex_metrika_period_visitors.html'
+    template = 'jet.dashboard/modules/yandex_metrika_period_visitors.html'
     group = None
     contrast = False
     settings_form = YandexMetrikaPeriodVisitorsSettingsForm

+ 5 - 5
jet/dashboard_modules/yandex_metrika_views.py → jet/dashboard/dashboard_modules/yandex_metrika_views.py

@@ -3,9 +3,9 @@ from django.contrib import messages
 from django.core.urlresolvers import reverse
 from django.http import HttpResponse
 from django.shortcuts import redirect
-from jet.dashboard_modules.yandex_metrika import YandexMetrikaClient
-from jet.models import UserDashboardModule
-from jet import dashboard
+from jet.dashboard.dashboard_modules.yandex_metrika import YandexMetrikaClient
+from jet.dashboard.models import UserDashboardModule
+from jet.dashboard import dashboard
 from django.utils.translation import ugettext_lazy as _
 
 
@@ -18,7 +18,7 @@ def yandex_metrika_revoke_view(request, pk):
     try:
         module = UserDashboardModule.objects.get(pk=pk)
         module.pop_settings(('access_token', 'expires_in', 'token_type', 'counter'))
-        return redirect(reverse('jet:update_module', kwargs={'pk': module.pk}))
+        return redirect(reverse('jet-dashboard:update_module', kwargs={'pk': module.pk}))
     except UserDashboardModule.DoesNotExist:
         return HttpResponse(_('Module not found'))
 
@@ -38,7 +38,7 @@ def yandex_metrika_callback_view(request):
         else:
             module.update_settings(result)
 
-        return redirect(reverse('jet:update_module', kwargs={'pk': module.pk}))
+        return redirect(reverse('jet-dashboard:update_module', kwargs={'pk': module.pk}))
     except KeyError:
         return HttpResponse(_('Bad arguments'))
     except UserDashboardModule.DoesNotExist:

+ 130 - 0
jet/dashboard/forms.py

@@ -0,0 +1,130 @@
+import json
+from django import forms
+from django.core.exceptions import ValidationError
+from jet.dashboard.models import UserDashboardModule
+from jet.dashboard.utils import get_current_dashboard
+
+
+class UpdateDashboardModulesForm(forms.Form):
+    app_label = forms.CharField(required=False)
+    modules = forms.CharField()
+    modules_objects = []
+
+    def __init__(self, request, *args, **kwargs):
+        self.request = request
+        super(UpdateDashboardModulesForm, self).__init__(*args, **kwargs)
+
+    def clean(self):
+        data = super(UpdateDashboardModulesForm, self).clean()
+
+        try:
+            modules = json.loads(data['modules'])
+
+            for module in modules:
+                db_module = UserDashboardModule.objects.get(
+                    user=self.request.user.pk,
+                    app_label=data['app_label'] if data['app_label'] else None,
+                    pk=module['id']
+                )
+
+                column = module['column']
+                order = module['order']
+
+                if db_module.column != column or db_module.order != order:
+                    db_module.column = column
+                    db_module.order = order
+
+                    self.modules_objects.append(db_module)
+        except Exception:
+            raise ValidationError('error')
+
+        return data
+
+    def save(self):
+        for module in self.modules_objects:
+            module.save()
+
+
+class AddUserDashboardModuleForm(forms.ModelForm):
+    type = forms.CharField()
+    module = forms.IntegerField()
+    module_cls = None
+
+    def __init__(self, request, *args, **kwargs):
+        self.request = request
+        super(AddUserDashboardModuleForm, self).__init__(*args, **kwargs)
+
+    class Meta:
+        model = UserDashboardModule
+        fields = ['app_label']
+
+    def clean_app_label(self):
+        data = self.cleaned_data['app_label']
+        return data if data != '' else None
+
+    def clean(self):
+        data = super(AddUserDashboardModuleForm, self).clean()
+
+        index_dashboard_cls = get_current_dashboard('app_index' if data['app_label'] else 'index')
+        index_dashboard = index_dashboard_cls({'request': self.request}, app_label=data['app_label'])
+
+        if data['type'] == 'children':
+            module = index_dashboard.children[data['module']]
+        elif data['type'] == 'available_children':
+            module = index_dashboard.available_children[data['module']]()
+        else:
+            raise ValidationError('error')
+
+        self.module_cls = module
+        return data
+
+    def save(self, commit=True):
+        self.instance.title = self.module_cls.title
+        self.instance.module = self.module_cls.fullname()
+        self.instance.user = self.request.user.pk
+        self.instance.column = 0
+        self.instance.order = -1
+        self.instance.settings = self.module_cls.dump_settings()
+        self.instance.children = self.module_cls.dump_children()
+
+        return super(AddUserDashboardModuleForm, self).save(commit)
+
+
+class UpdateDashboardModuleCollapseForm(forms.ModelForm):
+    def __init__(self, request, *args, **kwargs):
+        self.request = request
+        super(UpdateDashboardModuleCollapseForm, self).__init__(*args, **kwargs)
+
+    class Meta:
+        model = UserDashboardModule
+        fields = ['collapsed']
+
+    def clean(self):
+        data = super(UpdateDashboardModuleCollapseForm, self).clean()
+
+        if self.instance.user != self.request.user.pk:
+            raise ValidationError('error')
+
+        return data
+
+
+class RemoveDashboardModuleForm(forms.ModelForm):
+    def __init__(self, request, *args, **kwargs):
+        self.request = request
+        super(RemoveDashboardModuleForm, self).__init__(*args, **kwargs)
+
+    class Meta:
+        model = UserDashboardModule
+        fields = []
+
+    def clean(self):
+        cleaned_data = super(RemoveDashboardModuleForm, self).clean()
+
+        if self.instance.user != self.request.user.pk:
+            raise ValidationError('error')
+
+        return cleaned_data
+
+    def save(self, commit=True):
+        if commit:
+            self.instance.delete()

+ 33 - 0
jet/dashboard/migrations/0001_initial.py

@@ -0,0 +1,33 @@
+# -*- coding: utf-8 -*-
+from __future__ import unicode_literals
+
+from django.db import models, migrations
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+    ]
+
+    operations = [
+        migrations.CreateModel(
+            name='UserDashboardModule',
+            fields=[
+                ('id', models.AutoField(verbose_name='ID', primary_key=True, serialize=False, auto_created=True)),
+                ('title', models.CharField(verbose_name='Title', max_length=255)),
+                ('module', models.CharField(verbose_name='module', max_length=255)),
+                ('app_label', models.CharField(verbose_name='application name', max_length=255, blank=True, null=True)),
+                ('user', models.PositiveIntegerField(verbose_name='user')),
+                ('column', models.PositiveIntegerField(verbose_name='column')),
+                ('order', models.IntegerField(verbose_name='order')),
+                ('settings', models.TextField(verbose_name='settings', blank=True, default='')),
+                ('children', models.TextField(verbose_name='children', blank=True, default='')),
+                ('collapsed', models.BooleanField(verbose_name='collapsed', default=False)),
+            ],
+            options={
+                'verbose_name': 'user dashboard module',
+                'verbose_name_plural': 'user dashboard modules',
+                'ordering': ('column', 'order'),
+            },
+        ),
+    ]

+ 0 - 0
jet/dashboard/migrations/__init__.py


+ 57 - 0
jet/dashboard/models.py

@@ -0,0 +1,57 @@
+from importlib import import_module
+import json
+from django.db import models
+from django.utils.encoding import python_2_unicode_compatible
+from django.utils.translation import ugettext_lazy as _
+from jet.utils import LazyDateTimeEncoder
+
+
+@python_2_unicode_compatible
+class UserDashboardModule(models.Model):
+    title = models.CharField(verbose_name=_('Title'), max_length=255)
+    module = models.CharField(verbose_name=_('module'), max_length=255)
+    app_label = models.CharField(verbose_name=_('application name'), max_length=255, null=True, blank=True)
+    user = models.PositiveIntegerField(verbose_name=_('user'))
+    column = models.PositiveIntegerField(verbose_name=_('column'))
+    order = models.IntegerField(verbose_name=_('order'))
+    settings = models.TextField(verbose_name=_('settings'), default='', blank=True)
+    children = models.TextField(verbose_name=_('children'), default='', blank=True)
+    collapsed = models.BooleanField(verbose_name=_('collapsed'), default=False)
+
+    class Meta:
+        verbose_name = _('user dashboard module')
+        verbose_name_plural = _('user dashboard modules')
+        ordering = ('column', 'order')
+
+    def __str__(self):
+        return self.module
+
+    def load_module(self):
+        try:
+            package, module_name = self.module.rsplit('.', 1)
+            package = import_module(package)
+            module = getattr(package, module_name)
+
+            return module
+        except AttributeError:
+            return None
+
+    def pop_settings(self, pop_settings):
+        settings = json.loads(self.settings)
+
+        for setting in pop_settings:
+            if setting in settings:
+                settings.pop(setting)
+
+        self.settings = json.dumps(settings, cls=LazyDateTimeEncoder)
+        self.save()
+
+    def update_settings(self, update_settings):
+        settings = json.loads(self.settings)
+
+        settings.update(update_settings)
+
+        self.settings = json.dumps(settings, cls=LazyDateTimeEncoder)
+        self.save()
+
+

+ 6 - 6
jet/modules.py → jet/dashboard/modules.py

@@ -9,7 +9,7 @@ import datetime
 
 
 class DashboardModule(object):
-    template = 'jet/dashboard/module.html'
+    template = 'jet.dashboard/module.html'
     enabled = True
     draggable = True
     collapsible = True
@@ -123,7 +123,7 @@ class LinkListSettingsForm(forms.Form):
 
 class LinkList(DashboardModule):
     title = _('Links')
-    template = 'jet/dashboard/modules/link_list.html'
+    template = 'jet.dashboard/modules/link_list.html'
     layout = 'stacked'
     settings_form = LinkListSettingsForm
     child_form = LinkListItemForm
@@ -158,7 +158,7 @@ class LinkList(DashboardModule):
 
 class AppList(DashboardModule):
     title = _('Applications')
-    template = 'jet/dashboard/modules/app_list.html'
+    template = 'jet.dashboard/modules/app_list.html'
     models = None
     exclude = None
     hide_empty = True
@@ -199,7 +199,7 @@ class AppList(DashboardModule):
 
 class ModelList(DashboardModule):
     title = _('Models')
-    template = 'jet/dashboard/modules/model_list.html'
+    template = 'jet.dashboard/modules/model_list.html'
     models = None
     exclude = None
     hide_empty = True
@@ -240,7 +240,7 @@ class RecentActionsSettingsForm(forms.Form):
 
 class RecentActions(DashboardModule):
     title = _('Recent Actions')
-    template = 'jet/dashboard/modules/recent_actions.html'
+    template = 'jet.dashboard/modules/recent_actions.html'
     limit = 10
     include_list = None
     exclude_list = None
@@ -312,7 +312,7 @@ class FeedSettingsForm(forms.Form):
 
 class Feed(DashboardModule):
     title = _('RSS Feed')
-    template = 'jet/dashboard/modules/feed.html'
+    template = 'jet.dashboard/modules/feed.html'
     feed_url = None
     limit = None
     settings_form = FeedSettingsForm

+ 5 - 0
jet/dashboard/settings.py

@@ -0,0 +1,5 @@
+from django.conf import settings
+
+# Dashboard
+JET_INDEX_DASHBOARD = getattr(settings, 'JET_INDEX_DASHBOARD', 'jet.dashboard.dashboard.DefaultIndexDashboard')
+JET_APP_INDEX_DASHBOARD = getattr(settings, 'JET_APP_INDEX_DASHBOARD', 'jet.dashboard.dashboard.DefaultAppIndexDashboard')

+ 0 - 0
jet/static/jet/dashboard_modules/google_analytics.js → jet/dashboard/static/jet.dashboard/dashboard_modules/google_analytics.js


+ 0 - 0
jet/static/jet/dashboard_modules/yandex_metrika.js → jet/dashboard/static/jet.dashboard/dashboard_modules/yandex_metrika.js


+ 0 - 0
jet/static/jet/vendor/chart.js/CONTRIBUTING.md → jet/dashboard/static/jet.dashboard/vendor/chart.js/CONTRIBUTING.md


+ 0 - 0
jet/static/jet/vendor/chart.js/Chart.js → jet/dashboard/static/jet.dashboard/vendor/chart.js/Chart.js


+ 0 - 0
jet/static/jet/vendor/chart.js/Chart.min.js → jet/dashboard/static/jet.dashboard/vendor/chart.js/Chart.min.js


+ 0 - 0
jet/static/jet/vendor/chart.js/LICENSE.md → jet/dashboard/static/jet.dashboard/vendor/chart.js/LICENSE.md


+ 0 - 0
jet/static/jet/vendor/chart.js/README.md → jet/dashboard/static/jet.dashboard/vendor/chart.js/README.md


+ 2 - 2
jet/templates/admin/app_index.html → jet/dashboard/templates/admin/app_index.html

@@ -1,5 +1,5 @@
 {% extends "admin/base_site.html" %}
-{% load i18n static jet_tags %}
+{% load i18n static jet_dashboard_tags %}
 
 {% block html %}
     {% get_dashboard 'app_index' as dashboard %}
@@ -24,7 +24,7 @@
 
 {% block coltype %}colMS{% endblock %}
 
-{% block bodyclass %}{{ block.super }} app-{{ app_label }} dashboard{% endblock %}
+{% block bodyclass %}{{ block.super }} app-{{ app_label }}{% endblock %}
 
 {% if not is_popup %}
     {% block breadcrumbs %}

+ 35 - 0
jet/dashboard/templates/admin/index.html

@@ -0,0 +1,35 @@
+{% extends "admin/base_site.html" %}
+{% load i18n admin_static jet_dashboard_tags static %}
+
+{% block html %}
+    {% get_dashboard 'index' as dashboard %}
+    {{ block.super }}
+{% endblock %}
+
+{% block extrastyle %}
+    {{ block.super }}
+    <link rel="stylesheet" type="text/css" href="{% static "admin/css/dashboard.css" %}" />
+
+    {% for css in dashboard.media.css %}
+        <link href="{% static css %}" rel="stylesheet" />
+    {% endfor %}
+{% endblock %}
+
+{% block extrahead %}
+    {{ block.super }}
+    {% for js in dashboard.media.js %}
+        <script src="{% static js %}"></script>
+    {% endfor %}
+{% endblock %}
+
+{% block coltype %}colMS{% endblock %}
+
+{% block sidebar %}{% endblock %}
+
+{% block top-right %}
+    {{ dashboard.render_tools }}
+{% endblock %}
+
+{% block content %}
+    {{ dashboard.render }}
+{% endblock %}

+ 4 - 4
jet/templates/jet/dashboard/dashboard.html → jet/dashboard/templates/jet.dashboard/dashboard.html

@@ -6,7 +6,7 @@
             <div class="dashboard-column{% if forloop.first %} first{% endif %}">
                 {% for module in modules %}
                     {% if module.model.column == i %}
-                        {% include "jet/dashboard/module.html" with module=module %}
+                        {% include "jet.dashboard/module.html" with module=module %}
                     {% endif %}
                 {% endfor %}
             </div>
@@ -18,19 +18,19 @@
     <p>{% trans "Are you sure want to delete this widget?" %}</p>
 </div>
 
-<form action="{% url "jet:update_dashboard_modules" %}" method="POST" id="update-dashboard-modules-form">
+<form action="{% url "jet-dashboard:update_dashboard_modules" %}" method="POST" id="update-dashboard-modules-form">
     {% csrf_token %}
     <input type="hidden" name="app_label" value="{% if app_label %}{{ app_label }}{% endif %}">
     <input type="hidden" name="modules">
 </form>
 
-<form action="{% url "jet:update_dashboard_module_collapse" %}" method="POST" id="update-dashboard-module-collapse-form">
+<form action="{% url "jet-dashboard:update_dashboard_module_collapse" %}" method="POST" id="update-dashboard-module-collapse-form">
     {% csrf_token %}
     <input type="hidden" name="id">
     <input type="hidden" name="collapsed">
 </form>
 
-<form action="{% url "jet:remove_dashboard_module" %}" method="POST" id="remove-dashboard-module-form">
+<form action="{% url "jet-dashboard:remove_dashboard_module" %}" method="POST" id="remove-dashboard-module-form">
     {% csrf_token %}
     <input type="hidden" name="id">
 </form>

+ 1 - 1
jet/templates/jet/dashboard/dashboard_tools.html → jet/dashboard/templates/jet.dashboard/dashboard_tools.html

@@ -1,7 +1,7 @@
 {% load i18n %}
 
 <div class="background-form">
-    <form action="{% url "jet:add_user_dashboard_module" %}" method="POST" id="add-dashboard-module-form">
+    <form action="{% url "jet-dashboard:add_user_dashboard_module" %}" method="POST" id="add-dashboard-module-form">
         {% csrf_token %}
         <select class="add-dashboard" name="module">
             <option>{% trans "widgets" %}</option>

+ 2 - 2
jet/templates/jet/dashboard/module.html → jet/dashboard/templates/jet.dashboard/module.html

@@ -1,6 +1,6 @@
 {% load i18n %}
 
-<div class="dashboard-item{% if module.collapsible %} collapsible{% endif %}{% if module.model.collapsed %} collapsed{% endif %}{% if module.deletable %} deletable{% endif %}{% if module.ajax_load %} ajax{% endif %}"{% if module.ajax_load %} data-ajax-url="{% url "jet:load_dashboard_module" pk=module.model.id %}"{% endif %} data-module-id="{{ module.model.id }}">
+<div class="dashboard-item{% if module.collapsible %} collapsible{% endif %}{% if module.model.collapsed %} collapsed{% endif %}{% if module.deletable %} deletable{% endif %}{% if module.ajax_load %} ajax{% endif %}"{% if module.ajax_load %} data-ajax-url="{% url "jet-dashboard:load_dashboard_module" pk=module.model.id %}"{% endif %} data-module-id="{{ module.model.id }}">
     <div class="dashboard-item-header">
         <span class="dashboard-item-header-drag icon-grid"></span>
         <span class="dashboard-item-header-title">
@@ -16,7 +16,7 @@
             {% endif %}
 
             <span class="dashboard-item-header-buttons">
-                <a href="{% url "jet:update_module" pk=module.model.id %}" title="{% trans "Change" %}"><span class="icon-edit"></span></a>
+                <a href="{% url "jet-dashboard:update_module" pk=module.model.id %}" title="{% trans "Change" %}"><span class="icon-edit"></span></a>
 
                 {% if module.deletable %}
                     <a href="#" title="{% trans "Delete" %}" class="dashboard-item-remove"><span class="icon-cross"></span></a>

+ 0 - 0
jet/templates/jet/dashboard/modules/app_list.html → jet/dashboard/templates/jet.dashboard/modules/app_list.html


+ 0 - 0
jet/templates/jet/dashboard/modules/feed.html → jet/dashboard/templates/jet.dashboard/modules/feed.html


+ 0 - 0
jet/templates/jet/dashboard/modules/google_analytics_period_visitors.html → jet/dashboard/templates/jet.dashboard/modules/google_analytics_period_visitors.html


+ 0 - 0
jet/templates/jet/dashboard/modules/google_analytics_visitors_chart.html → jet/dashboard/templates/jet.dashboard/modules/google_analytics_visitors_chart.html


+ 0 - 0
jet/templates/jet/dashboard/modules/google_analytics_visitors_totals.html → jet/dashboard/templates/jet.dashboard/modules/google_analytics_visitors_totals.html


+ 0 - 0
jet/templates/jet/dashboard/modules/link_list.html → jet/dashboard/templates/jet.dashboard/modules/link_list.html


+ 0 - 0
jet/templates/jet/dashboard/modules/model_list.html → jet/dashboard/templates/jet.dashboard/modules/model_list.html


+ 0 - 0
jet/templates/jet/dashboard/modules/recent_actions.html → jet/dashboard/templates/jet.dashboard/modules/recent_actions.html


+ 0 - 0
jet/templates/jet/dashboard/modules/yandex_metrika_period_visitors.html → jet/dashboard/templates/jet.dashboard/modules/yandex_metrika_period_visitors.html


+ 0 - 0
jet/templates/jet/dashboard/modules/yandex_metrika_visitors_chart.html → jet/dashboard/templates/jet.dashboard/modules/yandex_metrika_visitors_chart.html


+ 0 - 0
jet/templates/jet/dashboard/modules/yandex_metrika_visitors_totals.html → jet/dashboard/templates/jet.dashboard/modules/yandex_metrika_visitors_totals.html


+ 4 - 4
jet/templates/jet/dashboard/update_module.html → jet/dashboard/templates/jet.dashboard/update_module.html

@@ -58,10 +58,10 @@
                     </fieldset>
                 {% endif %}
 
-                {% include "jet/dashboard/update_module_fieldset.html" with form=form %}
+                {% include "jet.dashboard/update_module_fieldset.html" with form=form %}
 
                 {% if settings_form %}
-                    {% include "jet/dashboard/update_module_fieldset.html" with form=settings_form %}
+                    {% include "jet.dashboard/update_module_fieldset.html" with form=settings_form %}
                 {% endif %}
             </div>
 
@@ -104,13 +104,13 @@
                                 {% for form in children_formset %}
                                     <div class="stacked {% if forloop.first %}selected {% endif %}inline-related {% if forloop.last %} last-related{% endif %}" id="{{ children_formset.prefix }}-{{ forloop.counter0 }}">
                                         {% if form.non_field_errors %}{{ form.non_field_errors }}{% endif %}
-                                        {% include "jet/dashboard/update_module_fieldset.html" with form=form %}
+                                        {% include "jet.dashboard/update_module_fieldset.html" with form=form %}
                                     </div>
                                 {% endfor %}
                                 {% with form=children_formset.empty_form %}
                                     <div class="stacked inline-related empty-form last-related" id="{{ children_formset.prefix }}-empty">
                                         {% if form.non_field_errors %}{{ form.non_field_errors }}{% endif %}
-                                        {% include "jet/dashboard/update_module_fieldset.html" with form=form %}
+                                        {% include "jet.dashboard/update_module_fieldset.html" with form=form %}
                                     </div>
                                 {% endwith %}
                             </div>

+ 0 - 0
jet/templates/jet/dashboard/update_module_fieldset.html → jet/dashboard/templates/jet.dashboard/update_module_fieldset.html


+ 0 - 0
jet/dashboard/templatetags/__init__.py


+ 12 - 0
jet/dashboard/templatetags/jet_dashboard_tags.py

@@ -0,0 +1,12 @@
+from __future__ import unicode_literals
+from django import template
+from jet.dashboard.utils import get_current_dashboard
+
+register = template.Library()
+
+
+@register.assignment_tag(takes_context=True)
+def get_dashboard(context, location):
+    dashboard_cls = get_current_dashboard(location)
+    dashboard = dashboard_cls(context)
+    return dashboard

+ 53 - 0
jet/dashboard/urls.py

@@ -0,0 +1,53 @@
+from django.conf.urls import patterns, url
+from django.views.i18n import javascript_catalog
+from jet.dashboard import dashboard
+from jet.dashboard.views import update_dashboard_modules_view, add_user_dashboard_module_view, \
+    update_dashboard_module_collapse_view, remove_dashboard_module_view, UpdateDashboardModuleView, \
+    load_dashboard_module_view, reset_dashboard_view
+
+urlpatterns = patterns(
+    '',
+    url(
+        r'^module/(?P<pk>\d+)/$',
+        UpdateDashboardModuleView.as_view(),
+        name='update_module'
+    ),
+    url(
+        r'^update_dashboard_modules/$',
+        update_dashboard_modules_view,
+        name='update_dashboard_modules'
+    ),
+    url(
+        r'^add_user_dashboard_module/$',
+        add_user_dashboard_module_view,
+        name='add_user_dashboard_module'
+    ),
+    url(
+        r'^update_dashboard_module_collapse/$',
+        update_dashboard_module_collapse_view,
+        name='update_dashboard_module_collapse'
+    ),
+    url(
+        r'^remove_dashboard_module/$',
+        remove_dashboard_module_view,
+        name='remove_dashboard_module'
+    ),
+    url(
+        r'^load_dashboard_module/(?P<pk>\d+)/$',
+        load_dashboard_module_view,
+        name='load_dashboard_module'
+    ),
+    url(
+        r'^reset_dashboard/((?P<app_label>[^/]+)/)?$',
+        reset_dashboard_view,
+        name='reset_dashboard'
+    ),
+    url(
+        r'^jsi18n/$',
+        javascript_catalog,
+        {'packages': ('jet',)},
+        name='jsi18n'
+    ),
+)
+
+urlpatterns += dashboard.urls.get_urls()

+ 17 - 0
jet/dashboard/utils.py

@@ -0,0 +1,17 @@
+from importlib import import_module
+from jet.dashboard import settings
+
+
+def get_current_dashboard(location):
+    if location == 'index':
+        path = settings.JET_INDEX_DASHBOARD
+    elif location == 'app_index':
+        path = settings.JET_APP_INDEX_DASHBOARD
+    else:
+        raise ValueError('Unknown dashboard location: %s' % location)
+
+    module, cls = path.rsplit('.', 1)
+    module = import_module(module)
+    index_dashboard_cls = getattr(module, cls)
+
+    return index_dashboard_cls

+ 223 - 0
jet/dashboard/views.py

@@ -0,0 +1,223 @@
+from django.contrib import messages
+from django.core.urlresolvers import reverse
+from django.forms.formsets import formset_factory
+from django.shortcuts import redirect
+from django.views.decorators.http import require_POST, require_GET
+from jet.dashboard.forms import UpdateDashboardModulesForm, AddUserDashboardModuleForm, \
+    UpdateDashboardModuleCollapseForm, RemoveDashboardModuleForm
+from jet.dashboard.models import UserDashboardModule
+from jet.utils import JsonResponse, get_app_list, SuccessMessageMixin
+from django.views.generic import UpdateView
+from django.utils.translation import ugettext_lazy as _
+
+
+class UpdateDashboardModuleView(SuccessMessageMixin, UpdateView):
+    model = UserDashboardModule
+    fields = ('title',)
+    template_name = 'jet.dashboard/update_module.html'
+    success_message = _('Widget was successfully updated')
+    object = None
+    module = None
+
+    def get_success_url(self):
+        if self.object.app_label:
+            return reverse('admin:app_list', kwargs={'app_label': self.object.app_label})
+        else:
+            return reverse('admin:index')
+
+    def get_module(self):
+        object = self.object if getattr(self, 'object', None) is not None else self.get_object()
+        return object.load_module()
+
+    def get_settings_form_kwargs(self):
+        kwargs = {
+            'initial': self.module.settings
+        }
+
+        if self.request.method in ('POST', 'PUT'):
+            kwargs.update({
+                'data': self.request.POST,
+                'files': self.request.FILES,
+            })
+        return kwargs
+
+    def get_settings_form(self):
+        if self.module.settings_form:
+            form = self.module.settings_form(**self.get_settings_form_kwargs())
+            if hasattr(form, 'set_module'):
+                form.set_module(self.module)
+            return form
+
+    def get_children_formset_kwargs(self):
+        kwargs = {
+            'initial': self.module.children,
+            'prefix': 'children',
+        }
+
+        if self.request.method in ('POST', 'PUT'):
+            kwargs.update({
+                'data': self.request.POST,
+                'files': self.request.FILES,
+            })
+        return kwargs
+
+    def get_children_formset(self):
+        if self.module.child_form:
+            return formset_factory(self.module.child_form, can_delete=True, extra=1)(**self.get_children_formset_kwargs())
+
+    def clean_children_data(self, children):
+        children = list(filter(
+            lambda item: isinstance(item, dict) and item and item.get('DELETE') is not True,
+            children
+        ))
+        for item in children:
+            item.pop('DELETE')
+        return children
+
+    def get_current_app(self):
+        app_list = get_app_list({'request': self.request})
+
+        for app in app_list:
+            if app.get('app_label', app.get('name')) == self.object.app_label:
+                return app
+
+    def get_context_data(self, **kwargs):
+        data = super(UpdateDashboardModuleView, self).get_context_data(**kwargs)
+        data['title'] = _('Change')
+        data['module'] = self.module
+        data['settings_form'] = self.get_settings_form()
+        data['children_formset'] = self.get_children_formset()
+        data['child_name'] = self.module.child_name if self.module.child_name else _('Items')
+        data['child_name_plural'] = self.module.child_name_plural if self.module.child_name_plural else _('Items')
+        data['app'] = self.get_current_app()
+        return data
+
+    def dispatch(self, request, *args, **kwargs):
+        self.object = self.get_object()
+        self.module = self.get_module()(model=self.object)
+        return super(UpdateDashboardModuleView, self).dispatch(request, *args, **kwargs)
+
+    def post(self, request, *args, **kwargs):
+        settings_form = self.get_settings_form()
+        children_formset = self.get_children_formset()
+
+        data = request.POST.copy()
+
+        if settings_form:
+            if settings_form.is_valid():
+                settings = settings_form.cleaned_data
+                data['settings'] = self.module.dump_settings(settings)
+            else:
+                return self.form_invalid(self.get_form(self.get_form_class()))
+
+        if children_formset:
+            if children_formset.is_valid():
+                self.module.children = self.clean_children_data(children_formset.cleaned_data)
+                data['children'] = self.module.dump_children()
+            else:
+                return self.form_invalid(self.get_form(self.get_form_class()))
+
+        request.POST = data
+
+        return super(UpdateDashboardModuleView, self).post(request, *args, **kwargs)
+
+    def form_valid(self, form):
+        if 'settings' in form.data:
+            form.instance.settings = form.data['settings']
+        if 'children' in form.data:
+            form.instance.children = form.data['children']
+        return super(UpdateDashboardModuleView, self).form_valid(form)
+
+
+@require_POST
+def update_dashboard_modules_view(request):
+    result = {'error': False}
+    form = UpdateDashboardModulesForm(request, request.POST)
+
+    if form.is_valid():
+        form.save()
+    else:
+        result['error'] = True
+
+    return JsonResponse(result)
+
+
+@require_POST
+def add_user_dashboard_module_view(request):
+    result = {'error': False}
+    form = AddUserDashboardModuleForm(request, request.POST)
+
+    if form.is_valid():
+        module = form.save()
+        result['id'] = module.pk
+        messages.success(request, _('Widget has been successfully added'))
+
+        if module.app_label:
+            result['success_url'] = reverse('admin:app_list', kwargs={'app_label': module.app_label})
+        else:
+            result['success_url'] = reverse('admin:index')
+    else:
+        result['error'] = True
+
+    return JsonResponse(result)
+
+
+@require_POST
+def update_dashboard_module_collapse_view(request):
+    result = {'error': False}
+
+    try:
+        instance = UserDashboardModule.objects.get(pk=request.POST.get('id'))
+        form = UpdateDashboardModuleCollapseForm(request, request.POST, instance=instance)
+
+        if form.is_valid():
+            module = form.save()
+            result['collapsed'] = module.collapsed
+        else:
+            result['error'] = True
+    except UserDashboardModule.DoesNotExist:
+        result['error'] = True
+
+    return JsonResponse(result)
+
+
+@require_POST
+def remove_dashboard_module_view(request):
+    result = {'error': False}
+
+    try:
+        instance = UserDashboardModule.objects.get(pk=request.POST.get('id'))
+        form = RemoveDashboardModuleForm(request, request.POST, instance=instance)
+
+        if form.is_valid():
+            form.save()
+        else:
+            result['error'] = True
+    except UserDashboardModule.DoesNotExist:
+        result['error'] = True
+
+    return JsonResponse(result)
+
+
+@require_GET
+def load_dashboard_module_view(request, pk):
+    result = {'error': False}
+
+    try:
+        instance = UserDashboardModule.objects.get(pk=pk)
+        module_cls = instance.load_module()
+        module = module_cls(model=instance, context={'request': request})
+        result['html'] = module.render()
+    except UserDashboardModule.DoesNotExist:
+        result['error'] = True
+
+    return JsonResponse(result)
+
+
+def reset_dashboard_view(request, app_label=None):
+    UserDashboardModule.objects.filter(user=request.user.pk, app_label=app_label).delete()
+    if app_label:
+        url = reverse('admin:app_list', kwargs={'app_label': app_label})
+    else:
+        url = reverse('admin:index')
+    return redirect(url)

+ 5 - 129
jet/forms.py

@@ -2,15 +2,16 @@ import json
 from django import forms
 from django.core.exceptions import ValidationError
 from django.db.models import Q
+import operator
+from jet.models import Bookmark, PinnedApplication
+from jet.utils import get_model_instance_label
+from functools import reduce
+
 try:
     from django.apps import apps
     get_model = apps.get_model
 except ImportError:
     from django.db.models.loading import get_model
-import operator
-from jet.models import Bookmark, PinnedApplication, UserDashboardModule
-from jet.utils import get_current_dashboard, get_model_instance_label
-from functools import reduce
 
 
 class AddBookmarkForm(forms.ModelForm):
@@ -83,131 +84,6 @@ class ToggleApplicationPinForm(forms.ModelForm):
                 return True
 
 
-class UpdateDashboardModulesForm(forms.Form):
-    app_label = forms.CharField(required=False)
-    modules = forms.CharField()
-    modules_objects = []
-
-    def __init__(self, request, *args, **kwargs):
-        self.request = request
-        super(UpdateDashboardModulesForm, self).__init__(*args, **kwargs)
-
-    def clean(self):
-        data = super(UpdateDashboardModulesForm, self).clean()
-
-        try:
-            modules = json.loads(data['modules'])
-
-            for module in modules:
-                db_module = UserDashboardModule.objects.get(
-                    user=self.request.user.pk,
-                    app_label=data['app_label'] if data['app_label'] else None,
-                    pk=module['id']
-                )
-
-                column = module['column']
-                order = module['order']
-
-                if db_module.column != column or db_module.order != order:
-                    db_module.column = column
-                    db_module.order = order
-
-                    self.modules_objects.append(db_module)
-        except Exception:
-            raise ValidationError('error')
-
-        return data
-
-    def save(self):
-        for module in self.modules_objects:
-            module.save()
-
-
-class AddUserDashboardModuleForm(forms.ModelForm):
-    type = forms.CharField()
-    module = forms.IntegerField()
-    module_cls = None
-
-    def __init__(self, request, *args, **kwargs):
-        self.request = request
-        super(AddUserDashboardModuleForm, self).__init__(*args, **kwargs)
-
-    class Meta:
-        model = UserDashboardModule
-        fields = ['app_label']
-
-    def clean_app_label(self):
-        data = self.cleaned_data['app_label']
-        return data if data != '' else None
-
-    def clean(self):
-        data = super(AddUserDashboardModuleForm, self).clean()
-
-        index_dashboard_cls = get_current_dashboard('app_index' if data['app_label'] else 'index')
-        index_dashboard = index_dashboard_cls({'request': self.request}, app_label=data['app_label'])
-
-        if data['type'] == 'children':
-            module = index_dashboard.children[data['module']]
-        elif data['type'] == 'available_children':
-            module = index_dashboard.available_children[data['module']]()
-        else:
-            raise ValidationError('error')
-
-        self.module_cls = module
-        return data
-
-    def save(self, commit=True):
-        self.instance.title = self.module_cls.title
-        self.instance.module = self.module_cls.fullname()
-        self.instance.user = self.request.user.pk
-        self.instance.column = 0
-        self.instance.order = -1
-        self.instance.settings = self.module_cls.dump_settings()
-        self.instance.children = self.module_cls.dump_children()
-
-        return super(AddUserDashboardModuleForm, self).save(commit)
-
-
-class UpdateDashboardModuleCollapseForm(forms.ModelForm):
-    def __init__(self, request, *args, **kwargs):
-        self.request = request
-        super(UpdateDashboardModuleCollapseForm, self).__init__(*args, **kwargs)
-
-    class Meta:
-        model = UserDashboardModule
-        fields = ['collapsed']
-
-    def clean(self):
-        data = super(UpdateDashboardModuleCollapseForm, self).clean()
-
-        if self.instance.user != self.request.user.pk:
-            raise ValidationError('error')
-
-        return data
-
-
-class RemoveDashboardModuleForm(forms.ModelForm):
-    def __init__(self, request, *args, **kwargs):
-        self.request = request
-        super(RemoveDashboardModuleForm, self).__init__(*args, **kwargs)
-
-    class Meta:
-        model = UserDashboardModule
-        fields = []
-
-    def clean(self):
-        cleaned_data = super(RemoveDashboardModuleForm, self).clean()
-
-        if self.instance.user != self.request.user.pk:
-            raise ValidationError('error')
-
-        return cleaned_data
-
-    def save(self, commit=True):
-        if commit:
-            self.instance.delete()
-
-
 class ModelLookupForm(forms.Form):
     app_label = forms.CharField()
     model = forms.CharField()

BIN
jet/locale/en/LC_MESSAGES/django.mo


+ 476 - 199
jet/locale/en/LC_MESSAGES/django.po

@@ -6,7 +6,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: PACKAGE VERSION\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2015-08-07 13:25+0000\n"
+"POT-Creation-Date: 2015-09-07 13:42+0000\n"
 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
 "Language-Team: LANGUAGE <LL@li.org>\n"
@@ -15,178 +15,546 @@ msgstr ""
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
 
-#: dashboard.py:157
+#: dashboard/dashboard.py:159
 msgid "Quick links"
 msgstr ""
 
-#: dashboard.py:163
+#: dashboard/dashboard.py:165
 msgid "Return to site"
 msgstr ""
 
-#: dashboard.py:164 templates/admin/base.html:85
+#: dashboard/dashboard.py:166 templates/admin/base.html:77
 msgid "Change password"
 msgstr ""
 
-#: dashboard.py:166 templates/admin/base.html:89
+#: dashboard/dashboard.py:168 templates/admin/base.html:81
 msgid "Log out"
 msgstr ""
 
-#: dashboard.py:174 modules.py:158 templates/admin/sidebar.html:23
+#: dashboard/dashboard.py:176 dashboard/modules.py:160
+#: templates/admin/base.html:157 templates/admin/index.html:14
 msgid "Applications"
 msgstr ""
 
-#: dashboard.py:182
+#: dashboard/dashboard.py:184
 msgid "Administration"
 msgstr ""
 
-#: dashboard.py:190 modules.py:238
+#: dashboard/dashboard.py:192 dashboard/modules.py:242
+#: templates/admin/index.html:68
 msgid "Recent Actions"
 msgstr ""
 
-#: dashboard.py:198
+#: dashboard/dashboard.py:200
 msgid "Latest Django News"
 msgstr ""
 
-#: dashboard.py:207
+#: dashboard/dashboard.py:209
 msgid "Support"
 msgstr ""
 
-#: dashboard.py:210
+#: dashboard/dashboard.py:212
 msgid "Django documentation"
 msgstr ""
 
-#: dashboard.py:215
+#: dashboard/dashboard.py:217
 msgid "Django \"django-users\" mailing list"
 msgstr ""
 
-#: dashboard.py:220
+#: dashboard/dashboard.py:222
 msgid "Django irc channel"
 msgstr ""
 
-#: dashboard.py:235
+#: dashboard/dashboard.py:237
 msgid "Application models"
 msgstr ""
 
-#: models.py:8 modules.py:113 templates/admin/sidebar.html:57
-msgid "URL"
+#: dashboard/dashboard_modules/google_analytics.py:143
+#: dashboard/dashboard_modules/yandex_metrika.py:101
+msgid "Revoke access"
 msgstr ""
 
-#: models.py:9
-msgid "title"
+#: dashboard/dashboard_modules/google_analytics.py:148
+#: dashboard/dashboard_modules/yandex_metrika.py:106
+msgid "Grant access"
 msgstr ""
 
-#: models.py:10 models.py:24 models.py:40
-msgid "user"
+#: dashboard/dashboard_modules/google_analytics.py:161
+#: dashboard/dashboard_modules/yandex_metrika.py:113
+msgid "Access"
 msgstr ""
 
-#: models.py:11 models.py:25
-msgid "date created"
+#: dashboard/dashboard_modules/google_analytics.py:162
+#: dashboard/dashboard_modules/yandex_metrika.py:114
+msgid "Counter"
 msgstr ""
 
-#: models.py:14
-msgid "bookmark"
+#: dashboard/dashboard_modules/google_analytics.py:163
+#: dashboard/dashboard_modules/yandex_metrika.py:115
+msgid "Statistics period"
 msgstr ""
 
-#: models.py:15 templates/admin/sidebar.html:70
-msgid "bookmarks"
+#: dashboard/dashboard_modules/google_analytics.py:164
+#: dashboard/dashboard_modules/yandex_metrika.py:116
+msgid "Today"
 msgstr ""
 
-#: models.py:23 models.py:39
-msgid "application name"
+#: dashboard/dashboard_modules/google_analytics.py:165
+#: dashboard/dashboard_modules/yandex_metrika.py:117
+msgid "Last week"
 msgstr ""
 
-#: models.py:28
-msgid "pinned application"
+#: dashboard/dashboard_modules/google_analytics.py:166
+#: dashboard/dashboard_modules/yandex_metrika.py:118
+msgid "Last month"
 msgstr ""
 
-#: models.py:29
-msgid "pinned applications"
+#: dashboard/dashboard_modules/google_analytics.py:167
+#: dashboard/dashboard_modules/yandex_metrika.py:119
+msgid "Last quarter"
+msgstr ""
+
+#: dashboard/dashboard_modules/google_analytics.py:168
+#: dashboard/dashboard_modules/yandex_metrika.py:120
+msgid "Last year"
+msgstr ""
+
+#: dashboard/dashboard_modules/google_analytics.py:178
+#: dashboard/dashboard_modules/yandex_metrika.py:130
+msgid "none"
+msgstr ""
+
+#: dashboard/dashboard_modules/google_analytics.py:181
+#: dashboard/dashboard_modules/yandex_metrika.py:133
+msgid "grant access first"
+msgstr ""
+
+#: dashboard/dashboard_modules/google_analytics.py:181
+#: dashboard/dashboard_modules/yandex_metrika.py:133
+msgid "counters loading failed"
+msgstr ""
+
+#: dashboard/dashboard_modules/google_analytics.py:186
+#: dashboard/dashboard_modules/yandex_metrika.py:138
+msgid "Show"
+msgstr ""
+
+#: dashboard/dashboard_modules/google_analytics.py:187
+#: dashboard/templates/jet.dashboard/modules/google_analytics_period_visitors.html:15
+msgid "Users"
+msgstr ""
+
+#: dashboard/dashboard_modules/google_analytics.py:188
+#: dashboard/templates/jet.dashboard/modules/google_analytics_period_visitors.html:16
+msgid "Sessions"
+msgstr ""
+
+#: dashboard/dashboard_modules/google_analytics.py:189
+#: dashboard/dashboard_modules/yandex_metrika.py:141
+#: dashboard/templates/jet.dashboard/modules/google_analytics_period_visitors.html:17
+#: dashboard/templates/jet.dashboard/modules/yandex_metrika_period_visitors.html:17
+msgid "Views"
+msgstr ""
+
+#: dashboard/dashboard_modules/google_analytics.py:191
+#: dashboard/dashboard_modules/google_analytics.py:199
+#: dashboard/dashboard_modules/yandex_metrika.py:143
+#: dashboard/dashboard_modules/yandex_metrika.py:151
+msgid "Group"
+msgstr ""
+
+#: dashboard/dashboard_modules/google_analytics.py:192
+#: dashboard/dashboard_modules/google_analytics.py:200
+#: dashboard/dashboard_modules/yandex_metrika.py:144
+#: dashboard/dashboard_modules/yandex_metrika.py:152
+msgid "By day"
+msgstr ""
+
+#: dashboard/dashboard_modules/google_analytics.py:193
+#: dashboard/dashboard_modules/google_analytics.py:201
+#: dashboard/dashboard_modules/yandex_metrika.py:145
+#: dashboard/dashboard_modules/yandex_metrika.py:153
+msgid "By week"
+msgstr ""
+
+#: dashboard/dashboard_modules/google_analytics.py:194
+#: dashboard/dashboard_modules/google_analytics.py:202
+#: dashboard/dashboard_modules/yandex_metrika.py:146
+#: dashboard/dashboard_modules/yandex_metrika.py:154
+msgid "By month"
+msgstr ""
+
+#: dashboard/dashboard_modules/google_analytics.py:275
+#, python-format
+msgid ""
+"Please <a href=\"%s\">attach Google account and choose Google Analytics "
+"counter</a> to start using widget"
 msgstr ""
 
-#: models.py:37 modules.py:114 templates/admin/sidebar.html:55
+#: dashboard/dashboard_modules/google_analytics.py:278
+#, python-format
+msgid ""
+"Please <a href=\"%s\">select Google Analytics counter</a> to start using "
+"widget"
+msgstr ""
+
+#: dashboard/dashboard_modules/google_analytics.py:297
+#: dashboard/dashboard_modules/google_analytics_views.py:42
+#: dashboard/dashboard_modules/yandex_metrika.py:231
+#: dashboard/dashboard_modules/yandex_metrika_views.py:37
+msgid "API request failed."
+msgstr ""
+
+#: dashboard/dashboard_modules/google_analytics.py:299
+#: dashboard/dashboard_modules/yandex_metrika.py:233
+#, python-format
+msgid " Try to <a href=\"%s\">revoke and grant access</a> again"
+msgstr ""
+
+#: dashboard/dashboard_modules/google_analytics.py:304
+msgid "Google Analytics visitors totals"
+msgstr ""
+
+#: dashboard/dashboard_modules/google_analytics.py:316
+msgid "users"
+msgstr ""
+
+#: dashboard/dashboard_modules/google_analytics.py:317
+msgid "sessions"
+msgstr ""
+
+#: dashboard/dashboard_modules/google_analytics.py:318
+#: dashboard/dashboard_modules/yandex_metrika.py:254
+msgid "views"
+msgstr ""
+
+#: dashboard/dashboard_modules/google_analytics.py:320
+#: dashboard/dashboard_modules/google_analytics.py:365
+#: dashboard/dashboard_modules/google_analytics.py:404
+#: dashboard/dashboard_modules/yandex_metrika.py:256
+#: dashboard/dashboard_modules/yandex_metrika.py:295
+#: dashboard/dashboard_modules/yandex_metrika.py:328
+msgid "Bad server response"
+msgstr ""
+
+#: dashboard/dashboard_modules/google_analytics.py:324
+msgid "Google Analytics visitors chart"
+msgstr ""
+
+#: dashboard/dashboard_modules/google_analytics.py:369
+msgid "Google Analytics period visitors"
+msgstr ""
+
+#: dashboard/dashboard_modules/google_analytics_views.py:26
+#: dashboard/dashboard_modules/google_analytics_views.py:46
+#: dashboard/dashboard_modules/yandex_metrika_views.py:23
+#: dashboard/dashboard_modules/yandex_metrika_views.py:45
+msgid "Module not found"
+msgstr ""
+
+#: dashboard/dashboard_modules/google_analytics_views.py:44
+#: dashboard/dashboard_modules/yandex_metrika_views.py:43
+msgid "Bad arguments"
+msgstr ""
+
+#: dashboard/dashboard_modules/yandex_metrika.py:139
+#: dashboard/templates/jet.dashboard/modules/yandex_metrika_period_visitors.html:15
+msgid "Visitors"
+msgstr ""
+
+#: dashboard/dashboard_modules/yandex_metrika.py:140
+#: dashboard/templates/jet.dashboard/modules/yandex_metrika_period_visitors.html:16
+msgid "Visits"
+msgstr ""
+
+#: dashboard/dashboard_modules/yandex_metrika.py:214
+#, python-format
+msgid ""
+"Please <a href=\"%s\">attach Yandex account and choose Yandex Metrika "
+"counter</a> to start using widget"
+msgstr ""
+
+#: dashboard/dashboard_modules/yandex_metrika.py:217
+#, python-format
+msgid ""
+"Please <a href=\"%s\">select Yandex Metrika counter</a> to start using widget"
+msgstr ""
+
+#: dashboard/dashboard_modules/yandex_metrika.py:240
+msgid "Yandex Metrika visitors totals"
+msgstr ""
+
+#: dashboard/dashboard_modules/yandex_metrika.py:252
+msgid "visitors"
+msgstr ""
+
+#: dashboard/dashboard_modules/yandex_metrika.py:253
+msgid "visits"
+msgstr ""
+
+#: dashboard/dashboard_modules/yandex_metrika.py:260
+msgid "Yandex Metrika visitors chart"
+msgstr ""
+
+#: dashboard/dashboard_modules/yandex_metrika.py:299
+msgid "Yandex Metrika period visitors"
+msgstr ""
+
+#: dashboard/models.py:11 dashboard/modules.py:116
+#: templates/admin/base.html:189
 msgid "Title"
 msgstr ""
 
-#: models.py:38
+#: dashboard/models.py:12
 msgid "module"
 msgstr ""
 
-#: models.py:41
+#: dashboard/models.py:13 models.py:28
+msgid "application name"
+msgstr ""
+
+#: dashboard/models.py:14 models.py:14 models.py:29
+msgid "user"
+msgstr ""
+
+#: dashboard/models.py:15
 msgid "column"
 msgstr ""
 
-#: models.py:42
+#: dashboard/models.py:16
 msgid "order"
 msgstr ""
 
-#: models.py:43
+#: dashboard/models.py:17
 msgid "settings"
 msgstr ""
 
-#: models.py:44
+#: dashboard/models.py:18
 msgid "children"
 msgstr ""
 
-#: models.py:45
+#: dashboard/models.py:19
 msgid "collapsed"
 msgstr ""
 
-#: models.py:48
+#: dashboard/models.py:22
 msgid "user dashboard module"
 msgstr ""
 
-#: models.py:49
+#: dashboard/models.py:23
 msgid "user dashboard modules"
 msgstr ""
 
-#: modules.py:115
+#: dashboard/modules.py:115 models.py:12 templates/admin/base.html:191
+msgid "URL"
+msgstr ""
+
+#: dashboard/modules.py:117
 msgid "External link"
 msgstr ""
 
-#: modules.py:119
+#: dashboard/modules.py:121
 msgid "Layout"
 msgstr ""
 
-#: modules.py:119
+#: dashboard/modules.py:121
 msgid "Stacked"
 msgstr ""
 
-#: modules.py:119
+#: dashboard/modules.py:121
 msgid "Inline"
 msgstr ""
 
-#: modules.py:123 modules.py:129
+#: dashboard/modules.py:125 dashboard/modules.py:131
 msgid "Links"
 msgstr ""
 
-#: modules.py:128
+#: dashboard/modules.py:130
 msgid "Link"
 msgstr ""
 
-#: modules.py:198
+#: dashboard/modules.py:201
 msgid "Models"
 msgstr ""
 
-#: modules.py:234 modules.py:305
+#: dashboard/modules.py:238 dashboard/modules.py:309
 msgid "Items limit"
 msgstr ""
 
-#: modules.py:306
+#: dashboard/modules.py:310
 msgid "Feed URL"
 msgstr ""
 
-#: modules.py:310
+#: dashboard/modules.py:314
 msgid "RSS Feed"
 msgstr ""
 
-#: modules.py:352
+#: dashboard/modules.py:356
 msgid "You must install the FeedParser python module"
 msgstr ""
 
-#: modules.py:357
+#: dashboard/modules.py:361
 msgid "You must provide a valid feed URL"
 msgstr ""
 
+#: dashboard/templates/admin/app_index.html:32
+#: dashboard/templates/jet.dashboard/update_module.html:14
+#: templates/admin/base.html:92 templates/admin/base.html.py:141
+#: templates/admin/change_form.html:17 templates/admin/change_list.html:33
+#: templates/admin/delete_confirmation.html:8
+#: templates/admin/delete_selected_confirmation.html:8
+#: templates/admin/object_history.html:6
+#: templates/registration/logged_out.html:4
+#: templates/registration/password_change_done.html:6
+#: templates/registration/password_change_form.html:6
+msgid "Home"
+msgstr ""
+
+#: dashboard/templates/jet.dashboard/dashboard.html:17
+msgid "Delete widget"
+msgstr ""
+
+#: dashboard/templates/jet.dashboard/dashboard.html:18
+msgid "Are you sure want to delete this widget?"
+msgstr ""
+
+#: dashboard/templates/jet.dashboard/dashboard_tools.html:7
+msgid "widgets"
+msgstr ""
+
+#: dashboard/templates/jet.dashboard/dashboard_tools.html:8
+msgid "available"
+msgstr ""
+
+#: dashboard/templates/jet.dashboard/dashboard_tools.html:13
+msgid "inititals"
+msgstr ""
+
+#: dashboard/templates/jet.dashboard/dashboard_tools.html:18
+#: dashboard/templates/jet.dashboard/modules/app_list.html:18
+#: dashboard/templates/jet.dashboard/modules/model_list.html:8
+#: templates/admin/change_form.html:20 templates/admin/index.html:34
+msgid "Add"
+msgstr ""
+
+#: dashboard/templates/jet.dashboard/module.html:19
+#: dashboard/templates/jet.dashboard/modules/app_list.html:24
+#: dashboard/templates/jet.dashboard/modules/model_list.html:14
+#: dashboard/views.py:86 templates/admin/edit_inline/stacked.html:44
+#: templates/admin/edit_inline/tabular.html:39 templates/admin/index.html:40
+msgid "Change"
+msgstr ""
+
+#: dashboard/templates/jet.dashboard/module.html:22
+#: templates/admin/delete_confirmation.html:12
+#: templates/admin/related_widget_wrapper.html:24
+#: templates/admin/submit_line.html:11
+msgid "Delete"
+msgstr ""
+
+#: dashboard/templates/jet.dashboard/modules/app_list.html:7
+#: dashboard/templates/jet.dashboard/modules/app_list.html:10
+#: templates/admin/index.html:23 templates/admin/index.html.py:26
+#, python-format
+msgid "Models in the %(name)s application"
+msgstr ""
+
+#: dashboard/templates/jet.dashboard/modules/feed.html:13
+#: dashboard/templates/jet.dashboard/modules/google_analytics_period_visitors.html:34
+#: dashboard/templates/jet.dashboard/modules/google_analytics_visitors_chart.html:30
+#: dashboard/templates/jet.dashboard/modules/google_analytics_visitors_totals.html:23
+#: dashboard/templates/jet.dashboard/modules/link_list.html:26
+#: dashboard/templates/jet.dashboard/modules/yandex_metrika_period_visitors.html:34
+#: dashboard/templates/jet.dashboard/modules/yandex_metrika_visitors_chart.html:30
+#: dashboard/templates/jet.dashboard/modules/yandex_metrika_visitors_totals.html:23
+msgid "Nothing to show"
+msgstr ""
+
+#: dashboard/templates/jet.dashboard/modules/google_analytics_period_visitors.html:14
+#: dashboard/templates/jet.dashboard/modules/yandex_metrika_period_visitors.html:14
+msgid "Date"
+msgstr ""
+
+#: dashboard/templates/jet.dashboard/modules/recent_actions.html:6
+#: templates/admin/index.html:75
+msgid "None available"
+msgstr ""
+
+#: dashboard/templates/jet.dashboard/modules/recent_actions.html:29
+#: templates/admin/index.html:98
+msgid "Unknown content"
+msgstr ""
+
+#: dashboard/templates/jet.dashboard/update_module.html:35
+#: templates/admin/change_form.html:62
+msgid "General"
+msgstr ""
+
+#: dashboard/templates/jet.dashboard/update_module.html:56
+#: templates/admin/change_list.html:61
+#: templates/admin/edit_inline/stacked.html:8
+#: templates/admin/edit_inline/tabular.html:10
+#: templates/admin/includes/fieldset.html:9 templates/admin/login.html:27
+#: templates/registration/password_change_form.html:21
+msgid "Please correct the errors below."
+msgstr ""
+
+#: dashboard/templates/jet.dashboard/update_module.html:126
+#: templates/admin/base.html:211 templates/admin/base.html.py:218
+#: templates/admin/edit_inline/stacked.html:21
+#: templates/admin/edit_inline/stacked.html:75
+#: templates/admin/edit_inline/tabular.html:100
+msgid "Remove"
+msgstr ""
+
+#: dashboard/templates/jet.dashboard/update_module.html:127
+#: templates/admin/edit_inline/stacked.html:76
+#: templates/admin/edit_inline/tabular.html:99
+#, python-format
+msgid "Add another %(verbose_name)s"
+msgstr ""
+
+#: dashboard/templates/jet.dashboard/update_module.html:135
+#: templates/admin/pagination.html:20 templates/admin/submit_line.html:4
+msgid "Save"
+msgstr ""
+
+#: dashboard/views.py:18
+msgid "Widget was successfully updated"
+msgstr ""
+
+#: dashboard/views.py:90 dashboard/views.py:91
+msgid "Items"
+msgstr ""
+
+#: dashboard/views.py:153
+msgid "Widget has been successfully added"
+msgstr ""
+
+#: models.py:13
+msgid "title"
+msgstr ""
+
+#: models.py:15 models.py:30
+msgid "date created"
+msgstr ""
+
+#: models.py:18
+msgid "bookmark"
+msgstr ""
+
+#: models.py:19 templates/admin/base.html:204
+msgid "bookmarks"
+msgstr ""
+
+#: models.py:33
+msgid "pinned application"
+msgstr ""
+
+#: models.py:34
+msgid "pinned applications"
+msgstr ""
+
 #: templates/admin/actions.html:8
 msgid "Run the selected action"
 msgstr ""
@@ -208,59 +576,54 @@ msgstr ""
 msgid "Clear selection"
 msgstr ""
 
-#: templates/admin/app_index.html:30 templates/admin/base.html:100
-#: templates/admin/change_form.html:22 templates/admin/change_list.html:33
-#: templates/admin/delete_confirmation.html:8
-#: templates/admin/delete_selected_confirmation.html:8
-#: templates/admin/sidebar.html:7
-#: templates/jet/dashboard/update_module.html:13
-#: templates/registration/logged_out.html:4
-#: templates/registration/password_change_done.html:6
-#: templates/registration/password_change_form.html:11
-msgid "Home"
+#: templates/admin/base.html:146
+msgid "View site"
 msgstr ""
 
-#: templates/admin/change_form.html:25
-#: templates/jet/dashboard/dashboard_tools.html:18
-#: templates/jet/dashboard/modules/app_list.html:13
-#: templates/jet/dashboard/modules/model_list.html:8
-msgid "Add"
+#: templates/admin/base.html:186 templates/admin/base.html.py:203
+msgid "Add bookmark"
+msgstr ""
+
+#: templates/admin/base.html:199
+msgid "Delete bookmark"
+msgstr ""
+
+#: templates/admin/base.html:200
+msgid "Are you sure want to delete this bookmark?"
+msgstr ""
+
+#: templates/admin/base.html:226
+msgid "Documentation"
+msgstr ""
+
+#: templates/admin/base.html:249
+msgid "Application page"
+msgstr ""
+
+#: templates/admin/base_site.html:3
+msgid "Django site admin"
 msgstr ""
 
-#: templates/admin/change_form.html:40
+#: templates/admin/change_form.html:35 templates/admin/object_history.html:10
 msgid "History"
 msgstr ""
 
-#: templates/admin/change_form.html:43
+#: templates/admin/change_form.html:38
 #: templates/admin/edit_inline/stacked.html:49
 #: templates/admin/edit_inline/tabular.html:45
 msgid "View on site"
 msgstr ""
 
-#: templates/admin/change_form.html:67
-#: templates/jet/dashboard/update_module.html:34
-msgid "General"
-msgstr ""
-
 #: templates/admin/change_list.html:51
 #, python-format
 msgid "Add %(name)s"
 msgstr ""
 
 #: templates/admin/change_list.html:61 templates/admin/login.html:27
-#: templates/registration/password_change_form.html:26
+#: templates/registration/password_change_form.html:21
 msgid "Please correct the error below."
 msgstr ""
 
-#: templates/admin/change_list.html:61
-#: templates/admin/edit_inline/stacked.html:8
-#: templates/admin/edit_inline/tabular.html:10
-#: templates/admin/includes/fieldset.html:10 templates/admin/login.html:27
-#: templates/jet/dashboard/update_module.html:53
-#: templates/registration/password_change_form.html:26
-msgid "Please correct the errors below."
-msgstr ""
-
 #: templates/admin/change_list_results.html:17
 #, python-format
 msgid "Sorting priority: %(priority_number)s"
@@ -278,12 +641,6 @@ msgstr ""
 msgid "try to reset filters"
 msgstr ""
 
-#: templates/admin/delete_confirmation.html:12
-#: templates/admin/related_widget_wrapper.html:24
-#: templates/admin/submit_line.html:11 templates/jet/dashboard/module.html:22
-msgid "Delete"
-msgstr ""
-
 #: templates/admin/delete_confirmation.html:18
 #, python-format
 msgid ""
@@ -347,29 +704,6 @@ msgid ""
 "following objects and their related items will be deleted:"
 msgstr ""
 
-#: templates/admin/edit_inline/stacked.html:21
-#: templates/admin/edit_inline/stacked.html:75
-#: templates/admin/edit_inline/tabular.html:100
-#: templates/admin/sidebar.html:77 templates/admin/sidebar.html.py:84
-#: templates/jet/dashboard/update_module.html:123
-msgid "Remove"
-msgstr ""
-
-#: templates/admin/edit_inline/stacked.html:44
-#: templates/admin/edit_inline/tabular.html:39
-#: templates/jet/dashboard/module.html:19
-#: templates/jet/dashboard/modules/app_list.html:19
-#: templates/jet/dashboard/modules/model_list.html:14 views.py:83
-msgid "Change"
-msgstr ""
-
-#: templates/admin/edit_inline/stacked.html:76
-#: templates/admin/edit_inline/tabular.html:99
-#: templates/jet/dashboard/update_module.html:124
-#, python-format
-msgid "Add another %(verbose_name)s"
-msgstr ""
-
 #: templates/admin/edit_inline/tabular.html:25
 msgid "Delete?"
 msgstr ""
@@ -383,6 +717,10 @@ msgstr ""
 msgid "Summary"
 msgstr ""
 
+#: templates/admin/index.html:56
+msgid "You don't have permission to edit anything."
+msgstr ""
+
 #: templates/admin/login.html:16
 msgid "<span class=\"bright\">Admin</span> Site"
 msgstr ""
@@ -395,13 +733,26 @@ msgstr ""
 msgid "Forgotten your password or username?"
 msgstr ""
 
-#: templates/admin/pagination.html:7 templates/admin/search_form.html:22
-msgid "Show all"
+#: templates/admin/object_history.html:21
+msgid "Date/time"
 msgstr ""
 
-#: templates/admin/pagination.html:20 templates/admin/submit_line.html:4
-#: templates/jet/dashboard/update_module.html:132
-msgid "Save"
+#: templates/admin/object_history.html:22
+msgid "User"
+msgstr ""
+
+#: templates/admin/object_history.html:23
+msgid "Action"
+msgstr ""
+
+#: templates/admin/object_history.html:37
+msgid ""
+"This object doesn't have a change history. It probably wasn't added via this "
+"admin site."
+msgstr ""
+
+#: templates/admin/pagination.html:7 templates/admin/search_form.html:20
+msgid "Show all"
 msgstr ""
 
 #: templates/admin/related_widget_wrapper.html:8
@@ -419,46 +770,22 @@ msgstr ""
 msgid "Delete selected %(model)s"
 msgstr ""
 
-#: templates/admin/search_form.html:8 templates/admin/search_form.html:19
+#: templates/admin/search_form.html:6 templates/admin/search_form.html:17
 msgid "Search"
 msgstr ""
 
-#: templates/admin/search_form.html:22
+#: templates/admin/search_form.html:20
 #, python-format
 msgid "%(counter)s result"
 msgid_plural "%(counter)s results"
 msgstr[0] ""
 msgstr[1] ""
 
-#: templates/admin/search_form.html:22
+#: templates/admin/search_form.html:20
 #, python-format
 msgid "%(full_result_count)s total"
 msgstr ""
 
-#: templates/admin/sidebar.html:12
-msgid "View site"
-msgstr ""
-
-#: templates/admin/sidebar.html:52 templates/admin/sidebar.html.py:69
-msgid "Add bookmark"
-msgstr ""
-
-#: templates/admin/sidebar.html:65
-msgid "Delete bookmark"
-msgstr ""
-
-#: templates/admin/sidebar.html:66
-msgid "Are you sure want to delete this bookmark?"
-msgstr ""
-
-#: templates/admin/sidebar.html:93
-msgid "Documentation"
-msgstr ""
-
-#: templates/admin/sidebar.html:113
-msgid "Application page"
-msgstr ""
-
 #: templates/admin/submit_line.html:5
 msgid "Save as new"
 msgstr ""
@@ -471,44 +798,6 @@ msgstr ""
 msgid "Save and continue editing"
 msgstr ""
 
-#: templates/jet/dashboard/dashboard.html:17
-msgid "Delete widget"
-msgstr ""
-
-#: templates/jet/dashboard/dashboard.html:18
-msgid "Are you sure want to delete this widget?"
-msgstr ""
-
-#: templates/jet/dashboard/dashboard_tools.html:7
-msgid "widgets"
-msgstr ""
-
-#: templates/jet/dashboard/dashboard_tools.html:8
-msgid "available"
-msgstr ""
-
-#: templates/jet/dashboard/dashboard_tools.html:13
-msgid "inititals"
-msgstr ""
-
-#: templates/jet/dashboard/modules/app_list.html:6
-#, python-format
-msgid "Models in the %(name)s application"
-msgstr ""
-
-#: templates/jet/dashboard/modules/feed.html:13
-#: templates/jet/dashboard/modules/link_list.html:26
-msgid "Nothing to show"
-msgstr ""
-
-#: templates/jet/dashboard/modules/recent_actions.html:6
-msgid "None available"
-msgstr ""
-
-#: templates/jet/dashboard/modules/recent_actions.html:26
-msgid "Unknown content"
-msgstr ""
-
 #: templates/registration/logged_out.html:9
 msgid "Thanks for spending some quality time with the Web site today."
 msgstr ""
@@ -518,7 +807,7 @@ msgid "Log in again"
 msgstr ""
 
 #: templates/registration/password_change_done.html:7
-#: templates/registration/password_change_form.html:12
+#: templates/registration/password_change_form.html:7
 msgid "Password change"
 msgstr ""
 
@@ -526,24 +815,12 @@ msgstr ""
 msgid "Your password was changed."
 msgstr ""
 
-#: templates/registration/password_change_form.html:30
+#: templates/registration/password_change_form.html:25
 msgid ""
 "Please enter your old password, for security's sake, and then enter your new "
 "password twice so we can verify you typed it in correctly."
 msgstr ""
 
-#: templates/registration/password_change_form.html:55
+#: templates/registration/password_change_form.html:50
 msgid "Change my password"
 msgstr ""
-
-#: views.py:18
-msgid "Widget was successfully updated"
-msgstr ""
-
-#: views.py:87 views.py:88
-msgid "Items"
-msgstr ""
-
-#: views.py:195
-msgid "Widget has been successfully added"
-msgstr ""

BIN
jet/locale/ru/LC_MESSAGES/django.mo


+ 492 - 205
jet/locale/ru/LC_MESSAGES/django.po

@@ -6,7 +6,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: PACKAGE VERSION\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2015-08-07 13:25+0000\n"
+"POT-Creation-Date: 2015-09-07 13:42+0000\n"
 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
 "Language-Team: LANGUAGE <LL@li.org>\n"
@@ -17,178 +17,552 @@ msgstr ""
 "Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n"
 "%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n"
 
-#: dashboard.py:157
+#: dashboard/dashboard.py:159
 msgid "Quick links"
 msgstr "Быстрые ссылки"
 
-#: dashboard.py:163
+#: dashboard/dashboard.py:165
 msgid "Return to site"
 msgstr "Вернуться на сайт"
 
-#: dashboard.py:164 templates/admin/base.html:85
+#: dashboard/dashboard.py:166 templates/admin/base.html:77
 msgid "Change password"
 msgstr ""
 
-#: dashboard.py:166 templates/admin/base.html:89
+#: dashboard/dashboard.py:168 templates/admin/base.html:81
 msgid "Log out"
 msgstr ""
 
-#: dashboard.py:174 modules.py:158 templates/admin/sidebar.html:23
+#: dashboard/dashboard.py:176 dashboard/modules.py:160
+#: templates/admin/base.html:157 templates/admin/index.html:14
 msgid "Applications"
 msgstr "Приложения"
 
-#: dashboard.py:182
+#: dashboard/dashboard.py:184
 msgid "Administration"
 msgstr "Администрирование"
 
-#: dashboard.py:190 modules.py:238
+#: dashboard/dashboard.py:192 dashboard/modules.py:242
+#: templates/admin/index.html:68
 msgid "Recent Actions"
 msgstr "Последние действия"
 
-#: dashboard.py:198
+#: dashboard/dashboard.py:200
 msgid "Latest Django News"
 msgstr "Новости от Django"
 
-#: dashboard.py:207
+#: dashboard/dashboard.py:209
 msgid "Support"
 msgstr "Поддержка"
 
-#: dashboard.py:210
+#: dashboard/dashboard.py:212
 msgid "Django documentation"
 msgstr "Документация по Django"
 
-#: dashboard.py:215
+#: dashboard/dashboard.py:217
 msgid "Django \"django-users\" mailing list"
 msgstr "Гугл-группа \"django-users\""
 
-#: dashboard.py:220
+#: dashboard/dashboard.py:222
 msgid "Django irc channel"
 msgstr "IRC канал Django"
 
-#: dashboard.py:235
+#: dashboard/dashboard.py:237
 msgid "Application models"
 msgstr "Модели приложения"
 
-#: models.py:8 modules.py:113 templates/admin/sidebar.html:57
-msgid "URL"
-msgstr "URL"
-
-#: models.py:9
-msgid "title"
+#: dashboard/dashboard_modules/google_analytics.py:143
+#: dashboard/dashboard_modules/yandex_metrika.py:101
+msgid "Revoke access"
+msgstr "Убрать доступ"
+
+#: dashboard/dashboard_modules/google_analytics.py:148
+#: dashboard/dashboard_modules/yandex_metrika.py:106
+msgid "Grant access"
+msgstr "Предоставить доступ"
+
+#: dashboard/dashboard_modules/google_analytics.py:161
+#: dashboard/dashboard_modules/yandex_metrika.py:113
+msgid "Access"
+msgstr "Доступ"
+
+#: dashboard/dashboard_modules/google_analytics.py:162
+#: dashboard/dashboard_modules/yandex_metrika.py:114
+msgid "Counter"
+msgstr "Счетчик"
+
+#: dashboard/dashboard_modules/google_analytics.py:163
+#: dashboard/dashboard_modules/yandex_metrika.py:115
+msgid "Statistics period"
+msgstr "Статистика за период"
+
+#: dashboard/dashboard_modules/google_analytics.py:164
+#: dashboard/dashboard_modules/yandex_metrika.py:116
+msgid "Today"
+msgstr "Сегодня"
+
+#: dashboard/dashboard_modules/google_analytics.py:165
+#: dashboard/dashboard_modules/yandex_metrika.py:117
+msgid "Last week"
+msgstr "Последняя неделя"
+
+#: dashboard/dashboard_modules/google_analytics.py:166
+#: dashboard/dashboard_modules/yandex_metrika.py:118
+msgid "Last month"
+msgstr "Последний месяц"
+
+#: dashboard/dashboard_modules/google_analytics.py:167
+#: dashboard/dashboard_modules/yandex_metrika.py:119
+msgid "Last quarter"
+msgstr "Последний квартал"
+
+#: dashboard/dashboard_modules/google_analytics.py:168
+#: dashboard/dashboard_modules/yandex_metrika.py:120
+msgid "Last year"
+msgstr "Последний год"
+
+#: dashboard/dashboard_modules/google_analytics.py:178
+#: dashboard/dashboard_modules/yandex_metrika.py:130
+msgid "none"
+msgstr "не указано"
+
+#: dashboard/dashboard_modules/google_analytics.py:181
+#: dashboard/dashboard_modules/yandex_metrika.py:133
+msgid "grant access first"
+msgstr "сначала предоставьте доступ"
+
+#: dashboard/dashboard_modules/google_analytics.py:181
+#: dashboard/dashboard_modules/yandex_metrika.py:133
+msgid "counters loading failed"
+msgstr "не удалось загрузить счетчики"
+
+#: dashboard/dashboard_modules/google_analytics.py:186
+#: dashboard/dashboard_modules/yandex_metrika.py:138
+msgid "Show"
+msgstr "Показывать"
+
+#: dashboard/dashboard_modules/google_analytics.py:187
+#: dashboard/templates/jet.dashboard/modules/google_analytics_period_visitors.html:15
+msgid "Users"
+msgstr "Пользователи"
+
+#: dashboard/dashboard_modules/google_analytics.py:188
+#: dashboard/templates/jet.dashboard/modules/google_analytics_period_visitors.html:16
+msgid "Sessions"
+msgstr "Сессии"
+
+#: dashboard/dashboard_modules/google_analytics.py:189
+#: dashboard/dashboard_modules/yandex_metrika.py:141
+#: dashboard/templates/jet.dashboard/modules/google_analytics_period_visitors.html:17
+#: dashboard/templates/jet.dashboard/modules/yandex_metrika_period_visitors.html:17
+msgid "Views"
+msgstr "Просмотры"
+
+#: dashboard/dashboard_modules/google_analytics.py:191
+#: dashboard/dashboard_modules/google_analytics.py:199
+#: dashboard/dashboard_modules/yandex_metrika.py:143
+#: dashboard/dashboard_modules/yandex_metrika.py:151
+msgid "Group"
+msgstr "Группировать"
+
+#: dashboard/dashboard_modules/google_analytics.py:192
+#: dashboard/dashboard_modules/google_analytics.py:200
+#: dashboard/dashboard_modules/yandex_metrika.py:144
+#: dashboard/dashboard_modules/yandex_metrika.py:152
+msgid "By day"
+msgstr "По дням"
+
+#: dashboard/dashboard_modules/google_analytics.py:193
+#: dashboard/dashboard_modules/google_analytics.py:201
+#: dashboard/dashboard_modules/yandex_metrika.py:145
+#: dashboard/dashboard_modules/yandex_metrika.py:153
+msgid "By week"
+msgstr "По неделям"
+
+#: dashboard/dashboard_modules/google_analytics.py:194
+#: dashboard/dashboard_modules/google_analytics.py:202
+#: dashboard/dashboard_modules/yandex_metrika.py:146
+#: dashboard/dashboard_modules/yandex_metrika.py:154
+msgid "By month"
+msgstr "По месяцам"
+
+#: dashboard/dashboard_modules/google_analytics.py:275
+#, python-format
+msgid ""
+"Please <a href=\"%s\">attach Google account and choose Google Analytics "
+"counter</a> to start using widget"
 msgstr ""
+"Пожалуйста <a href=\"%s\">прикрепите аккаунт Google и выберите счетчик "
+"Google Analytics</a> для виджета"
 
-#: models.py:10 models.py:24 models.py:40
-msgid "user"
+#: dashboard/dashboard_modules/google_analytics.py:278
+#, python-format
+msgid ""
+"Please <a href=\"%s\">select Google Analytics counter</a> to start using "
+"widget"
 msgstr ""
+"Пожалуйста <a href=\"%s\">выберите счетчик Google Analytics</a> для виджета"
 
-#: models.py:11 models.py:25
-msgid "date created"
+#: dashboard/dashboard_modules/google_analytics.py:297
+#: dashboard/dashboard_modules/google_analytics_views.py:42
+#: dashboard/dashboard_modules/yandex_metrika.py:231
+#: dashboard/dashboard_modules/yandex_metrika_views.py:37
+msgid "API request failed."
+msgstr "Ошибка запроса к API."
+
+#: dashboard/dashboard_modules/google_analytics.py:299
+#: dashboard/dashboard_modules/yandex_metrika.py:233
+#, python-format
+msgid " Try to <a href=\"%s\">revoke and grant access</a> again"
+msgstr " Попробуйте <a href=\"%s\">убрать и предоставить доступ</a> заново"
+
+#: dashboard/dashboard_modules/google_analytics.py:304
+msgid "Google Analytics visitors totals"
+msgstr "Данные о посещениях Google Analytics"
+
+#: dashboard/dashboard_modules/google_analytics.py:316
+msgid "users"
+msgstr "пользовотели"
+
+#: dashboard/dashboard_modules/google_analytics.py:317
+msgid "sessions"
+msgstr "сессии"
+
+#: dashboard/dashboard_modules/google_analytics.py:318
+#: dashboard/dashboard_modules/yandex_metrika.py:254
+msgid "views"
+msgstr "просмотры"
+
+#: dashboard/dashboard_modules/google_analytics.py:320
+#: dashboard/dashboard_modules/google_analytics.py:365
+#: dashboard/dashboard_modules/google_analytics.py:404
+#: dashboard/dashboard_modules/yandex_metrika.py:256
+#: dashboard/dashboard_modules/yandex_metrika.py:295
+#: dashboard/dashboard_modules/yandex_metrika.py:328
+msgid "Bad server response"
+msgstr "Некорректный ответ сервера"
+
+#: dashboard/dashboard_modules/google_analytics.py:324
+msgid "Google Analytics visitors chart"
+msgstr "График посещений Google Analytics"
+
+#: dashboard/dashboard_modules/google_analytics.py:369
+msgid "Google Analytics period visitors"
+msgstr "Посещения Google Analytics за период"
+
+#: dashboard/dashboard_modules/google_analytics_views.py:26
+#: dashboard/dashboard_modules/google_analytics_views.py:46
+#: dashboard/dashboard_modules/yandex_metrika_views.py:23
+#: dashboard/dashboard_modules/yandex_metrika_views.py:45
+msgid "Module not found"
+msgstr "Модуль не найден"
+
+#: dashboard/dashboard_modules/google_analytics_views.py:44
+#: dashboard/dashboard_modules/yandex_metrika_views.py:43
+msgid "Bad arguments"
+msgstr "Некорректные аргументы"
+
+#: dashboard/dashboard_modules/yandex_metrika.py:139
+#: dashboard/templates/jet.dashboard/modules/yandex_metrika_period_visitors.html:15
+msgid "Visitors"
+msgstr "Посетители"
+
+#: dashboard/dashboard_modules/yandex_metrika.py:140
+#: dashboard/templates/jet.dashboard/modules/yandex_metrika_period_visitors.html:16
+msgid "Visits"
+msgstr "Визиты"
+
+#: dashboard/dashboard_modules/yandex_metrika.py:214
+#, python-format
+msgid ""
+"Please <a href=\"%s\">attach Yandex account and choose Yandex Metrika "
+"counter</a> to start using widget"
 msgstr ""
+"Пожалуйста <a href=\"%s\">прикрепите аккаунт Яндекс и выберите счетчик "
+"Яндекс Метрики</a> для виджета"
 
-#: models.py:14
-msgid "bookmark"
+#: dashboard/dashboard_modules/yandex_metrika.py:217
+#, python-format
+msgid ""
+"Please <a href=\"%s\">select Yandex Metrika counter</a> to start using widget"
 msgstr ""
+"Пожалуйста <a href=\"%s\">выберите счетчик Яндекс Метрики</a> для виджета"
 
-#: models.py:15 templates/admin/sidebar.html:70
-msgid "bookmarks"
-msgstr "закладки"
+#: dashboard/dashboard_modules/yandex_metrika.py:240
+msgid "Yandex Metrika visitors totals"
+msgstr "Данные о посещениях Яндекс Метрики"
 
-#: models.py:23 models.py:39
-msgid "application name"
-msgstr ""
+#: dashboard/dashboard_modules/yandex_metrika.py:252
+msgid "visitors"
+msgstr "посетители"
 
-#: models.py:28
-msgid "pinned application"
-msgstr ""
+#: dashboard/dashboard_modules/yandex_metrika.py:253
+msgid "visits"
+msgstr "визиты"
 
-#: models.py:29
-msgid "pinned applications"
-msgstr ""
+#: dashboard/dashboard_modules/yandex_metrika.py:260
+msgid "Yandex Metrika visitors chart"
+msgstr "График посещений Яндекс Метрики"
+
+#: dashboard/dashboard_modules/yandex_metrika.py:299
+msgid "Yandex Metrika period visitors"
+msgstr "Посещения Яндекс Метрики за период"
 
-#: models.py:37 modules.py:114 templates/admin/sidebar.html:55
+#: dashboard/models.py:11 dashboard/modules.py:116
+#: templates/admin/base.html:189
 msgid "Title"
 msgstr "Название"
 
-#: models.py:38
+#: dashboard/models.py:12
 msgid "module"
 msgstr ""
 
-#: models.py:41
+#: dashboard/models.py:13 models.py:28
+msgid "application name"
+msgstr ""
+
+#: dashboard/models.py:14 models.py:14 models.py:29
+msgid "user"
+msgstr ""
+
+#: dashboard/models.py:15
 msgid "column"
 msgstr ""
 
-#: models.py:42
+#: dashboard/models.py:16
 msgid "order"
 msgstr ""
 
-#: models.py:43
+#: dashboard/models.py:17
 msgid "settings"
 msgstr ""
 
-#: models.py:44
+#: dashboard/models.py:18
 msgid "children"
 msgstr ""
 
-#: models.py:45
+#: dashboard/models.py:19
 msgid "collapsed"
 msgstr ""
 
-#: models.py:48
+#: dashboard/models.py:22
 msgid "user dashboard module"
 msgstr ""
 
-#: models.py:49
+#: dashboard/models.py:23
 msgid "user dashboard modules"
 msgstr ""
 
-#: modules.py:115
+#: dashboard/modules.py:115 models.py:12 templates/admin/base.html:191
+msgid "URL"
+msgstr "URL"
+
+#: dashboard/modules.py:117
 msgid "External link"
 msgstr "Внешняя ссылка"
 
-#: modules.py:119
+#: dashboard/modules.py:121
 msgid "Layout"
 msgstr "Отображение"
 
-#: modules.py:119
+#: dashboard/modules.py:121
 msgid "Stacked"
 msgstr "Списком"
 
-#: modules.py:119
+#: dashboard/modules.py:121
 msgid "Inline"
 msgstr "В строчку"
 
-#: modules.py:123 modules.py:129
+#: dashboard/modules.py:125 dashboard/modules.py:131
 msgid "Links"
 msgstr "Ссылки"
 
-#: modules.py:128
+#: dashboard/modules.py:130
 msgid "Link"
 msgstr "Ссылка"
 
-#: modules.py:198
+#: dashboard/modules.py:201
 msgid "Models"
 msgstr "Модели"
 
-#: modules.py:234 modules.py:305
+#: dashboard/modules.py:238 dashboard/modules.py:309
 msgid "Items limit"
 msgstr "Количество элементов"
 
-#: modules.py:306
+#: dashboard/modules.py:310
 msgid "Feed URL"
 msgstr "URL потока"
 
-#: modules.py:310
+#: dashboard/modules.py:314
 msgid "RSS Feed"
 msgstr "RSS поток"
 
-#: modules.py:352
+#: dashboard/modules.py:356
 msgid "You must install the FeedParser python module"
 msgstr "Необходимо установить python модуль FeedParser"
 
-#: modules.py:357
+#: dashboard/modules.py:361
 msgid "You must provide a valid feed URL"
 msgstr "Необходимо указать корректный URL потока"
 
+#: dashboard/templates/admin/app_index.html:32
+#: dashboard/templates/jet.dashboard/update_module.html:14
+#: templates/admin/base.html:92 templates/admin/base.html.py:141
+#: templates/admin/change_form.html:17 templates/admin/change_list.html:33
+#: templates/admin/delete_confirmation.html:8
+#: templates/admin/delete_selected_confirmation.html:8
+#: templates/admin/object_history.html:6
+#: templates/registration/logged_out.html:4
+#: templates/registration/password_change_done.html:6
+#: templates/registration/password_change_form.html:6
+msgid "Home"
+msgstr ""
+
+#: dashboard/templates/jet.dashboard/dashboard.html:17
+msgid "Delete widget"
+msgstr "Удалить виджет"
+
+#: dashboard/templates/jet.dashboard/dashboard.html:18
+msgid "Are you sure want to delete this widget?"
+msgstr "Вы точно хотите удалить этот виджет?"
+
+#: dashboard/templates/jet.dashboard/dashboard_tools.html:7
+msgid "widgets"
+msgstr "виджеты"
+
+#: dashboard/templates/jet.dashboard/dashboard_tools.html:8
+msgid "available"
+msgstr "доступные"
+
+#: dashboard/templates/jet.dashboard/dashboard_tools.html:13
+msgid "inititals"
+msgstr "изначальные"
+
+#: dashboard/templates/jet.dashboard/dashboard_tools.html:18
+#: dashboard/templates/jet.dashboard/modules/app_list.html:18
+#: dashboard/templates/jet.dashboard/modules/model_list.html:8
+#: templates/admin/change_form.html:20 templates/admin/index.html:34
+msgid "Add"
+msgstr ""
+
+#: dashboard/templates/jet.dashboard/module.html:19
+#: dashboard/templates/jet.dashboard/modules/app_list.html:24
+#: dashboard/templates/jet.dashboard/modules/model_list.html:14
+#: dashboard/views.py:86 templates/admin/edit_inline/stacked.html:44
+#: templates/admin/edit_inline/tabular.html:39 templates/admin/index.html:40
+msgid "Change"
+msgstr ""
+
+#: dashboard/templates/jet.dashboard/module.html:22
+#: templates/admin/delete_confirmation.html:12
+#: templates/admin/related_widget_wrapper.html:24
+#: templates/admin/submit_line.html:11
+msgid "Delete"
+msgstr ""
+
+#: dashboard/templates/jet.dashboard/modules/app_list.html:7
+#: dashboard/templates/jet.dashboard/modules/app_list.html:10
+#: templates/admin/index.html:23 templates/admin/index.html.py:26
+#, python-format
+msgid "Models in the %(name)s application"
+msgstr ""
+
+#: dashboard/templates/jet.dashboard/modules/feed.html:13
+#: dashboard/templates/jet.dashboard/modules/google_analytics_period_visitors.html:34
+#: dashboard/templates/jet.dashboard/modules/google_analytics_visitors_chart.html:30
+#: dashboard/templates/jet.dashboard/modules/google_analytics_visitors_totals.html:23
+#: dashboard/templates/jet.dashboard/modules/link_list.html:26
+#: dashboard/templates/jet.dashboard/modules/yandex_metrika_period_visitors.html:34
+#: dashboard/templates/jet.dashboard/modules/yandex_metrika_visitors_chart.html:30
+#: dashboard/templates/jet.dashboard/modules/yandex_metrika_visitors_totals.html:23
+msgid "Nothing to show"
+msgstr "Содержимое отсутствует"
+
+#: dashboard/templates/jet.dashboard/modules/google_analytics_period_visitors.html:14
+#: dashboard/templates/jet.dashboard/modules/yandex_metrika_period_visitors.html:14
+msgid "Date"
+msgstr ""
+
+#: dashboard/templates/jet.dashboard/modules/recent_actions.html:6
+#: templates/admin/index.html:75
+msgid "None available"
+msgstr ""
+
+#: dashboard/templates/jet.dashboard/modules/recent_actions.html:29
+#: templates/admin/index.html:98
+msgid "Unknown content"
+msgstr ""
+
+#: dashboard/templates/jet.dashboard/update_module.html:35
+#: templates/admin/change_form.html:62
+msgid "General"
+msgstr "Общее"
+
+#: dashboard/templates/jet.dashboard/update_module.html:56
+#: templates/admin/change_list.html:61
+#: templates/admin/edit_inline/stacked.html:8
+#: templates/admin/edit_inline/tabular.html:10
+#: templates/admin/includes/fieldset.html:9 templates/admin/login.html:27
+#: templates/registration/password_change_form.html:21
+msgid "Please correct the errors below."
+msgstr ""
+
+#: dashboard/templates/jet.dashboard/update_module.html:126
+#: templates/admin/base.html:211 templates/admin/base.html.py:218
+#: templates/admin/edit_inline/stacked.html:21
+#: templates/admin/edit_inline/stacked.html:75
+#: templates/admin/edit_inline/tabular.html:100
+msgid "Remove"
+msgstr ""
+
+#: dashboard/templates/jet.dashboard/update_module.html:127
+#: templates/admin/edit_inline/stacked.html:76
+#: templates/admin/edit_inline/tabular.html:99
+#, python-format
+msgid "Add another %(verbose_name)s"
+msgstr ""
+
+#: dashboard/templates/jet.dashboard/update_module.html:135
+#: templates/admin/pagination.html:20 templates/admin/submit_line.html:4
+msgid "Save"
+msgstr ""
+
+#: dashboard/views.py:18
+msgid "Widget was successfully updated"
+msgstr "Виджет успешно изменен"
+
+#: dashboard/views.py:90 dashboard/views.py:91
+msgid "Items"
+msgstr "Элементы"
+
+#: dashboard/views.py:153
+msgid "Widget has been successfully added"
+msgstr "Виджет успешно добавлен"
+
+#: models.py:13
+msgid "title"
+msgstr ""
+
+#: models.py:15 models.py:30
+msgid "date created"
+msgstr ""
+
+#: models.py:18
+msgid "bookmark"
+msgstr ""
+
+#: models.py:19 templates/admin/base.html:204
+msgid "bookmarks"
+msgstr "закладки"
+
+#: models.py:33
+msgid "pinned application"
+msgstr ""
+
+#: models.py:34
+msgid "pinned applications"
+msgstr ""
+
 #: templates/admin/actions.html:8
 msgid "Run the selected action"
 msgstr ""
@@ -210,59 +584,56 @@ msgstr ""
 msgid "Clear selection"
 msgstr ""
 
-#: templates/admin/app_index.html:30 templates/admin/base.html:100
-#: templates/admin/change_form.html:22 templates/admin/change_list.html:33
-#: templates/admin/delete_confirmation.html:8
-#: templates/admin/delete_selected_confirmation.html:8
-#: templates/admin/sidebar.html:7
-#: templates/jet/dashboard/update_module.html:13
-#: templates/registration/logged_out.html:4
-#: templates/registration/password_change_done.html:6
-#: templates/registration/password_change_form.html:11
-msgid "Home"
+#: templates/admin/base.html:146
+msgid "View site"
 msgstr ""
 
-#: templates/admin/change_form.html:25
-#: templates/jet/dashboard/dashboard_tools.html:18
-#: templates/jet/dashboard/modules/app_list.html:13
-#: templates/jet/dashboard/modules/model_list.html:8
-msgid "Add"
+#: templates/admin/base.html:186 templates/admin/base.html.py:203
+msgid "Add bookmark"
+msgstr "Добавить закладку"
+
+#: templates/admin/base.html:199
+msgid "Delete bookmark"
+msgstr "Удалить закладку"
+
+#: templates/admin/base.html:200
+msgid "Are you sure want to delete this bookmark?"
+msgstr "Вы точно хотите удалить эту закладку?"
+
+#: templates/admin/base.html:226
+msgid "Documentation"
 msgstr ""
 
-#: templates/admin/change_form.html:40
+#: templates/admin/base.html:249
+msgid "Application page"
+msgstr "Страница приложения"
+
+#: templates/admin/base_site.html:3
+#, fuzzy
+#| msgid "Django irc channel"
+msgid "Django site admin"
+msgstr "IRC канал Django"
+
+#: templates/admin/change_form.html:35 templates/admin/object_history.html:10
 msgid "History"
 msgstr ""
 
-#: templates/admin/change_form.html:43
+#: templates/admin/change_form.html:38
 #: templates/admin/edit_inline/stacked.html:49
 #: templates/admin/edit_inline/tabular.html:45
 msgid "View on site"
 msgstr ""
 
-#: templates/admin/change_form.html:67
-#: templates/jet/dashboard/update_module.html:34
-msgid "General"
-msgstr "Общее"
-
 #: templates/admin/change_list.html:51
 #, python-format
 msgid "Add %(name)s"
 msgstr ""
 
 #: templates/admin/change_list.html:61 templates/admin/login.html:27
-#: templates/registration/password_change_form.html:26
+#: templates/registration/password_change_form.html:21
 msgid "Please correct the error below."
 msgstr ""
 
-#: templates/admin/change_list.html:61
-#: templates/admin/edit_inline/stacked.html:8
-#: templates/admin/edit_inline/tabular.html:10
-#: templates/admin/includes/fieldset.html:10 templates/admin/login.html:27
-#: templates/jet/dashboard/update_module.html:53
-#: templates/registration/password_change_form.html:26
-msgid "Please correct the errors below."
-msgstr ""
-
 #: templates/admin/change_list_results.html:17
 #, python-format
 msgid "Sorting priority: %(priority_number)s"
@@ -280,12 +651,6 @@ msgstr ""
 msgid "try to reset filters"
 msgstr "попробуйте сбросить фильтры"
 
-#: templates/admin/delete_confirmation.html:12
-#: templates/admin/related_widget_wrapper.html:24
-#: templates/admin/submit_line.html:11 templates/jet/dashboard/module.html:22
-msgid "Delete"
-msgstr ""
-
 #: templates/admin/delete_confirmation.html:18
 #, python-format
 msgid ""
@@ -349,29 +714,6 @@ msgid ""
 "following objects and their related items will be deleted:"
 msgstr ""
 
-#: templates/admin/edit_inline/stacked.html:21
-#: templates/admin/edit_inline/stacked.html:75
-#: templates/admin/edit_inline/tabular.html:100
-#: templates/admin/sidebar.html:77 templates/admin/sidebar.html.py:84
-#: templates/jet/dashboard/update_module.html:123
-msgid "Remove"
-msgstr ""
-
-#: templates/admin/edit_inline/stacked.html:44
-#: templates/admin/edit_inline/tabular.html:39
-#: templates/jet/dashboard/module.html:19
-#: templates/jet/dashboard/modules/app_list.html:19
-#: templates/jet/dashboard/modules/model_list.html:14 views.py:83
-msgid "Change"
-msgstr ""
-
-#: templates/admin/edit_inline/stacked.html:76
-#: templates/admin/edit_inline/tabular.html:99
-#: templates/jet/dashboard/update_module.html:124
-#, python-format
-msgid "Add another %(verbose_name)s"
-msgstr ""
-
 #: templates/admin/edit_inline/tabular.html:25
 msgid "Delete?"
 msgstr ""
@@ -385,6 +727,10 @@ msgstr ""
 msgid "Summary"
 msgstr ""
 
+#: templates/admin/index.html:56
+msgid "You don't have permission to edit anything."
+msgstr ""
+
 #: templates/admin/login.html:16
 msgid "<span class=\"bright\">Admin</span> Site"
 msgstr "Панель <span class=\"bright\">Администратора</span>"
@@ -397,13 +743,28 @@ msgstr ""
 msgid "Forgotten your password or username?"
 msgstr ""
 
-#: templates/admin/pagination.html:7 templates/admin/search_form.html:22
-msgid "Show all"
+#: templates/admin/object_history.html:21
+msgid "Date/time"
 msgstr ""
 
-#: templates/admin/pagination.html:20 templates/admin/submit_line.html:4
-#: templates/jet/dashboard/update_module.html:132
-msgid "Save"
+#: templates/admin/object_history.html:22
+msgid "User"
+msgstr ""
+
+#: templates/admin/object_history.html:23
+#, fuzzy
+#| msgid "Applications"
+msgid "Action"
+msgstr "Приложения"
+
+#: templates/admin/object_history.html:37
+msgid ""
+"This object doesn't have a change history. It probably wasn't added via this "
+"admin site."
+msgstr ""
+
+#: templates/admin/pagination.html:7 templates/admin/search_form.html:20
+msgid "Show all"
 msgstr ""
 
 #: templates/admin/related_widget_wrapper.html:8
@@ -421,11 +782,11 @@ msgstr ""
 msgid "Delete selected %(model)s"
 msgstr ""
 
-#: templates/admin/search_form.html:8 templates/admin/search_form.html:19
+#: templates/admin/search_form.html:6 templates/admin/search_form.html:17
 msgid "Search"
 msgstr ""
 
-#: templates/admin/search_form.html:22
+#: templates/admin/search_form.html:20
 #, python-format
 msgid "%(counter)s result"
 msgid_plural "%(counter)s results"
@@ -433,35 +794,11 @@ msgstr[0] ""
 msgstr[1] ""
 msgstr[2] ""
 
-#: templates/admin/search_form.html:22
+#: templates/admin/search_form.html:20
 #, python-format
 msgid "%(full_result_count)s total"
 msgstr ""
 
-#: templates/admin/sidebar.html:12
-msgid "View site"
-msgstr ""
-
-#: templates/admin/sidebar.html:52 templates/admin/sidebar.html.py:69
-msgid "Add bookmark"
-msgstr "Добавить закладку"
-
-#: templates/admin/sidebar.html:65
-msgid "Delete bookmark"
-msgstr "Удалить закладку"
-
-#: templates/admin/sidebar.html:66
-msgid "Are you sure want to delete this bookmark?"
-msgstr "Вы точно хотите удалить эту закладку?"
-
-#: templates/admin/sidebar.html:93
-msgid "Documentation"
-msgstr ""
-
-#: templates/admin/sidebar.html:113
-msgid "Application page"
-msgstr "Страница приложения"
-
 #: templates/admin/submit_line.html:5
 msgid "Save as new"
 msgstr ""
@@ -474,44 +811,6 @@ msgstr ""
 msgid "Save and continue editing"
 msgstr ""
 
-#: templates/jet/dashboard/dashboard.html:17
-msgid "Delete widget"
-msgstr "Удалить виджет"
-
-#: templates/jet/dashboard/dashboard.html:18
-msgid "Are you sure want to delete this widget?"
-msgstr "Вы точно хотите удалить этот виджет?"
-
-#: templates/jet/dashboard/dashboard_tools.html:7
-msgid "widgets"
-msgstr "виджеты"
-
-#: templates/jet/dashboard/dashboard_tools.html:8
-msgid "available"
-msgstr "доступные"
-
-#: templates/jet/dashboard/dashboard_tools.html:13
-msgid "inititals"
-msgstr "изначальные"
-
-#: templates/jet/dashboard/modules/app_list.html:6
-#, python-format
-msgid "Models in the %(name)s application"
-msgstr ""
-
-#: templates/jet/dashboard/modules/feed.html:13
-#: templates/jet/dashboard/modules/link_list.html:26
-msgid "Nothing to show"
-msgstr "Содержимое отсутствует"
-
-#: templates/jet/dashboard/modules/recent_actions.html:6
-msgid "None available"
-msgstr ""
-
-#: templates/jet/dashboard/modules/recent_actions.html:26
-msgid "Unknown content"
-msgstr ""
-
 #: templates/registration/logged_out.html:9
 msgid "Thanks for spending some quality time with the Web site today."
 msgstr ""
@@ -521,7 +820,7 @@ msgid "Log in again"
 msgstr ""
 
 #: templates/registration/password_change_done.html:7
-#: templates/registration/password_change_form.html:12
+#: templates/registration/password_change_form.html:7
 msgid "Password change"
 msgstr ""
 
@@ -529,24 +828,12 @@ msgstr ""
 msgid "Your password was changed."
 msgstr ""
 
-#: templates/registration/password_change_form.html:30
+#: templates/registration/password_change_form.html:25
 msgid ""
 "Please enter your old password, for security's sake, and then enter your new "
 "password twice so we can verify you typed it in correctly."
 msgstr ""
 
-#: templates/registration/password_change_form.html:55
+#: templates/registration/password_change_form.html:50
 msgid "Change my password"
 msgstr ""
-
-#: views.py:18
-msgid "Widget was successfully updated"
-msgstr "Виджет успешно изменен"
-
-#: views.py:87 views.py:88
-msgid "Items"
-msgstr "Элементы"
-
-#: views.py:195
-msgid "Widget has been successfully added"
-msgstr "Виджет успешно добавлен"

+ 17 - 0
jet/migrations/0002_delete_userdashboardmodule.py

@@ -0,0 +1,17 @@
+# -*- coding: utf-8 -*-
+from __future__ import unicode_literals
+
+from django.db import models, migrations
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('jet', '0001_initial'),
+    ]
+
+    operations = [
+        migrations.DeleteModel(
+            name='UserDashboardModule',
+        ),
+    ]

+ 0 - 50
jet/models.py

@@ -37,53 +37,3 @@ class PinnedApplication(models.Model):
     def __str__(self):
         return self.app_label
 
-
-@python_2_unicode_compatible
-class UserDashboardModule(models.Model):
-    title = models.CharField(verbose_name=_('Title'), max_length=255)
-    module = models.CharField(verbose_name=_('module'), max_length=255)
-    app_label = models.CharField(verbose_name=_('application name'), max_length=255, null=True, blank=True)
-    user = models.PositiveIntegerField(verbose_name=_('user'))
-    column = models.PositiveIntegerField(verbose_name=_('column'))
-    order = models.IntegerField(verbose_name=_('order'))
-    settings = models.TextField(verbose_name=_('settings'), default='', blank=True)
-    children = models.TextField(verbose_name=_('children'), default='', blank=True)
-    collapsed = models.BooleanField(verbose_name=_('collapsed'), default=False)
-
-    class Meta:
-        verbose_name = _('user dashboard module')
-        verbose_name_plural = _('user dashboard modules')
-        ordering = ('column', 'order')
-
-    def __str__(self):
-        return self.module
-
-    def load_module(self):
-        try:
-            package, module_name = self.module.rsplit('.', 1)
-            package = import_module(package)
-            module = getattr(package, module_name)
-
-            return module
-        except AttributeError:
-            return None
-
-    def pop_settings(self, pop_settings):
-        settings = json.loads(self.settings)
-
-        for setting in pop_settings:
-            if setting in settings:
-                settings.pop(setting)
-
-        self.settings = json.dumps(settings, cls=LazyDateTimeEncoder)
-        self.save()
-
-    def update_settings(self, update_settings):
-        settings = json.loads(self.settings)
-
-        settings.update(update_settings)
-
-        self.settings = json.dumps(settings, cls=LazyDateTimeEncoder)
-        self.save()
-
-

+ 0 - 4
jet/settings.py

@@ -2,7 +2,3 @@ from django.conf import settings
 
 # Theme
 JET_THEME = getattr(settings, 'JET_THEME', 'default')
-
-# Dashboard
-JET_INDEX_DASHBOARD = getattr(settings, 'JET_INDEX_DASHBOARD', 'jet.dashboard.DefaultIndexDashboard')
-JET_APP_INDEX_DASHBOARD = getattr(settings, 'JET_APP_INDEX_DASHBOARD', 'jet.dashboard.DefaultAppIndexDashboard')

+ 7 - 3
jet/static/jet/css/_content.scss

@@ -4,6 +4,10 @@
   background-color: $background-color;
 }
 
+.dashboard #content {
+  width: 500px;
+}
+
 .small {
   font-size: 12px;
 }
@@ -72,10 +76,10 @@ ul.object-tools {
   }
 }
 
-.context-sidebar {
+.content-sidebar {
   float: right;
-  margin-left: 20px;
-  max-width: 33%;
+  width: 18em;
+  margin: 0 20px;
 }
 
 .dashboard .module table td a {

+ 6 - 3
jet/static/jet/css/themes/default/base.css

@@ -4595,6 +4595,9 @@ table#change-history {
 .content {
   background-color: #ecf2f6; }
 
+.dashboard #content {
+  width: 500px; }
+
 .small, .module .form-row .help, .module .form-row .errorlist, .changeform .tabular.inline-related .module .errorlist, .login-form .form-row .errorlist {
   font-size: 12px; }
 
@@ -4647,10 +4650,10 @@ ul.object-tools {
       margin-top: 0;
       line-height: normal; }
 
-.context-sidebar {
+.content-sidebar {
   float: right;
-  margin-left: 20px;
-  max-width: 33%; }
+  width: 18em;
+  margin: 0 20px; }
 
 .dashboard .module table td a {
   display: inline !important; }

File diff suppressed because it is too large
+ 0 - 0
jet/static/jet/css/themes/default/base.css.map


+ 6 - 3
jet/static/jet/css/themes/green/base.css

@@ -4626,6 +4626,9 @@ table#change-history {
 .content {
   background-color: #eff6f5; }
 
+.dashboard #content {
+  width: 500px; }
+
 .small, .module .form-row .help, .module .form-row .errorlist, .changeform .tabular.inline-related .module .errorlist, .login-form .form-row .errorlist {
   font-size: 12px; }
 
@@ -4678,10 +4681,10 @@ ul.object-tools {
       margin-top: 0;
       line-height: normal; }
 
-.context-sidebar {
+.content-sidebar {
   float: right;
-  margin-left: 20px;
-  max-width: 33%; }
+  width: 18em;
+  margin: 0 20px; }
 
 .dashboard .module table td a {
   display: inline !important; }

File diff suppressed because it is too large
+ 0 - 0
jet/static/jet/css/themes/green/base.css.map


+ 6 - 4
jet/templates/admin/base.html

@@ -1,5 +1,5 @@
 {% load i18n admin_static jet_tags %}
-{% get_current_language_bidi as LANGUAGE_BIDI %}{% format_current_language LANGUAGE_CODE as LANGUAGE_CODE %}{% get_current_theme as THEME %}{% get_current_language as LANGUAGE_CODE %}
+{% get_current_language as LANGUAGE_CODE %}{% get_current_language_bidi as LANGUAGE_BIDI %}{% format_current_language LANGUAGE_CODE as LANGUAGE_CODE %}{% get_current_theme as THEME %}
 {% block html %}<!DOCTYPE html>
 <html lang="{{ LANGUAGE_CODE|default:"en-us" }}" {% if LANGUAGE_BIDI %}dir="rtl"{% endif %}>
 <head>
@@ -110,14 +110,16 @@
                     {% endif %}
                 {% endblock messages %}
 
+            <div class="content-sidebar">
+                        {% block sidebar %}{% endblock %}
+                    </div>
+
                 <div id="content" class="cf {% block coltype %}colM{% endblock %}">
                     {% block pretitle %}{% endblock %}
                     {% if is_popup %}
                         {% block content_title %}{% if title %}<h1>{{ title }}</h1>{% endif %}{% endblock %}
                     {% endif %}
-                    <div class="context-sidebar">
-                        {% block sidebar %}{% endblock %}
-                    </div>
+
                     {% block content %}
                     {% block object-tools %}{% endblock %}
                     {{ content }}

+ 101 - 26
jet/templates/admin/index.html

@@ -1,37 +1,112 @@
 {% extends "admin/base_site.html" %}
-{% load i18n admin_static jet_tags static %}
+{% load i18n admin_static log %}
 
-{% block html %}
-    {% get_dashboard 'index' as dashboard %}
-    {{ block.super }}
-{% endblock %}
+{% block extrastyle %}{{ block.super }}<link rel="stylesheet" type="text/css" href="{% static "admin/css/dashboard.css" %}" />{% endblock %}
 
-{% block extrastyle %}
-    {{ block.super }}
-    <link rel="stylesheet" type="text/css" href="{% static "admin/css/dashboard.css" %}" />
+{% block coltype %}colMS{% endblock %}
 
-    {% for css in dashboard.media.css %}
-        <link href="{% static css %}" rel="stylesheet" />
-    {% endfor %}
-{% endblock %}
+{% block bodyclass %}{{ block.super }} dashboard{% endblock %}
+
+{% block content %}
+    <div class="dashboard-item">
+        <div class="dashboard-item-header">
+            <span class="dashboard-item-header-title">
+                {% trans "Applications" %}
+            </span>
+        </div>
+        <div class="dashboard-item-content">
+            {% if app_list %}
+                <ul>
+                    {% for app in app_list %}
+                        <li class="contrast">
+                            {% if app.name != app.app_label|capfirst|escape %}
+                                <a href="{{ app.app_url }}" title="{% blocktrans with name=app.name %}Models in the {{ name }} application{% endblocktrans %}">{{ app.name }}</a>
+                            {% else %}
+                                {% trans app.app_label as app_label %}
+                                <a href="{{ app.app_url }}" title="{% blocktrans with name=app_label %}Models in the {{ name }} application{% endblocktrans %}">{{ app_label }}</a>
+                            {% endif %}
+                        </li>
+
+                        {% for model in app.models %}
+                            <li>
+                                <span class="float-right">
+                                    {% if model.add_url %}
+                                        <a href="{{ model.add_url }}" class="addlink" title="{% trans 'Add' %}"><span class="icon-add3"></span></a>
+                                    {% else %}
+                                        &nbsp;
+                                    {% endif %}
 
-{% block extrahead %}
-    {{ block.super }}
-    {% for js in dashboard.media.js %}
-        <script src="{% static js %}"></script>
-    {% endfor %}
+                                    {% if model.admin_url %}
+                                        <a href="{{ model.admin_url }}" class="changelink" title="{% trans 'Change' %}"><span class="icon-edit"></span></a>
+                                    {% else %}
+                                        &nbsp;
+                                    {% endif %}
+                                </span>
+
+                                {% if model.admin_url %}
+                                    <a href="{{ model.admin_url }}">{{ model.name }}</a>
+                                {% else %}
+                                    {{ model.name }}
+                                {% endif %}
+                            </li>
+                        {% endfor %}
+                    {% endfor %}
+                </ul>
+            {% else %}
+                <p>{% trans "You don't have permission to edit anything." %}</p>
+            {% endif %}
+        </div>
+    </div>
 {% endblock %}
 
-{% block coltype %}colMS{% endblock %}
+{% block sidebar %}
+    {% get_admin_log 10 as admin_log for_user user %}
 
-{% block bodyclass %}{{ block.super }} dashboard{% endblock %}
+    <div class="dashboard-item">
+        <div class="dashboard-item-header">
+            <span class="dashboard-item-header-title">
+                {% trans 'Recent Actions' %}
+            </span>
+        </div>
+        <div class="dashboard-item-content">
+            <ul>
+                {% if not admin_log %}
+                    <li>
+                        {% trans 'None available' %}
+                    </li>
+                {% else %}
+                    {% for entry in admin_log %}
+                        <li class="nowrap">
+                            <span class="float-right">
+                                <span class="icon-user tooltip" title="{{ entry.user }}"></span>
+                                <span class="icon-clock tooltip" title="{{ entry.action_time }}"></span>
+                            </span>
 
-{% block sidebar %}{% endblock %}
+                            {% if entry.is_addition %}
+                                <span class="icon-add3"></span>
+                            {% endif %}
+                            {% if entry.is_change %}
+                                <span class="icon-edit"></span>
+                            {% endif %}
+                            {% if entry.is_deletion %}
+                                <span class="icon-cross"></span>
+                            {% endif %}
 
-{% block top-right %}
-    {{ dashboard.render_tools }}
-{% endblock %}
+                            {% if entry.content_type %}
+                                <span class="mini quiet">{% filter capfirst %}{{ entry.content_type }}{% endfilter %}</span>
+                            {% else %}
+                                <span class="mini quiet">{% trans 'Unknown content' %}</span>
+                            {% endif %}
 
-{% block content %}
-    {{ dashboard.render }}
-{% endblock %}
+                            {% if entry.is_deletion or not entry.get_admin_url %}
+                                {{ entry.object_repr }}
+                            {% else %}
+                                <a href="{{ entry.get_admin_url }}">{{ entry.object_repr }}</a>
+                            {% endif %}
+                        </li>
+                    {% endfor %}
+                {% endif %}
+            </ul>
+        </div>
+    </div>
+{% endblock %}

+ 1 - 8
jet/templatetags/jet_tags.py

@@ -8,7 +8,7 @@ from django.template import loader, Context
 from jet import settings
 from jet.models import Bookmark, PinnedApplication
 import re
-from jet.utils import get_app_list, get_model_instance_label, get_current_dashboard
+from jet.utils import get_app_list, get_model_instance_label
 
 register = template.Library()
 
@@ -218,13 +218,6 @@ def jet_add_preserved_filters(context, url, popup=False, to_field=None):
         return url
 
 
-@register.assignment_tag(takes_context=True)
-def get_dashboard(context, location):
-    dashboard_cls = get_current_dashboard(location)
-    dashboard = dashboard_cls(context)
-    return dashboard
-
-
 @register.filter()
 def if_onetoone(formset):
     return getattr(formset, 'fk') and isinstance(formset.fk, OneToOneField)

+ 2 - 2
jet/tests/dashboard.py

@@ -1,5 +1,5 @@
-from jet import modules
-from jet.dashboard import Dashboard
+from jet.dashboard import modules
+from jet.dashboard.dashboard import Dashboard
 
 
 class TestIndexDashboard(Dashboard):

+ 1 - 0
jet/tests/settings.py

@@ -9,6 +9,7 @@ DEBUG_PROPAGATE_EXCEPTIONS = True
 ROOT_URLCONF = 'jet.tests.urls'
 
 INSTALLED_APPS = (
+    'jet.dashboard',
     'jet',
     'django.contrib.auth',
     'django.contrib.contenttypes',

+ 4 - 4
jet/tests/test_dashboard.py

@@ -1,7 +1,7 @@
 from django.contrib.auth.models import User
 from django.test import TestCase, Client
-from jet.modules import LinkList, RecentActions
-from jet.models import UserDashboardModule
+from jet.dashboard.modules import LinkList, RecentActions
+from jet.dashboard.models import UserDashboardModule
 from jet.tests.dashboard import TestIndexDashboard
 
 
@@ -25,7 +25,7 @@ class DashboardTestCase(TestCase):
     def _init_dashboard(self):
         UserDashboardModule.objects.create(
             title='',
-            module='jet.modules.LinkList',
+            module='jet.dashboard.modules.LinkList',
             app_label=None,
             user=self.admin_user.pk,
             column=0,
@@ -33,7 +33,7 @@ class DashboardTestCase(TestCase):
         )
         UserDashboardModule.objects.create(
             title='',
-            module='jet.modules.RecentActions',
+            module='jet.dashboard.modules.RecentActions',
             app_label=None,
             user=self.admin_user.pk,
             column=0,

+ 15 - 14
jet/tests/test_views.py

@@ -2,8 +2,9 @@ import json
 from django.contrib.auth.models import User
 from django.core.urlresolvers import reverse
 from django.test import TestCase, Client
-from jet.modules import LinkList
-from jet.models import UserDashboardModule, Bookmark
+from jet.dashboard.modules import LinkList
+from jet.models import Bookmark
+from jet.dashboard.models import UserDashboardModule
 
 
 class ViewsTestCase(TestCase):
@@ -24,7 +25,7 @@ class ViewsTestCase(TestCase):
         new_layout = 'stacked'
         module = UserDashboardModule.objects.create(
             title=title,
-            module='jet.modules.LinkList',
+            module='jet.dashboard.modules.LinkList',
             app_label=None,
             user=self.admin_user.pk,
             column=0,
@@ -33,7 +34,7 @@ class ViewsTestCase(TestCase):
             children='[]'
         )
 
-        response = self.admin.get(reverse('jet:update_module', kwargs={'pk': module.pk}))
+        response = self.admin.get(reverse('jet-dashboard:update_module', kwargs={'pk': module.pk}))
         self.assertEqual(response.status_code, 200)
         self.assertTrue(response.context['module'] is not None)
         self.assertTrue(isinstance(response.context['module'], LinkList))
@@ -56,7 +57,7 @@ class ViewsTestCase(TestCase):
             '_save': 'Save'
         }
 
-        self.admin.post(reverse('jet:update_module', kwargs={'pk': module.pk}), post)
+        self.admin.post(reverse('jet-dashboard:update_module', kwargs={'pk': module.pk}), post)
         self.assertEqual(response.status_code, 200)
         module = UserDashboardModule.objects.get(pk=module.pk)
         settings = json.loads(module.settings)
@@ -115,7 +116,7 @@ class ViewsTestCase(TestCase):
         app_label = None
         module_0 = UserDashboardModule.objects.create(
             title='',
-            module='jet.modules.LinkList',
+            module='jet.dashboard.modules.LinkList',
             app_label=app_label,
             user=self.admin_user.pk,
             column=0,
@@ -123,13 +124,13 @@ class ViewsTestCase(TestCase):
         )
         module_1 = UserDashboardModule.objects.create(
             title='',
-            module='jet.modules.LinkList',
+            module='jet.dashboard.modules.LinkList',
             app_label=app_label,
             user=self.admin_user.pk,
             column=0,
             order=1
         )
-        response = self.admin.post(reverse('jet:update_dashboard_modules'), {
+        response = self.admin.post(reverse('jet-dashboard:update_dashboard_modules'), {
             'app_label': '',
             'modules': json.dumps([
                 {'id': module_0.pk, 'column': 0, 'order': 1},
@@ -151,7 +152,7 @@ class ViewsTestCase(TestCase):
         module_1.delete()
 
     def test_add_user_dashboard_module_view(self):
-        response = self.admin.post(reverse('jet:add_user_dashboard_module'), {
+        response = self.admin.post(reverse('jet-dashboard:add_user_dashboard_module'), {
             'app_label': '',
             'type': 'available_children',
             'module': 0
@@ -167,13 +168,13 @@ class ViewsTestCase(TestCase):
     def test_update_dashboard_module_collapse_view(self):
         module = UserDashboardModule.objects.create(
             title='',
-            module='jet.modules.LinkList',
+            module='jet.dashboard.modules.LinkList',
             app_label=None,
             user=self.admin_user.pk,
             column=0,
             order=0
         )
-        response = self.admin.post(reverse('jet:update_dashboard_module_collapse'), {
+        response = self.admin.post(reverse('jet-dashboard:update_dashboard_module_collapse'), {
             'id': module.pk, 'collapsed': True
         })
         self.assertEqual(response.status_code, 200)
@@ -182,7 +183,7 @@ class ViewsTestCase(TestCase):
         self.assertTrue(response['collapsed'])
 
         module = UserDashboardModule.objects.get(pk=module.pk)
-        response = self.admin.post(reverse('jet:update_dashboard_module_collapse'), {
+        response = self.admin.post(reverse('jet-dashboard:update_dashboard_module_collapse'), {
             'id': module.pk, 'collapsed': False
         })
         self.assertEqual(response.status_code, 200)
@@ -195,13 +196,13 @@ class ViewsTestCase(TestCase):
     def test_remove_dashboard_module_view(self):
         module = UserDashboardModule.objects.create(
             title='',
-            module='jet.modules.LinkList',
+            module='jet.dashboard.modules.LinkList',
             app_label=None,
             user=self.admin_user.pk,
             column=0,
             order=0
         )
-        response = self.admin.post(reverse('jet:remove_dashboard_module'), {'id': module.pk})
+        response = self.admin.post(reverse('jet-dashboard:remove_dashboard_module'), {'id': module.pk})
         self.assertEqual(response.status_code, 200)
         response = json.loads(response.content.decode())
         self.assertFalse(response['error'])

+ 1 - 0
jet/tests/urls.py

@@ -6,6 +6,7 @@ admin.autodiscover()
 urlpatterns = patterns(
     '',
     url(r'^jet/', include('jet.urls', 'jet')),
+    url(r'^jet/dashboard/', include('jet.dashboard.urls', 'jet-dashboard')),
     url(r'^admin/doc/', include('django.contrib.admindocs.urls')),
     url(r'^admin/', include(admin.site.urls)),
 )

+ 1 - 36
jet/urls.py

@@ -1,17 +1,9 @@
 from django.conf.urls import patterns, url
 from django.views.i18n import javascript_catalog
-from jet import dashboard
-from jet.views import add_bookmark_view, remove_bookmark_view, toggle_application_pin_view, \
-    update_dashboard_modules_view, add_user_dashboard_module_view, update_dashboard_module_collapse_view, \
-    remove_dashboard_module_view, UpdateDashboardModuleView, load_dashboard_module_view, model_lookup_view
+from jet.views import add_bookmark_view, remove_bookmark_view, toggle_application_pin_view, model_lookup_view
 
 urlpatterns = patterns(
     '',
-    url(
-        r'^module/(?P<pk>\d+)/$',
-        UpdateDashboardModuleView.as_view(),
-        name='update_module'
-    ),
     url(
         r'^add_bookmark/$',
         add_bookmark_view,
@@ -27,31 +19,6 @@ urlpatterns = patterns(
         toggle_application_pin_view,
         name='toggle_application_pin'
     ),
-    url(
-        r'^update_dashboard_modules/$',
-        update_dashboard_modules_view,
-        name='update_dashboard_modules'
-    ),
-    url(
-        r'^add_user_dashboard_module/$',
-        add_user_dashboard_module_view,
-        name='add_user_dashboard_module'
-    ),
-    url(
-        r'^update_dashboard_module_collapse/$',
-        update_dashboard_module_collapse_view,
-        name='update_dashboard_module_collapse'
-    ),
-    url(
-        r'^remove_dashboard_module/$',
-        remove_dashboard_module_view,
-        name='remove_dashboard_module'
-    ),
-    url(
-        r'^load_dashboard_module/(?P<pk>\d+)/$',
-        load_dashboard_module_view,
-        name='load_dashboard_module'
-    ),
     url(
         r'^model_lookup/$',
         model_lookup_view,
@@ -64,5 +31,3 @@ urlpatterns = patterns(
         name='jsi18n'
     ),
 )
-
-urlpatterns += dashboard.urls.get_urls()

+ 0 - 15
jet/utils.py

@@ -59,21 +59,6 @@ def get_admin_site_name(context):
     return get_admin_site(context).name
 
 
-def get_current_dashboard(location):
-    if location == 'index':
-        path = settings.JET_INDEX_DASHBOARD
-    elif location == 'app_index':
-        path = settings.JET_APP_INDEX_DASHBOARD
-    else:
-        raise ValueError('Unknown dashboard location: %s' % location)
-
-    module, cls = path.rsplit('.', 1)
-    module = import_module(module)
-    index_dashboard_cls = getattr(module, cls)
-
-    return index_dashboard_cls
-
-
 class LazyDateTimeEncoder(json.JSONEncoder):
     def default(self, obj):
         if isinstance(obj, datetime.datetime) or isinstance(obj, datetime.date):

+ 3 - 212
jet/views.py

@@ -1,131 +1,7 @@
-from django.contrib import messages
-from django.core.urlresolvers import reverse
-from django.forms.formsets import formset_factory
 from django.views.decorators.http import require_POST, require_GET
-from jet.forms import AddBookmarkForm, RemoveBookmarkForm, ToggleApplicationPinForm, UpdateDashboardModulesForm, \
-    AddUserDashboardModuleForm, UpdateDashboardModuleCollapseForm, RemoveDashboardModuleForm, ModelLookupForm
-from jet.models import Bookmark, UserDashboardModule
-from jet.utils import JsonResponse, get_app_list, SuccessMessageMixin
-from django.views.generic import UpdateView
-from django.utils.translation import ugettext_lazy as _
-
-
-class UpdateDashboardModuleView(SuccessMessageMixin, UpdateView):
-    model = UserDashboardModule
-    fields = ('title',)
-    template_name = 'jet/dashboard/update_module.html'
-    success_message = _('Widget was successfully updated')
-    object = None
-    module = None
-
-    def get_success_url(self):
-        if self.object.app_label:
-            return reverse('admin:app_list', kwargs={'app_label': self.object.app_label})
-        else:
-            return reverse('admin:index')
-
-    def get_module(self):
-        object = self.object if getattr(self, 'object', None) is not None else self.get_object()
-        return object.load_module()
-
-    def get_settings_form_kwargs(self):
-        kwargs = {
-            'initial': self.module.settings
-        }
-
-        if self.request.method in ('POST', 'PUT'):
-            kwargs.update({
-                'data': self.request.POST,
-                'files': self.request.FILES,
-            })
-        return kwargs
-
-    def get_settings_form(self):
-        if self.module.settings_form:
-            form = self.module.settings_form(**self.get_settings_form_kwargs())
-            if hasattr(form, 'set_module'):
-                form.set_module(self.module)
-            return form
-
-    def get_children_formset_kwargs(self):
-        kwargs = {
-            'initial': self.module.children,
-            'prefix': 'children',
-        }
-
-        if self.request.method in ('POST', 'PUT'):
-            kwargs.update({
-                'data': self.request.POST,
-                'files': self.request.FILES,
-            })
-        return kwargs
-
-    def get_children_formset(self):
-        if self.module.child_form:
-            return formset_factory(self.module.child_form, can_delete=True, extra=1)(**self.get_children_formset_kwargs())
-
-    def clean_children_data(self, children):
-        children = list(filter(
-            lambda item: isinstance(item, dict) and item and item.get('DELETE') is not True,
-            children
-        ))
-        for item in children:
-            item.pop('DELETE')
-        return children
-
-    def get_current_app(self):
-        app_list = get_app_list({'request': self.request})
-
-        for app in app_list:
-            if app.get('app_label', app.get('name')) == self.object.app_label:
-                return app
-
-    def get_context_data(self, **kwargs):
-        data = super(UpdateDashboardModuleView, self).get_context_data(**kwargs)
-        data['title'] = _('Change')
-        data['module'] = self.module
-        data['settings_form'] = self.get_settings_form()
-        data['children_formset'] = self.get_children_formset()
-        data['child_name'] = self.module.child_name if self.module.child_name else _('Items')
-        data['child_name_plural'] = self.module.child_name_plural if self.module.child_name_plural else _('Items')
-        data['app'] = self.get_current_app()
-        return data
-
-    def dispatch(self, request, *args, **kwargs):
-        self.object = self.get_object()
-        self.module = self.get_module()(model=self.object)
-        return super(UpdateDashboardModuleView, self).dispatch(request, *args, **kwargs)
-
-    def post(self, request, *args, **kwargs):
-        settings_form = self.get_settings_form()
-        children_formset = self.get_children_formset()
-
-        data = request.POST.copy()
-
-        if settings_form:
-            if settings_form.is_valid():
-                settings = settings_form.cleaned_data
-                data['settings'] = self.module.dump_settings(settings)
-            else:
-                return self.form_invalid(self.get_form(self.get_form_class()))
-
-        if children_formset:
-            if children_formset.is_valid():
-                self.module.children = self.clean_children_data(children_formset.cleaned_data)
-                data['children'] = self.module.dump_children()
-            else:
-                return self.form_invalid(self.get_form(self.get_form_class()))
-
-        request.POST = data
-
-        return super(UpdateDashboardModuleView, self).post(request, *args, **kwargs)
-
-    def form_valid(self, form):
-        if 'settings' in form.data:
-            form.instance.settings = form.data['settings']
-        if 'children' in form.data:
-            form.instance.children = form.data['children']
-        return super(UpdateDashboardModuleView, self).form_valid(form)
+from jet.forms import AddBookmarkForm, RemoveBookmarkForm, ToggleApplicationPinForm, ModelLookupForm
+from jet.models import Bookmark
+from jet.utils import JsonResponse
 
 
 @require_POST
@@ -174,91 +50,6 @@ def toggle_application_pin_view(request):
     return JsonResponse(result)
 
 
-@require_POST
-def update_dashboard_modules_view(request):
-    result = {'error': False}
-    form = UpdateDashboardModulesForm(request, request.POST)
-
-    if form.is_valid():
-        form.save()
-    else:
-        result['error'] = True
-
-    return JsonResponse(result)
-
-
-@require_POST
-def add_user_dashboard_module_view(request):
-    result = {'error': False}
-    form = AddUserDashboardModuleForm(request, request.POST)
-
-    if form.is_valid():
-        module = form.save()
-        result['id'] = module.pk
-        messages.success(request, _('Widget has been successfully added'))
-
-        if module.app_label:
-            result['success_url'] = reverse('admin:app_list', kwargs={'app_label': module.app_label})
-        else:
-            result['success_url'] = reverse('admin:index')
-    else:
-        result['error'] = True
-
-    return JsonResponse(result)
-
-
-@require_POST
-def update_dashboard_module_collapse_view(request):
-    result = {'error': False}
-
-    try:
-        instance = UserDashboardModule.objects.get(pk=request.POST.get('id'))
-        form = UpdateDashboardModuleCollapseForm(request, request.POST, instance=instance)
-
-        if form.is_valid():
-            module = form.save()
-            result['collapsed'] = module.collapsed
-        else:
-            result['error'] = True
-    except UserDashboardModule.DoesNotExist:
-        result['error'] = True
-
-    return JsonResponse(result)
-
-
-@require_POST
-def remove_dashboard_module_view(request):
-    result = {'error': False}
-
-    try:
-        instance = UserDashboardModule.objects.get(pk=request.POST.get('id'))
-        form = RemoveDashboardModuleForm(request, request.POST, instance=instance)
-
-        if form.is_valid():
-            form.save()
-        else:
-            result['error'] = True
-    except UserDashboardModule.DoesNotExist:
-        result['error'] = True
-
-    return JsonResponse(result)
-
-
-@require_GET
-def load_dashboard_module_view(request, pk):
-    result = {'error': False}
-
-    try:
-        instance = UserDashboardModule.objects.get(pk=pk)
-        module_cls = instance.load_module()
-        module = module_cls(model=instance, context={'request': request})
-        result['html'] = module.render()
-    except UserDashboardModule.DoesNotExist:
-        result['error'] = True
-
-    return JsonResponse(result)
-
-
 @require_GET
 def model_lookup_view(request):
     result = {'error': False}

Some files were not shown because too many files changed in this diff