Browse Source

bug #15 - add dashboard/ root to the main controller, and associated template and methods in the dbapi

damien 11 years ago
parent
commit
575be7d06b

+ 12 - 0
pboard/pboard/controllers/root.py View File

@@ -90,6 +90,18 @@ class RootController(BaseController):
90 90
         flash(_('We hope to see you soon!'))
91 91
         redirect(came_from)
92 92
         
93
+    @expose('pboard.templates.dashboard')
94
+    @require(predicates.in_group('user', msg=l_('Please login to access this page')))
95
+    def dashboard(self):
96
+      loCurrentUser   = pld.PODStaticController.getCurrentUser()
97
+      loApiController = pld.PODUserFilteredApiController(loCurrentUser.user_id)
98
+
99
+      loLastModifiedNodes = loApiController.getLastModifiedNodes(10)
100
+      loWhatsHotNodes     = loApiController.getNodesByStatus('hot', 5)
101
+      loActionToDoNodes   = loApiController.getNodesByStatus('actiontodo', 5)
102
+      return dict(last_modified_nodes=loLastModifiedNodes, whats_hot_nodes=loWhatsHotNodes, action_to_do_nodes = loActionToDoNodes)
103
+
104
+
93 105
     @expose('pboard.templates.document')
94 106
     @require(predicates.in_group('user', msg=l_('Please login to access this page')))
95 107
     def document(self, node=0, came_from=lurl('/')):

+ 18 - 0
pboard/pboard/lib/dbapi.py View File

@@ -46,6 +46,7 @@ class PODUserFilteredApiController(object):
46 46
     self._iExtraUserIdList     = piExtraUserIdList
47 47
     self._iUserIdFilteringList = None
48 48
   
49
+
49 50
   def _getUserIdListForFiltering(self):
50 51
     if self._iUserIdFilteringList==None:
51 52
       self._iUserIdFilteringList = list()
@@ -54,6 +55,7 @@ class PODUserFilteredApiController(object):
54 55
         self._iUserIdFilteringList.append(liUserId)
55 56
     return self._iUserIdFilteringList
56 57
 
58
+
57 59
   def createNode(self):
58 60
     loNode          = pbmd.PBNode()
59 61
     loNode.owner_id = self._iCurrentUserId
@@ -62,12 +64,14 @@ class PODUserFilteredApiController(object):
62 64
   
63 65
     query.filter(User.name.in_(['ed', 'wendy', 'jack']))
64 66
 
67
+
65 68
   def createDummyNode(self):
66 69
     loNewNode = self.createNode()
67 70
     loNewNode.data_label   = 'New document'
68 71
     loNewNode.data_content = 'insert content...'
69 72
     return loNewNode
70 73
 
74
+
71 75
   def getNode(self, liNodeId):
72 76
     liOwnerIdList = self._getUserIdListForFiltering()
73 77
     if liNodeId==0:
@@ -75,6 +79,20 @@ class PODUserFilteredApiController(object):
75 79
     else:
76 80
       return DBSession.query(pbmd.PBNode).options(joinedload_all("_lAllChildren")).filter(pbmd.PBNode.node_id==liNodeId).filter(pbmd.PBNode.owner_id.in_(liOwnerIdList)).one()
77 81
 
82
+
83
+  def getLastModifiedNodes(self, piMaxNodeNb):
84
+    """
85
+    Returns a list of nodes order by modification time and limited to piMaxNodeNb nodes
86
+    """
87
+    liOwnerIdList = self._getUserIdListForFiltering()
88
+    return DBSession.query(pbmd.PBNode).options(joinedload_all("_lAllChildren")).filter(pbmd.PBNode.owner_id.in_(liOwnerIdList)).order_by(pbmd.PBNode.updated_at.desc()).limit(piMaxNodeNb).all()
89
+
90
+
91
+  def getNodesByStatus(self, psNodeStatus, piMaxNodeNb=5):
92
+    liOwnerIdList = self._getUserIdListForFiltering()
93
+    return DBSession.query(pbmd.PBNode).options(joinedload_all("_lAllChildren")).filter(pbmd.PBNode.owner_id.in_(liOwnerIdList)).filter(pbmd.PBNode.node_status==psNodeStatus).order_by(pbmd.PBNode.updated_at).limit(piMaxNodeNb).all()
94
+
95
+
78 96
   def buildTreeListForMenu(self):
79 97
     liOwnerIdList = self._getUserIdListForFiltering()
80 98
     

+ 18 - 2
pboard/pboard/model/data.py View File

@@ -263,8 +263,24 @@ class PBNode(DeclarativeBase):
263 263
     else:
264 264
       return laIconClass[self.node_type]
265 265
       
266
-      
267
-  def getFormattedDateTime(self, poDateTime, psDateTimeFormat = '%d/%m/%Y @ %H:%M'):
266
+  def getUserFriendlyNodeType(self):
267
+    laNodeTypesLng = dict()
268
+    laNodeTypesLng['node']   = 'Document' # FIXME - D.A. - 2013-11-14 - Make text translatable
269
+    laNodeTypesLng['folder'] = 'Document'
270
+    laNodeTypesLng['data']   = 'Document'
271
+
272
+    laNodeTypesLng['file']   = 'File'
273
+    laNodeTypesLng['event']  = 'Event'
274
+    laNodeTypesLng['contact'] = 'Contact'
275
+    laNodeTypesLng['comment'] = 'Comment'
276
+
277
+    if self.node_type==PBNodeType.Data and self.getStaticChildNb()>0:
278
+      return laNodeTypesLng['folder']
279
+    else:
280
+      return laNodeTypesLng[self.node_type]
281
+
282
+    
283
+  def getFormattedDateTime(self, poDateTime, psDateTimeFormat = '%d/%m/%Y ~ %H:%M'):
268 284
     return poDateTime.strftime(psDateTimeFormat)
269 285
 
270 286
   def getFormattedDate(self, poDateTime, psDateTimeFormat = '%d/%m/%Y'):

+ 109 - 0
pboard/pboard/templates/dashboard.mak View File

@@ -0,0 +1,109 @@
1
+<%inherit file="local:templates.master"/>
2
+<%namespace name="POD" file="pboard.templates.pod"/>
3
+
4
+<%def name="title()">
5
+pod > dashobard
6
+</%def>
7
+
8
+  <div class="row">
9
+    <div class="container-fluid">
10
+      <div class="row-fluid">
11
+        <div class="span6">
12
+          ## LEFT PANEL OF THE DASHBOARD
13
+          <div id='whats-hot-panel' class="well">
14
+            ## WHAT'S HOT PANEL
15
+            <h3><i class="fa fa-warning pod-red"></i> ${_("What's hot!")}</h3>
16
+            % if len(whats_hot_nodes)<=0:
17
+              <p>${_("No hot stuff for today.")}</p>
18
+            % else:
19
+              <ul>
20
+              % for node in whats_hot_nodes:
21
+                <li title="${node.data_label}">
22
+                  <i class="${node.getIconClass()}" title="${node.getUserFriendlyNodeType()}"></i> 
23
+                % if node.node_type=='data' or node.parent_id==None:
24
+                  <a href="${tg.url('/document/%i'%node.node_id)}">
25
+                % else:
26
+                  <a href="${tg.url('/document/%i#tab-%ss'%(node.parent_id, node.node_type))}">
27
+                % endif
28
+                    ${node.getTruncatedLabel(70)}
29
+                  </a>
30
+                    <span title="${_('last modification')}" class="pull-right label">
31
+                     ${node.getFormattedDateTime(node.updated_at)}
32
+                    </span>
33
+                </li>
34
+              % endfor
35
+              </ul>
36
+            % endif
37
+            ## WHAT'S HOT PANEL [END]
38
+          </div>
39
+
40
+          <div id='action-to-do-documents-panel' class="well">
41
+            ## DOCUMENTS REQUIRING ACTIONS PANEL
42
+            <h3><i class="pod-blue fa fa-gears"></i> ${_("Actions to do")}</h3>
43
+            % if len(action_to_do_nodes)<=0:
44
+              <p>${_("No document requiring action.")}</p>
45
+            % else:
46
+              <ul>
47
+              % for node in action_to_do_nodes:
48
+                <li title="${node.data_label}">
49
+                  <i class="${node.getIconClass()}" title="${node.getUserFriendlyNodeType()}"></i> 
50
+                % if node.node_type=='data' or node.parent_id==None:
51
+                  <a href="${tg.url('/document/%i'%node.node_id)}">
52
+                % else:
53
+                  <a href="${tg.url('/document/%i#tab-%ss'%(node.parent_id, node.node_type))}">
54
+                % endif
55
+                    ${node.getTruncatedLabel(70)}
56
+                  </a>
57
+                    <span title="${_('last modification')}" class="pull-right label">
58
+                     ${node.getFormattedDateTime(node.updated_at)}
59
+                    </span>
60
+                </li>
61
+              % endfor
62
+              </ul>
63
+            % endif
64
+            ## DOCUMENTS REQUIRING ACTIONS PANEL [END]
65
+          </div>
66
+
67
+          ## LEFT PANEL OF THE DASHBOARD [END]
68
+        </div>
69
+        <div class="span6">
70
+          ## RIGHT PANEL OF THE DASHBOARD
71
+          <div id='last-modified-documents-panel' class="well">
72
+            <h3><i style="color: #999;" class="fa fa-clock-o"></i> ${_("Latest operations")}</h3>
73
+            % if len(last_modified_nodes)<=0:
74
+              <p>${_("No activity found")}</p>
75
+            % else:
76
+              <table class="table table-condensed table-hover">
77
+              % for node in last_modified_nodes:
78
+                <tr title="${node.data_label}">
79
+                  <td>${node.getFormattedDateTime(node.updated_at)}</td>
80
+                  <td title="${node.getUserFriendlyNodeType()}">
81
+                    <i class="${node.getIconClass()}"></i> 
82
+                  </td>
83
+                  <td>
84
+                  % if node.node_type=='data' or node.parent_id==None:
85
+                    <a href="${tg.url('/document/%i'%node.node_id)}">
86
+                  % else:
87
+                    <a href="${tg.url('/document/%i#tab-%ss'%(node.parent_id, node.node_type))}">
88
+                  % endif
89
+                      ${node.getTruncatedLabel(35)}
90
+                    </a>
91
+                  </td>
92
+                  <td>
93
+                  % if node.updated_at==node.created_at:
94
+                    <span class="label label-success">${_("created")}</span>
95
+                  % else:
96
+                    <span class="label label-info">${_("updated")}</span>
97
+                  % endif
98
+                  </td>
99
+                </tr>
100
+              % endfor
101
+              </table>
102
+            % endif
103
+          </div>
104
+          ## RIGHT PANEL OF THE DASHBOARD [END]
105
+        </div>
106
+      </div>
107
+    </div>
108
+  </div>
109
+

+ 6 - 3
pboard/pboard/templates/master.mak View File

@@ -78,14 +78,17 @@ h3:Hover div.pod-toolbar {
78 78
   visibility: visible;
79 79
 }
80 80
 
81
+.pod-blue {color: #3a87ad !important; }
82
+.pod-red {color: #F00 !important; }
83
+
81 84
 body { padding-top: 60px; }
82 85
 @media screen and (max-width: 768px) {
83 86
     body { padding-top: 0px; }
84 87
 }
85 88
 
86
-ul.nav li.dropdown:hover > ul.dropdown-menu {
87
-    display: block;
88
-}
89
+## ul.nav li.dropdown:hover > ul.dropdown-menu {
90
+##     display: block;
91
+## }
89 92
 
90 93
     </style>
91 94
 </head>