Commit fd1aead11607134ab76006a892030e59eb87373d
Exists in
master
and in
3 other branches
Merge branch 'refactoring' of https://github.com/amadeusproject/amadeuslms into refactoring
Showing
12 changed files
with
719 additions
and
136 deletions
Show diff stats
... | ... | @@ -0,0 +1,296 @@ |
1 | +$('.pendencies-content').on('show.bs.collapse', function(e) { | |
2 | + if($(this).is(e.target)){ | |
3 | + var panel_id = $(this).data('id'), | |
4 | + pendencies = $(this).find('.pendencies'), | |
5 | + history = $(this).find('.history'), | |
6 | + btn = $(this).parent().find('.fa-angle-right'); | |
7 | + | |
8 | + btn = btn[0]; | |
9 | + | |
10 | + $(btn).switchClass("fa-angle-right", "fa-angle-down", 250, "easeInOutQuad"); | |
11 | + | |
12 | + getPendencies(panel_id); | |
13 | + } | |
14 | +}); | |
15 | + | |
16 | +$('.pendencies-content').on('hidden.bs.collapse', function(e) { | |
17 | + if($(this).is(e.target)){ | |
18 | + var btn = $(this).parent().find('.fa-angle-down'); | |
19 | + | |
20 | + btn = btn[0]; | |
21 | + | |
22 | + $(btn).switchClass("fa-angle-down", "fa-angle-right", 250, "easeInOutQuad"); | |
23 | + } | |
24 | +}); | |
25 | + | |
26 | +$('.pendencies-content').on('hidden.bs.collapse', function(e) { | |
27 | + if($(this).is(e.target)){ | |
28 | + var panel_id = $(this).data('id'), | |
29 | + pendencies = $(this).find('.pendencies'), | |
30 | + history = $(this).find('.history'), | |
31 | + p_holder = pendencies.find('.holder'), | |
32 | + h_holder = history.find('.holder'); | |
33 | + | |
34 | + | |
35 | + var p_items = pendencies.find('.pendencies-cards').children(":visible").length; | |
36 | + | |
37 | + if (p_items > 10) { | |
38 | + p_holder.jPages("destroy"); | |
39 | + } | |
40 | + | |
41 | + var h_items = history.find("#history_table_" + panel_id).children(":visible").length; | |
42 | + | |
43 | + if (h_items > 10) { | |
44 | + h_holder.jPages("destroy"); | |
45 | + } | |
46 | + } | |
47 | +}); | |
48 | + | |
49 | +function getPendencies(panel_id) { | |
50 | + var list = $("#pendencies_list_" + panel_id), | |
51 | + holder = list.parent().find('.holder'); | |
52 | + | |
53 | + if (list.children().length == 0) { | |
54 | + var url = list.parent().data('url'); | |
55 | + | |
56 | + $.ajax({ | |
57 | + url: url, | |
58 | + success: function (data) { | |
59 | + list.html(data); | |
60 | + | |
61 | + var items = list.children(":visible").length; | |
62 | + | |
63 | + if (items > 10) { | |
64 | + holder.jPages({ | |
65 | + containerID : "pendencies_list_" + panel_id, | |
66 | + perPage: 10, | |
67 | + previous: "«", | |
68 | + next: "»", | |
69 | + midRange: 5 | |
70 | + }); | |
71 | + } | |
72 | + | |
73 | + metaFunctions(); | |
74 | + } | |
75 | + }); | |
76 | + } else { | |
77 | + var items = list.children(":visible").length; | |
78 | + | |
79 | + if (items > 10) { | |
80 | + holder.jPages({ | |
81 | + containerID : "pendencies_list_" + panel_id, | |
82 | + perPage: 10, | |
83 | + previous: "«", | |
84 | + next: "»", | |
85 | + midRange: 5 | |
86 | + }); | |
87 | + } | |
88 | + | |
89 | + metaFunctions(); | |
90 | + } | |
91 | + | |
92 | + list.parent().parent().find('.history').attr('style', 'display: none'); | |
93 | + list.parent().attr('style', 'display: block'); | |
94 | + | |
95 | + list.parent().parent().find('.pendencies_link').addClass('active'); | |
96 | + list.parent().parent().find('.history_link').removeClass('active'); | |
97 | +} | |
98 | + | |
99 | +function getHistory(panel_id) { | |
100 | + var container = $("#subject_" + panel_id), | |
101 | + list = container.find('.history_data'), | |
102 | + holder = container.find('.holder'); | |
103 | + | |
104 | + if (list.children().length == 0) { | |
105 | + var url = list.parent().data('url'); | |
106 | + | |
107 | + $.ajax({ | |
108 | + url: url, | |
109 | + success: function (data) { | |
110 | + list.html(data); | |
111 | + | |
112 | + var form = list.find('.form_search'); | |
113 | + | |
114 | + form.submit(function () { | |
115 | + searchHistory(panel_id); | |
116 | + | |
117 | + return false; | |
118 | + }); | |
119 | + | |
120 | + var items = $("#history_table_" + panel_id).children(":visible").length; | |
121 | + | |
122 | + if (items > 10) { | |
123 | + holder.jPages({ | |
124 | + containerID : "history_table_" + panel_id, | |
125 | + perPage: 10, | |
126 | + previous: "«", | |
127 | + next: "»", | |
128 | + midRange: 5 | |
129 | + }); | |
130 | + } | |
131 | + } | |
132 | + }); | |
133 | + } else { | |
134 | + var items = $("#history_table_" + panel_id).children(":visible").length; | |
135 | + | |
136 | + if (items > 10) { | |
137 | + holder.jPages({ | |
138 | + containerID : "history_table_" + panel_id, | |
139 | + perPage: 10, | |
140 | + previous: "«", | |
141 | + next: "»", | |
142 | + midRange: 5 | |
143 | + }); | |
144 | + } | |
145 | + } | |
146 | + | |
147 | + container.find('.pendencies_link').removeClass('active'); | |
148 | + container.find('.history_link').addClass('active'); | |
149 | + | |
150 | + container.find('.history').attr('style', 'display: block'); | |
151 | + container.find('.pendencies').attr('style', 'display: none'); | |
152 | +} | |
153 | + | |
154 | +function searchHistory(panel_id) { | |
155 | + var container = $("#subject_" + panel_id), | |
156 | + url = container.find('.history').data('url'), | |
157 | + list = container.find('.history_data'), | |
158 | + form = container.find('.form_search'), | |
159 | + holder = container.find('.holder'); | |
160 | + | |
161 | + $.ajax({ | |
162 | + url: url, | |
163 | + data: form.serialize(), | |
164 | + success: function (data) { | |
165 | + list.html(data); | |
166 | + | |
167 | + var form = list.find('.form_search'); | |
168 | + | |
169 | + form.submit(function () { | |
170 | + searchHistory(panel_id); | |
171 | + | |
172 | + return false; | |
173 | + }); | |
174 | + | |
175 | + var items = $("#history_table_" + panel_id).children(":visible").length; | |
176 | + | |
177 | + if (items > 10) { | |
178 | + holder.jPages({ | |
179 | + containerID : "history_table_" + panel_id, | |
180 | + perPage: 10, | |
181 | + previous: "«", | |
182 | + next: "»", | |
183 | + midRange: 5 | |
184 | + }); | |
185 | + } | |
186 | + } | |
187 | + }); | |
188 | +} | |
189 | + | |
190 | +function orderBy(panel_id, order) { | |
191 | + var container = $("#subject_" + panel_id), | |
192 | + url = container.find('.history').data('url'), | |
193 | + list = container.find('.history_data'), | |
194 | + search = container.find('input[name="search"]').val(), | |
195 | + holder = container.find('.holder'); | |
196 | + | |
197 | + $.ajax({ | |
198 | + url: url, | |
199 | + data: {'order_by': order, 'search': search}, | |
200 | + success: function (data) { | |
201 | + list.html(data); | |
202 | + | |
203 | + var form = list.find('.form_search'); | |
204 | + | |
205 | + form.submit(function () { | |
206 | + searchHistory(panel_id); | |
207 | + | |
208 | + return false; | |
209 | + }); | |
210 | + | |
211 | + var items = $("#history_table_" + panel_id).children(":visible").length; | |
212 | + | |
213 | + if (items > 10) { | |
214 | + holder.jPages({ | |
215 | + containerID : "history_table_" + panel_id, | |
216 | + perPage: 10, | |
217 | + previous: "«", | |
218 | + next: "»", | |
219 | + midRange: 5 | |
220 | + }); | |
221 | + } | |
222 | + } | |
223 | + }); | |
224 | +} | |
225 | + | |
226 | +function metaFunctions() { | |
227 | + var locale = navigator.language || navigator.userLanguage; | |
228 | + | |
229 | + $('[data-toggle="popover"]').popover({ | |
230 | + html: true, | |
231 | + content: function () { | |
232 | + return $(".popover").html(); | |
233 | + } | |
234 | + }).on('show.bs.popover', function (e) { | |
235 | + $('[data-toggle="popover"]').not(e.target).popover('hide'); | |
236 | + }).on('shown.bs.popover', function (e) { | |
237 | + if($(this).is(e.target)){ | |
238 | + var popover = $(this), | |
239 | + datetime = popover.parent().find('.datetimepicker'), | |
240 | + form = popover.parent().find('form:visible'), | |
241 | + cancel = popover.parent().find('.cancel:visible'), | |
242 | + save = popover.parent().find('.save:visible'); | |
243 | + | |
244 | + if (typeof(datetime.data("DateTimePicker")) != "undefined") { | |
245 | + datetime.data("DateTimePicker").destroy(); | |
246 | + } | |
247 | + | |
248 | + datetime.datetimepicker({ | |
249 | + format: "YYYY-MM-DD HH:mm", | |
250 | + locale: locale, | |
251 | + inline: true, | |
252 | + sideBySide: false | |
253 | + }); | |
254 | + | |
255 | + cancel.on("click", function () { | |
256 | + popover.popover('hide'); | |
257 | + }); | |
258 | + | |
259 | + save.on("click", function () { | |
260 | + var meta = datetime.data('date'), | |
261 | + url = form.attr('action'), | |
262 | + method = form.attr('method'), | |
263 | + token = form.find('input[name="csrfmiddlewaretoken"]').val(), | |
264 | + notification = form.find('input[name="id"]').val(); | |
265 | + | |
266 | + $.ajax({ | |
267 | + url: url, | |
268 | + method: method, | |
269 | + data: {'csrfmiddlewaretoken': token, 'meta': meta, 'id': notification}, | |
270 | + dataType: 'json', | |
271 | + success: function (response) { | |
272 | + if (response.error) { | |
273 | + alertify.error(response.message); | |
274 | + } else { | |
275 | + alertify.success(response.message); | |
276 | + popover.popover('hide'); | |
277 | + } | |
278 | + } | |
279 | + }); | |
280 | + }); | |
281 | + } | |
282 | + }).on('hide.bs.popover', function (e) { | |
283 | + if($(this).is(e.target)){ | |
284 | + var popover = $(this), | |
285 | + datetime = popover.parent().find('.datetimepicker'); | |
286 | + | |
287 | + if (typeof(datetime.data("DateTimePicker")) != "undefined") { | |
288 | + datetime.data("DateTimePicker").destroy(); | |
289 | + } | |
290 | + | |
291 | + datetime.html(''); | |
292 | + } | |
293 | + }).on('hidden.bs.popover', function (e) { | |
294 | + $(e.target).data("bs.popover").inState.click = false; | |
295 | + }); | |
296 | +} | |
0 | 297 | \ No newline at end of file | ... | ... |
amadeus/templates/base.html
... | ... | @@ -186,7 +186,7 @@ |
186 | 186 | <i class="fa fa-envelope-o" aria-hidden="true"></i> |
187 | 187 | </li> |
188 | 188 | <li class="item action_icon" data-toggle="tooltip" data-placement="right" title="{% trans "Pendencias" %}"> |
189 | - <a href=""> | |
189 | + <a href="{% url 'notifications:manage' %}"> | |
190 | 190 | <i class="fa fa-exclamation-triangle" aria-hidden="true"></i> |
191 | 191 | {% if notifications_count > 0 %} |
192 | 192 | <span class="badge notify_badge">{% if notifications_count > 99 %} +99 {% else %} {{ notifications_count }} {% endif %}</span> | ... | ... |
notifications/templates/notifications/_ajax_history.html
0 → 100644
... | ... | @@ -0,0 +1,72 @@ |
1 | +{% load i18n notification_filters %} | |
2 | + | |
3 | +<div class="row"> | |
4 | + <div class="col-md-12"> | |
5 | + <div class="col-md-offset-3 col-md-5"> | |
6 | + <h4 class="text-center history-header">{{ rows }} {% trans 'rows' %}</h4> | |
7 | + </div> | |
8 | + <div class="col-md-4"> | |
9 | + <form action="" method="GET" class="form-horizontal form_search"> | |
10 | + <div class="form-group"> | |
11 | + <label class="col-md-4 history-control-label control-label">{% trans 'Search' %}:</label> | |
12 | + <div class="col-md-8"> | |
13 | + <input type="text" class="form-control" name="search" value="{{ searched }}" placeholder="{% trans 'Insert date or resource' %}" /> | |
14 | + <input type="hidden" name="order_by" value="{{ order_by }}" /> | |
15 | + </div> | |
16 | + </div> | |
17 | + </form> | |
18 | + </div> | |
19 | + <table class="table table-striped table-bordered"> | |
20 | + <thead> | |
21 | + <th> | |
22 | + <a href="javascript: orderBy({{ subject_id }}, '{{ request|order_ajax:'creation_date' }}')"> | |
23 | + {% trans 'Date' %} <i class="fa fa-fw {{ request|order_icon_class:'creation_date' }} pull-right"></i> | |
24 | + </a> | |
25 | + </th> | |
26 | + <th> | |
27 | + <a href="javascript: orderBy({{ subject_id }}, '{{ request|order_ajax:'resource' }}')"> | |
28 | + {% trans 'Resource' %} <i class="fa fa-fw {{ request|order_icon_class:'resource' }} pull-right"></i> | |
29 | + </a> | |
30 | + </th> | |
31 | + <th> | |
32 | + <a href="javascript: orderBy({{ subject_id }}, '{{ request|order_ajax:'task' }}')"> | |
33 | + {% trans 'Task' %} <i class="fa fa-fw {{ request|order_icon_class:'task' }} pull-right"></i> | |
34 | + </a> | |
35 | + </th> | |
36 | + <th> | |
37 | + <a href="javascript: orderBy({{ subject_id }}, '{{ request|order_ajax:'final_date' }}')"> | |
38 | + {% trans 'Final Date' %} <i class="fa fa-fw {{ request|order_icon_class:'final_date' }} pull-right"></i> | |
39 | + </a> | |
40 | + </th> | |
41 | + <th> | |
42 | + <a href="javascript: orderBy({{ subject_id }}, '{{ request|order_ajax:'notification' }}')"> | |
43 | + {% trans 'Notification' %} <i class="fa fa-fw {{ request|order_icon_class:'notification' }} pull-right"></i> | |
44 | + </a> | |
45 | + </th> | |
46 | + <th> | |
47 | + <a href="javascript: orderBy({{ subject_id }}, '{{ request|order_ajax:'obs' }}'')"> | |
48 | + {% trans 'Observation' %} <i class="fa fa-fw {{ request|order_icon_class:'obs' }} pull-right"></i> | |
49 | + </a> | |
50 | + </th> | |
51 | + </thead> | |
52 | + <tbody id="history_table_{{ subject_id }}"> | |
53 | + {% if rows > 0 %} | |
54 | + {% for notification in notifications %} | |
55 | + <tr> | |
56 | + <td>{{ notification.creation_date|date:"SHORT_DATE_FORMAT" }}</td> | |
57 | + <td>{{ notification.task.resource }}</td> | |
58 | + <td>{{ notification.task.get_action_display }}</td> | |
59 | + <td>{{ notification.task.end_date|date:"SHORT_DATE_FORMAT"|default:_('Not Informed') }}</td> | |
60 | + <td>{{ notification.level|warning_msg }}</td> | |
61 | + <td>{{ notification|observation }}</td> | |
62 | + </tr> | |
63 | + {% endfor %} | |
64 | + {% else %} | |
65 | + <tr> | |
66 | + <td colspan="6" class="text-center">{% trans 'No results found' %}</td> | |
67 | + </tr> | |
68 | + {% endif %} | |
69 | + </tbody> | |
70 | + </table> | |
71 | + </div> | |
72 | +</div> | |
0 | 73 | \ No newline at end of file | ... | ... |
notifications/templates/notifications/_history.html
... | ... | @@ -10,7 +10,7 @@ |
10 | 10 | <div class="form-group"> |
11 | 11 | <label class="col-md-4 history-control-label control-label">{% trans 'Search' %}:</label> |
12 | 12 | <div class="col-md-8"> |
13 | - <input type="text" class="form-control" name="search" placeholder="{% trans 'Search...' %}" /> | |
13 | + <input type="text" class="form-control" name="search" value="{{ searched }}" placeholder="{% trans 'Insert date or resource' %}" /> | |
14 | 14 | </div> |
15 | 15 | </div> |
16 | 16 | </form> |
... | ... | @@ -57,8 +57,7 @@ |
57 | 57 | <td>{{ notification.task.get_action_display }}</td> |
58 | 58 | <td>{{ notification.task.end_date|date:"SHORT_DATE_FORMAT"|default:_('Not Informed') }}</td> |
59 | 59 | <td>{{ notification.level|warning_msg }}</td> |
60 | - <td> | |
61 | - </td> | |
60 | + <td>{{ notification|observation }}</td> | |
62 | 61 | </tr> |
63 | 62 | {% endfor %} |
64 | 63 | {% else %} | ... | ... |
notifications/templates/notifications/_view.html
1 | 1 | {% load i18n notification_filters %} |
2 | 2 | |
3 | -<div class="row"> | |
4 | - <div class="col-md-12"> | |
5 | - <div class="panel panel-default"> | |
6 | - <div class="pendency panel-body"> | |
7 | - <ul class="breadcrumb"> | |
8 | - <li> | |
9 | - <a href="">{% trans 'Home' %}</a> | |
10 | - </li> | |
11 | - <li> | |
12 | - <a href="">{{ notification.task.resource.topic.subject.category }}</a> | |
13 | - </li> | |
14 | - <li> | |
15 | - <a href="">{{ notification.task.resource.topic.subject }}</a> | |
16 | - </li> | |
17 | - <li> | |
18 | - <a href="">{{ notification.task.resource.topic }}</a> | |
19 | - </li> | |
20 | - <li> | |
21 | - <a href="">{{ notification.task.resource }}</a> | |
22 | - </li> | |
23 | - </ul> | |
24 | - <div class="row"> | |
25 | - <div class="col-md-6"> | |
26 | - <h4>{{ notification }}</h4> | |
27 | - <p>{% trans 'Final Date/Time' %}: {{ notification.task.end_date|default:_('Not Informed') }}</p> | |
3 | +{% for notification in notifications %} | |
4 | + <div class="row"> | |
5 | + <div class="col-md-12"> | |
6 | + <div class="panel panel-default"> | |
7 | + <div class="pendency panel-body"> | |
8 | + <ul class="breadcrumb"> | |
9 | + <li> | |
10 | + <a href="">{% trans 'Home' %}</a> | |
11 | + </li> | |
12 | + <li> | |
13 | + <a href="">{{ notification.task.resource.topic.subject.category }}</a> | |
14 | + </li> | |
15 | + <li> | |
16 | + <a href="">{{ notification.task.resource.topic.subject }}</a> | |
17 | + </li> | |
18 | + <li> | |
19 | + <a href="">{{ notification.task.resource.topic }}</a> | |
20 | + </li> | |
21 | + <li> | |
22 | + <a href="">{{ notification.task.resource }}</a> | |
23 | + </li> | |
24 | + </ul> | |
25 | + <div class="row"> | |
26 | + <div class="col-md-6"> | |
27 | + <h4>{{ notification }}</h4> | |
28 | + <p>{% trans 'Final Date/Time' %}: {{ notification.task.end_date|default:_('Not Informed') }}</p> | |
28 | 29 | |
29 | - {% if notification.level == 2 %} | |
30 | - <p class="meta">{% trans 'Your goal was to realize this in' %}: {{ notification.meta }}</p> | |
31 | - {% elif notification.level == 4 %} | |
32 | - <p class="meta">{% trans 'Task finished in' %}: {{ notification.task.limit_date }}</p> | |
33 | - {% endif %} | |
30 | + {% if notification.level == 2 %} | |
31 | + <p class="meta">{% trans 'Your goal was to realize this in' %}: {{ notification.meta }}</p> | |
32 | + {% elif notification.level == 4 %} | |
33 | + <p class="meta">{% trans 'Task finished in' %}: {{ notification.task.limit_date }}</p> | |
34 | + {% endif %} | |
34 | 35 | |
35 | - <b>{{ notification|done_percent|floatformat:2 }}%</b> {% trans 'of the participants already realized this task.' %} | |
36 | - </div> | |
37 | - <div class="col-md-6"> | |
38 | - <div class="alert {{ notification.level|warning_class }}"> | |
39 | - <i class="fa fa-exclamation-triangle"></i> | |
40 | - <span>{{ notification.level|warning_msg }}</span> | |
36 | + <b>{{ notification|done_percent|floatformat:2 }}%</b> {% trans 'of the participants already realized this task.' %} | |
37 | + </div> | |
38 | + <div class="col-md-6"> | |
39 | + <div class="alert {{ notification.level|warning_class }}"> | |
40 | + <i class="fa fa-exclamation-triangle"></i> | |
41 | + <span>{{ notification.level|warning_msg }}</span> | |
42 | + </div> | |
41 | 43 | </div> |
42 | 44 | </div> |
43 | - </div> | |
44 | - <div class="row text-center"> | |
45 | - <a href="{% url notification.task.resource.access_link notification.task.resource.slug %}" class="btn btn-success btn-raised" {% if notification.task.resource.show_window %}target="_blank"{% endif %}> | |
46 | - {% if notification.level == 4 %} | |
47 | - {% trans 'Access the task' %} | |
48 | - {% else %} | |
49 | - {% trans 'Realize the task' %} | |
50 | - {% endif %} | |
51 | - </a> | |
52 | - | |
53 | - {% if notification.level < 3 %} | |
54 | - <button class="btn btn-default no_button">{% trans 'or' %}</button> | |
55 | - <button class="btn btn-default btn-raised" data-toggle="popover" data-trigger="focus" data-placement="right"> | |
56 | - {% if notification.level == 1 %} | |
57 | - {% trans 'Define goal to realization' %} | |
45 | + <div class="row text-center"> | |
46 | + <a href="{% url notification.task.resource.access_link notification.task.resource.slug %}" class="btn btn-success btn-raised" {% if notification.task.resource.show_window %}target="_blank"{% endif %}> | |
47 | + {% if notification.level == 4 %} | |
48 | + {% trans 'Access the task' %} | |
58 | 49 | {% else %} |
59 | - {% trans 'Define new goal' %} | |
50 | + {% trans 'Realize the task' %} | |
60 | 51 | {% endif %} |
61 | - </button> | |
52 | + </a> | |
62 | 53 | |
63 | - <div class="popover"> | |
64 | - <div class="popover-content"> | |
65 | - <form role="form" method="post"> | |
66 | - {% csrf_token %} | |
67 | - <div style="overflow:hidden;"> | |
68 | - <div class="form-group"> | |
69 | - <div class="row"> | |
70 | - <div class="col-md-12"> | |
71 | - <div class="datetimepicker"></div> | |
72 | - <input type="hidden" class="meta" name="meta" /> | |
73 | - <input type="hidden" name="id" value="{{ notification.id }}"> | |
74 | - </div> | |
75 | - </div> | |
76 | - </div> | |
77 | - </div> | |
78 | - </form> | |
79 | - </div> | |
80 | - <div class="popover-footer"> | |
81 | - <button type="button" class="btn btn-raised btn-sm btn-primary save pull-left"> | |
82 | - {% trans 'Save Goal' %} | |
83 | - </button> | |
84 | - <button type="button" class="btn btn-default btn-sm btn-raised cancel pull-right"> | |
85 | - {% trans 'Cancel' %} | |
86 | - </button> | |
87 | - </div> | |
88 | - </div> | |
89 | - {% endif %} | |
54 | + {% if notification.level < 3 %} | |
55 | + <button class="btn btn-default no_button">{% trans 'or' %}</button> | |
56 | + <button class="btn btn-default btn-raised" data-toggle="popover" data-placement="right"> | |
57 | + {% if notification.level == 1 %} | |
58 | + {% trans 'Define goal to realization' %} | |
59 | + {% else %} | |
60 | + {% trans 'Define new goal' %} | |
61 | + {% endif %} | |
62 | + </button> | |
63 | + | |
64 | + <div class="popover"> | |
65 | + <div class="popover-content"> | |
66 | + <form action="{% url 'notifications:set_goal' %}" role="form" method="post"> | |
67 | + {% csrf_token %} | |
68 | + <div style="overflow:hidden;"> | |
69 | + <div class="form-group"> | |
70 | + <div class="row"> | |
71 | + <div class="col-md-12"> | |
72 | + <div class="datetimepicker"></div> | |
73 | + <input type="hidden" name="id" value="{{ notification.id }}"> | |
74 | + </div> | |
75 | + </div> | |
76 | + </div> | |
77 | + </div> | |
78 | + </form> | |
79 | + </div> | |
80 | + <div class="popover-footer"> | |
81 | + <button type="button" class="btn btn-raised btn-sm btn-success save pull-left"> | |
82 | + {% trans 'Save Goal' %} | |
83 | + </button> | |
84 | + <button type="button" class="btn btn-default btn-sm btn-raised cancel pull-right"> | |
85 | + {% trans 'Cancel' %} | |
86 | + </button> | |
87 | + </div> | |
88 | + </div> | |
89 | + {% endif %} | |
90 | + </div> | |
90 | 91 | </div> |
91 | 92 | </div> |
92 | 93 | </div> |
93 | 94 | </div> |
94 | -</div> | |
95 | -<script> | |
96 | -$(document).ready(function(){ | |
97 | - var locale = navigator.language || navigator.userLanguage; | |
98 | - | |
99 | - $('[data-toggle="popover"]').popover({ | |
100 | - html: true, | |
101 | - content: function () { | |
102 | - return $(".popover").html(); | |
103 | - } | |
104 | - }).on('shown.bs.popover', function (e) { | |
105 | - if($(this).is(e.target)){ | |
106 | - var popover = $(this), | |
107 | - datetime = popover.parent().find('.datetimepicker'), | |
108 | - form = popover.parent().find('form'), | |
109 | - cancel = popover.parent().find('.cancel'), | |
110 | - save = popover.parent().find('.save'); | |
111 | - | |
112 | - if (typeof(datetime.data("DateTimePicker")) != "undefined") { | |
113 | - datetime.data("DateTimePicker").destroy(); | |
114 | - } | |
115 | - | |
116 | - datetime.datetimepicker({ | |
117 | - locale: locale, | |
118 | - inline: true, | |
119 | - sideBySide: false | |
120 | - }); | |
121 | - | |
122 | - cancel.on("click", function () { | |
123 | - popover.popover('hide'); | |
124 | - }); | |
125 | - | |
126 | - save.on("click", function () { | |
127 | - var field = form.find('.meta'); | |
128 | - field.val(datetime.data('date')); | |
129 | - console.log(form.serialize()); | |
130 | - }); | |
131 | - } | |
132 | - }); | |
133 | -}); | |
134 | -</script> | |
135 | 95 | \ No newline at end of file |
96 | +{% endfor %} | |
136 | 97 | \ No newline at end of file | ... | ... |
... | ... | @@ -0,0 +1,61 @@ |
1 | +{% extends 'base.html' %} | |
2 | + | |
3 | +{% load static i18n pagination permissions_tags subject_counter %} | |
4 | +{% load django_bootstrap_breadcrumbs %} | |
5 | + | |
6 | +{% block breadcrumbs %} | |
7 | + {{ block.super }} | |
8 | + | |
9 | + {% breadcrumb 'Pendencies' 'notifications:manage' %} | |
10 | +{% endblock %} | |
11 | + | |
12 | +{% block content %} | |
13 | + {% if notifications.count > 0 %} | |
14 | + <div class="panel-group" id="subject-accordion" role="tablist" aria-multiselectable="true"> | |
15 | + {% for notification in notifications %} | |
16 | + <div class="panel panel-info subject-panel"> | |
17 | + <div class="panel-heading"> | |
18 | + <div class="row"> | |
19 | + <div class="col-md-12 category-header"> | |
20 | + <h4 class="panel-title"> | |
21 | + <a class="category-course-link pull-left" data-parent="#subject-accordion" data-toggle="collapse" href="#subject_{{ notification.task__resource__topic__subject }}"> | |
22 | + <button class="btn btn-default btn-xs text-center cat-selector"><i class="fa fa-angle-right fa-2x" aria-hidden="true"></i></button> {{ notification.task__resource__topic__subject__name }} ({{ notification.total }}) | |
23 | + </a> | |
24 | + </h4> | |
25 | + </div> | |
26 | + </div> | |
27 | + </div> | |
28 | + <div id="subject_{{ notification.task__resource__topic__subject }}" class="panel-collapse collapse pendencies-content" data-id="{{ notification.task__resource__topic__subject }}"> | |
29 | + <div id="core-subjects-options-div"> | |
30 | + <ul class="core-subjects-options"> | |
31 | + <a href="javascript:getPendencies({{ notification.task__resource__topic__subject }})"><li class="pendencies_link active">{% trans "Actual Pendencies" %} ({{ notification.total }})</li></a> | |
32 | + <a href="javascript:getHistory({{ notification.task__resource__topic__subject }})"><li class="history_link">{% trans "Notifications History" %}</li></a> | |
33 | + </ul> | |
34 | + </div> | |
35 | + | |
36 | + <div class="pendencies" data-url="{% url 'notifications:ajax_view' notification.task__resource__topic__subject %}"> | |
37 | + <div id="pendencies_list_{{ notification.task__resource__topic__subject }}" class="pendencies-cards"></div> | |
38 | + <div class="holder"></div> | |
39 | + </div> | |
40 | + | |
41 | + <div class="history" data-url="{% url 'notifications:ajax_history' notification.task__resource__topic__subject %}"> | |
42 | + <div class="history_data"></div> | |
43 | + <div class="text-center"> | |
44 | + <div class="holder"></div> | |
45 | + </div> | |
46 | + </div> | |
47 | + </div> | |
48 | + </div> | |
49 | + {% endfor %} | |
50 | + | |
51 | + {% pagination request paginator page_obj %} | |
52 | + </div> | |
53 | + {% else %} | |
54 | + <div class="text-center no-subjects"> | |
55 | + <i class="fa fa-exclamation-triangle"></i> | |
56 | + <h4>{% trans 'You do not posses any pendency in this subject' %}</h4> | |
57 | + </div> | |
58 | + {% endif %} | |
59 | + | |
60 | + <script type="text/javascript" src="{% static 'js/pendencies.js' %}"></script> | |
61 | +{% endblock %} | |
0 | 62 | \ No newline at end of file | ... | ... |
notifications/templates/notifications/subject.html
... | ... | @@ -29,15 +29,13 @@ |
29 | 29 | <div id="core-subjects-options-div"> |
30 | 30 | <ul class="core-subjects-options"> |
31 | 31 | <a href="{% url 'notifications:view' subject.slug %}"><li {% if not history %} class="active" {% endif %}>{% trans "Actual Pendencies" %} ({{ total }})</li></a> |
32 | - <a href="{% url 'notifications:history' subject.slug %}" ><li {% if history %} class="active" {% endif %}>{% trans "Notifications History" %}</li></a> | |
32 | + <a href="{% url 'notifications:history' subject.slug %}"><li {% if history %} class="active" {% endif %}>{% trans "Notifications History" %}</li></a> | |
33 | 33 | </ul> |
34 | 34 | </div> |
35 | 35 | |
36 | 36 | {% if not history %} |
37 | 37 | {% if notifications.count > 0 %} |
38 | - {% for notification in notifications %} | |
39 | - {% include 'notifications/_view.html' %} | |
40 | - {% endfor %} | |
38 | + {% include 'notifications/_view.html' %} | |
41 | 39 | |
42 | 40 | {% pagination request paginator page_obj %} |
43 | 41 | {% else %} |
... | ... | @@ -51,4 +49,11 @@ |
51 | 49 | {% endif %} |
52 | 50 | </div> |
53 | 51 | </div> |
52 | + | |
53 | + <script type="text/javascript" src="{% static 'js/pendencies.js' %}"></script> | |
54 | + <script type="text/javascript"> | |
55 | + $(function () { | |
56 | + metaFunctions(); | |
57 | + }); | |
58 | + </script> | |
54 | 59 | {% endblock %} |
55 | 60 | \ No newline at end of file | ... | ... |
notifications/templatetags/notification_filters.py
1 | 1 | from django import template |
2 | 2 | from datetime import datetime |
3 | +from django.utils import timezone, formats | |
3 | 4 | from django.utils.translation import ugettext_lazy as _ |
4 | 5 | |
5 | 6 | from notifications.utils import get_resource_users |
... | ... | @@ -87,4 +88,41 @@ def order_href(request, column): |
87 | 88 | if len(getvars) > 0: |
88 | 89 | params = '&%s' % getvars.urlencode() |
89 | 90 | |
90 | - return "?order_by=" + order_href + params | |
91 | 91 | \ No newline at end of file |
92 | + return "?order_by=" + order_href + params | |
93 | + | |
94 | +@register.filter(name = 'order_ajax') | |
95 | +def order_ajax(request, column): | |
96 | + getvars = request.GET.copy() | |
97 | + order_href = "-" + column | |
98 | + order = None | |
99 | + params = "" | |
100 | + | |
101 | + if 'order_by' in getvars: | |
102 | + order = getvars['order_by'] | |
103 | + del getvars['order_by'] | |
104 | + | |
105 | + if not order: | |
106 | + if column == "creation_date": | |
107 | + order_href = "creation_date" | |
108 | + else: | |
109 | + if column in order: | |
110 | + if "-" in order: | |
111 | + order_href = column | |
112 | + | |
113 | + return order_href | |
114 | + | |
115 | +@register.filter(name = 'observation') | |
116 | +def observation(notification): | |
117 | + msg = '' | |
118 | + | |
119 | + if notification.level == 1: | |
120 | + if notification.meta: | |
121 | + msg = _('Goal defined to task realization: %s')%(formats.date_format(notification.meta, "SHORT_DATETIME_FORMAT")) | |
122 | + elif notification.level == 2: | |
123 | + if notification.meta: | |
124 | + if notification.meta < timezone.now(): | |
125 | + msg = _('Goal defined to task realization: %s')%(formats.date_format(notification.meta, "SHORT_DATETIME_FORMAT")) | |
126 | + else: | |
127 | + msg = _('New goal defined to task realization: %s')%(formats.date_format(notification.meta, "SHORT_DATETIME_FORMAT")) | |
128 | + | |
129 | + return msg | |
92 | 130 | \ No newline at end of file | ... | ... |
notifications/urls.py
... | ... | @@ -2,6 +2,10 @@ from django.conf.urls import url |
2 | 2 | from . import views |
3 | 3 | |
4 | 4 | urlpatterns = [ |
5 | + url(r'^$', views.IndexView.as_view(), name='manage'), | |
6 | + url(r'^set_goal/$', views.set_goal, name='set_goal'), | |
7 | + url(r'^ajax/(?P<id>[\w_-]+)/$', views.AjaxNotifications.as_view(), name='ajax_view'), | |
8 | + url(r'^ajax_history/(?P<id>[\w_-]+)/$', views.AjaxHistory.as_view(), name='ajax_history'), | |
5 | 9 | url(r'^(?P<slug>[\w_-]+)/$', views.SubjectNotifications.as_view(), name='view'), |
6 | 10 | url(r'^(?P<slug>[\w_-]+)/history/$', views.SubjectHistory.as_view(), name='history'), |
7 | 11 | ] |
8 | 12 | \ No newline at end of file | ... | ... |
notifications/utils.py
1 | 1 | from datetime import date |
2 | 2 | from django.utils import timezone |
3 | 3 | from django.db.models import Q |
4 | +from dateutil.parser import parse | |
4 | 5 | |
5 | 6 | from log.models import Log |
6 | 7 | from pendencies.models import Pendencies |
... | ... | @@ -63,7 +64,7 @@ def set_notifications(): |
63 | 64 | notification.save() |
64 | 65 | |
65 | 66 | def get_order_by(order): |
66 | - if not order: | |
67 | + if order is None or order == "": | |
67 | 68 | return ["-creation_date"] |
68 | 69 | |
69 | 70 | if "creation_date" in order: |
... | ... | @@ -96,3 +97,10 @@ def get_order_by(order): |
96 | 97 | return ["-meta"] |
97 | 98 | else: |
98 | 99 | return ["meta"] |
100 | + | |
101 | +def is_date(string): | |
102 | + try: | |
103 | + parse(string) | |
104 | + return True | |
105 | + except ValueError: | |
106 | + return False | |
99 | 107 | \ No newline at end of file | ... | ... |
notifications/views.py
... | ... | @@ -4,16 +4,20 @@ from django.contrib import messages |
4 | 4 | from django.core.urlresolvers import reverse, reverse_lazy |
5 | 5 | from django.utils.translation import ugettext_lazy as _ |
6 | 6 | from django.contrib.auth.mixins import LoginRequiredMixin |
7 | -from django.db.models import Q | |
7 | +from django.contrib.auth.decorators import login_required | |
8 | +from django.http import JsonResponse | |
9 | +from django.db.models import Q, Count | |
8 | 10 | |
11 | +from dateutil import parser | |
9 | 12 | from datetime import datetime |
13 | +from django.utils import formats, timezone | |
10 | 14 | |
11 | 15 | from amadeus.permissions import has_subject_view_permissions |
12 | 16 | |
13 | 17 | from subjects.models import Subject |
14 | 18 | |
15 | 19 | from .models import Notification |
16 | -from .utils import get_order_by | |
20 | +from .utils import get_order_by, is_date | |
17 | 21 | |
18 | 22 | class SubjectNotifications(LoginRequiredMixin, generic.ListView): |
19 | 23 | login_url = reverse_lazy("users:login") |
... | ... | @@ -86,7 +90,22 @@ class SubjectHistory(LoginRequiredMixin, generic.ListView): |
86 | 90 | self.total = notifications.filter(creation_date = datetime.now()).count() |
87 | 91 | |
88 | 92 | if search: |
89 | - notifications = notifications.filter(Q(task__resource__name__icontains = search)).order_by(*order) | |
93 | + queries = Q(task__resource__name__icontains = search) | |
94 | + queries |= Q(task__action__icontains = search) | |
95 | + | |
96 | + if search.isdigit(): | |
97 | + queries |= Q(level = search) | |
98 | + | |
99 | + if is_date(search): | |
100 | + search_date = parser.parse(search) | |
101 | + search_date = timezone.make_aware(search_date, timezone.get_current_timezone()) | |
102 | + | |
103 | + queries |= Q(creation_date = search_date) | |
104 | + queries |= Q(task__limit_date = search_date) | |
105 | + queries |= Q(task__end_date = search_date) | |
106 | + queries |= Q(meta__date = search_date) | |
107 | + | |
108 | + notifications = notifications.filter(queries).order_by(*order) | |
90 | 109 | |
91 | 110 | self.num_rows = notifications.count() |
92 | 111 | |
... | ... | @@ -103,5 +122,124 @@ class SubjectHistory(LoginRequiredMixin, generic.ListView): |
103 | 122 | context['history'] = True |
104 | 123 | context['total'] = self.total |
105 | 124 | context['rows'] = self.num_rows |
125 | + context['searched'] = self.request.GET.get("search", "") | |
126 | + | |
127 | + return context | |
128 | + | |
129 | +class IndexView(LoginRequiredMixin, generic.ListView): | |
130 | + login_url = reverse_lazy("users:login") | |
131 | + redirect_field_name = 'next' | |
132 | + | |
133 | + context_object_name = 'notifications' | |
134 | + template_name = 'notifications/index.html' | |
135 | + paginate_by = 10 | |
136 | + | |
137 | + def get_queryset(self): | |
138 | + notifications = Notification.objects.filter(user = self.request.user, viewed = False, creation_date = datetime.now()).values('task__resource__topic__subject', 'task__resource__topic__subject__name').annotate(total = Count('task__resource__topic__subject')) | |
139 | + | |
140 | + return notifications | |
141 | + | |
142 | + def get_context_data(self, **kwargs): | |
143 | + context = super(IndexView, self).get_context_data(**kwargs) | |
144 | + | |
145 | + context['title'] = _('Pendencies') | |
146 | + | |
147 | + return context | |
148 | + | |
149 | +class AjaxNotifications(LoginRequiredMixin, generic.ListView): | |
150 | + login_url = reverse_lazy("users:login") | |
151 | + redirect_field_name = 'next' | |
152 | + | |
153 | + context_object_name = 'notifications' | |
154 | + template_name = 'notifications/_view.html' | |
155 | + | |
156 | + def get_queryset(self): | |
157 | + subject_id = self.kwargs.get('id', '') | |
158 | + | |
159 | + notifications = Notification.objects.filter(user = self.request.user, task__resource__topic__subject__id = subject_id, creation_date = datetime.now()).order_by("task__limit_date", "task__end_date") | |
160 | + | |
161 | + return notifications | |
162 | + | |
163 | +class AjaxHistory(LoginRequiredMixin, generic.ListView): | |
164 | + login_url = reverse_lazy("users:login") | |
165 | + redirect_field_name = 'next' | |
166 | + | |
167 | + context_object_name = 'notifications' | |
168 | + template_name = 'notifications/_ajax_history.html' | |
169 | + | |
170 | + def get_queryset(self): | |
171 | + subject_id = self.kwargs.get('id', '') | |
172 | + | |
173 | + order = get_order_by(self.request.GET.get("order_by", None)) | |
174 | + search = self.request.GET.get("search", None) | |
175 | + | |
176 | + notifications = Notification.objects.filter(user = self.request.user, task__resource__topic__subject__id = subject_id).order_by(*order) | |
177 | + | |
178 | + if search: | |
179 | + queries = Q(task__resource__name__icontains = search) | |
180 | + queries |= Q(task__action__icontains = search) | |
181 | + | |
182 | + if search.isdigit(): | |
183 | + queries |= Q(level = search) | |
184 | + | |
185 | + if is_date(search): | |
186 | + search_date = parser.parse(search) | |
187 | + search_date = timezone.make_aware(search_date, timezone.get_current_timezone()) | |
188 | + | |
189 | + queries |= Q(creation_date = search_date) | |
190 | + queries |= Q(task__limit_date = search_date) | |
191 | + queries |= Q(task__end_date = search_date) | |
192 | + queries |= Q(meta__date = search_date) | |
193 | + | |
194 | + notifications = notifications.filter(queries).order_by(*order) | |
195 | + | |
196 | + self.num_rows = notifications.count() | |
197 | + | |
198 | + return notifications | |
199 | + | |
200 | + def get_context_data(self, **kwargs): | |
201 | + context = super(AjaxHistory, self).get_context_data(**kwargs) | |
202 | + | |
203 | + subject_id = self.kwargs.get('id', '') | |
204 | + | |
205 | + context['subject_id'] = subject_id | |
206 | + context['rows'] = self.num_rows | |
207 | + context['searched'] = self.request.GET.get("search", "") | |
208 | + context['order_by'] = self.request.GET.get("order_by", "") | |
209 | + | |
210 | + return context | |
211 | + | |
212 | +@login_required | |
213 | +def set_goal(request): | |
214 | + if request.method == "POST" and request.is_ajax(): | |
215 | + meta = request.POST.get('meta', None) | |
216 | + | |
217 | + if not meta: | |
218 | + return JsonResponse({'error': True, 'message': _('No goal date received')}) | |
219 | + | |
220 | + meta = parser.parse(meta) | |
221 | + | |
222 | + notify_id = request.POST.get('id', None) | |
223 | + | |
224 | + if not notify_id: | |
225 | + return JsonResponse({'error': True, 'message': _('Could not identify the notification')}) | |
226 | + | |
227 | + notification = get_object_or_404(Notification, id = notify_id) | |
228 | + | |
229 | + meta = timezone.make_aware(meta, timezone.get_current_timezone()) | |
230 | + | |
231 | + if meta < timezone.now(): | |
232 | + return JsonResponse({'error': True, 'message': _("The goal date should be equal or after today's date")}) | |
233 | + | |
234 | + if meta.date() > notification.task.resource.topic.subject.end_date: | |
235 | + return JsonResponse({'error': True, 'message': _("The goal date should be equal or before subject's date")}) | |
236 | + | |
237 | + notification.meta = meta | |
238 | + notification.save() | |
239 | + | |
240 | + if notification.level == 2: | |
241 | + message = _('Your new goal to realize the task %s is %s')%(str(notification.task), formats.date_format(meta, "SHORT_DATETIME_FORMAT")) | |
242 | + else: | |
243 | + message = _('Your goal to realize the task %s is %s')%(str(notification.task), formats.date_format(meta, "SHORT_DATETIME_FORMAT")) | |
106 | 244 | |
107 | - return context | |
108 | 245 | \ No newline at end of file |
246 | + return JsonResponse({'error': False, 'message': message}) | |
109 | 247 | \ No newline at end of file | ... | ... |
requirements.txt