liquid_feedback_frontend
view app/main/timeline/index.lua @ 172:165f4bd02cf3
don't show the first draft of a new initiative as a new draft event in the timeline
new draft should only show changes of drafts drafts of new initiatives as they are handled by the new initiative event
new draft should only show changes of drafts drafts of new initiatives as they are handled by the new initiative event
author | Daniel Poelzleithner <poelzi@poelzi.org> |
---|---|
date | Sun Oct 10 19:40:32 2010 +0200 (2010-10-10) |
parents | 77260f05fd4b |
children |
line source
1 execute.view{
2 module = "timeline",
3 view = "_constants"
4 }
6 local active_name = ""
7 local areas_ignored = {}
8 local options_box_count = param.get("options_box_count", atom.number) or 1
9 if options_box_count > 10 then
10 options_box_count = 10
11 end
13 local function format_dow(dow)
14 local dows = {
15 _"Monday",
16 _"Tuesday",
17 _"Wednesday",
18 _"Thursday",
19 _"Friday",
20 _"Saturday",
21 _"Sunday"
22 }
23 return dows[dow+1]
24 end
25 slot.put_into("title", _"Timeline")
27 slot.select("actions", function()
28 local setting_key = "liquidfeedback_frontend_timeline_current_options"
29 local setting = Setting:by_pk(app.session.member.id, setting_key)
30 local current_options = ""
31 if setting then
32 current_options = setting.value
33 end
34 local setting_maps = app.session.member:get_setting_maps_by_key("timeline_filters")
35 for i, setting_map in ipairs(setting_maps) do
36 local active
37 local options_string = setting_map.value
38 local name = setting_map.subkey
39 if options_string == current_options then
40 active = true
41 active_name = name
42 end
43 ui.link{
44 image = { static = "icons/16/time.png" },
45 attr = { class = active and "action_active" or nil },
46 text = name,
47 form_attr = { class = "inline" },
48 module = 'timeline',
49 action = 'update',
50 params = {
51 options_string = options_string
52 },
53 }
54 end
55 if #setting_maps > 0 then
56 ui.link{
57 content = function()
58 ui.image{ static = "icons/16/wrench.png" }
59 slot.put(_"Manage filter")
60 end,
61 module = "timeline",
62 view = "list_filter",
63 }
64 end
65 ui.link{
66 content = function()
67 ui.image{ static = "icons/16/bullet_disk.png" }
68 slot.put(_"Save current filter")
69 end,
70 module = "timeline",
71 view = "save_filter",
72 params = {
73 current_name = active_name
74 },
75 attr = {
76 onclick = "el=document.getElementById('timeline_save');el.checked=true;el.form.submit();return(false);"
77 }
78 }
79 end)
81 util.help("timeline.index", _"Timeline")
83 ui.form{
84 module = "timeline",
85 action = "update",
86 content = function()
87 ui.container{
89 content = function()
91 ui.tag{
92 tag = "input",
93 attr = {
94 type = "radio",
95 id = "timeline_search_last_24h",
96 name = "search_from",
97 value = "last_24h",
98 checked = param.get("date") == "last_24h" and "checked" or nil
99 },
100 }
102 ui.tag{
103 tag = "label",
104 attr = {
105 ["for"] = "timeline_search_last_24h"
106 },
107 content = " " .. _"last 24 hours" .. " "
108 }
110 ui.tag{
111 tag = "input",
112 attr = {
113 type = "radio",
114 id = "timeline_search_from_date",
115 name = "search_from",
116 value = "date",
117 checked = not (param.get("date") == "last_24h") and "checked" or nil
118 },
119 }
121 slot.put(" ")
122 local current_date = param.get("date")
123 if not current_date or #current_date == 0 or current_date == "last_24h" then
124 current_date = tostring(db:query("select now()::date as date")[1].date)
125 end
126 ui.tag{
127 tag = "input",
128 attr = {
129 type = "text",
130 id = "timeline_search_date",
131 style = "width: 10em;",
132 onchange = "this.form.submit();",
133 onclick = "document.getElementById('timeline_search_from_date').checked = true;",
134 name = "date",
135 value = current_date
136 },
137 content = function() end
138 }
140 ui.script{ static = "gregor.js/gregor.js" }
141 util.gregor("timeline_search_date", true)
144 ui.link{
145 attr = { style = "margin-left: 1em; font-weight: bold;", onclick = "document.getElementById('timeline_search_date').form.submit();return(false);" },
146 content = function()
147 ui.image{
148 attr = { style = "margin-right: 0.25em;" },
149 static = "icons/16/magnifier.png"
150 }
151 slot.put(_"Search")
152 end,
153 external = "#",
154 }
155 local show_options = param.get("show_options", atom.boolean)
156 ui.link{
157 attr = { style = "margin-left: 1em;", onclick = "el=document.getElementById('timeline_show_options');el.checked=" .. tostring(not show_options) .. ";el.form.submit();return(false);" },
158 content = function()
159 ui.image{
160 attr = { style = "margin-right: 0.25em;" },
161 static = "icons/16/text_list_bullets.png"
162 }
163 slot.put(not show_options and _"Show filter details" or _"Hide filter details")
164 end,
165 external = "#",
166 }
168 ui.field.boolean{
169 attr = { id = "timeline_show_options", style = "display: none;", onchange="this.form.submit();" },
170 name = "show_options",
171 value = param.get("show_options", atom.boolean)
172 }
173 ui.hidden_field{ name = "current_name", value = active_name }
174 ui.field.boolean{
175 attr = { id = "timeline_save", style = "display: none;", onchange="this.form.submit();" },
176 name = "save",
177 value = false
178 }
180 end
181 }
183 ui.container{
184 attr = {
185 id = "timeline_options_boxes",
186 class = "vertical",
187 style = not param.get("show_options", atom.boolean) and "display: none;" or nil
188 },
189 content = function()
191 local function option_field(event_ident, filter_ident)
192 local param_name
193 if not filter_ident then
194 param_name = "option_" .. event_ident
195 else
196 param_name = "option_" .. event_ident .. "_" .. filter_ident
197 end
198 local value = param.get(param_name, atom.boolean)
199 ui.field.boolean{
200 attr = { id = param_name },
201 name = param_name,
202 value = value,
203 }
204 end
206 local function filter_option_fields(event_ident, filter_idents)
208 for i, filter_ident in ipairs(filter_idents) do
209 slot.put("<td>")
210 option_field(event_ident, filter_ident)
211 slot.put("</td><td><div class='ui_field_label label_right'>")
212 ui.tag{
213 attr = { ["for"] = "option_" .. event_ident .. "_" .. filter_ident },
214 tag = "label",
215 content = filter_names[filter_ident]
216 }
217 slot.put("</div></td>")
218 end
220 end
222 local event_groups = {
223 {
224 title = _"Issue events",
225 event_idents = {
226 "issue_created",
227 "issue_canceled",
228 "issue_accepted",
229 "issue_half_frozen",
230 "issue_finished_without_voting",
231 "issue_voting_started",
232 "issue_finished_after_voting",
233 },
234 filter_idents = {
235 "membership",
236 "interested"
237 }
238 },
239 {
240 title = _"Initiative events",
241 event_idents = {
242 "initiative_created",
243 "initiative_revoked",
244 "draft_created",
245 "suggestion_created",
246 },
247 filter_idents = {
248 "membership",
249 "interested",
250 "supporter",
251 "potential_supporter",
252 "initiator"
253 }
254 }
255 }
257 slot.put("<table>")
259 for i_event_group, event_group in ipairs(event_groups) do
260 slot.put("<tr>")
261 slot.put("<th colspan='2'>")
262 slot.put(event_group.title)
263 slot.put("</th><th colspan='10'>")
264 slot.put(_"Show only events which match... (or associtated)")
265 slot.put("</th>")
266 slot.put("</tr>")
267 local event_idents = event_group.event_idents
268 for i, event_ident in ipairs(event_idents) do
269 slot.put("<tr><td>")
270 option_field(event_ident)
271 slot.put("</td><td><div class='ui_field_label label_right'>")
272 ui.tag{
273 attr = { ["for"] = "option_" .. event_ident },
274 tag = "label",
275 content = event_names[event_ident]
276 }
277 slot.put("</div></td>")
278 filter_option_fields(event_ident, event_group.filter_idents)
279 slot.put("</tr>")
280 end
281 end
283 slot.put("</table>")
285 local areas = Area:new_selector():add_where("active='t'"):exec()
286 for i, area in ipairs(areas) do
287 if param.get("option_ignore_area_"..tostring(area.id)) then
288 areas_ignored[#areas_ignored+1] = area.id
289 end
290 end
292 ui.multiselect{
293 style = "checkbox",
294 selected_ids = areas_ignored,
295 container_attr = { class = "ignore_area_list" },
296 container2_attr = { class = "ignore_area_item" },
297 label = _"Ignore Areas",
298 name = "option_ignore_area[]",
299 foreign_records = areas,
300 foreign_id = "id",
301 foreign_name = "name"
302 }
304 end
305 }
306 end
307 }
309 local date = param.get("date")
311 if not date or #date == 0 then
312 date = "today"
313 end
315 local timeline_selector
317 for event, event_name in pairs(event_names) do
319 if param.get("option_" .. event, atom.boolean) then
321 local tmp = Timeline:new_selector()
322 if event == "draft_created" then
323 tmp
324 :reset_fields()
325 :add_field("max(timeline.occurrence)", "occurrence")
326 :add_field("timeline.event", nil, { "grouped" })
327 :add_field("timeline.issue_id", nil, { "grouped" })
328 :add_field("draft.initiative_id", nil, { "grouped" })
329 :add_field("max(timeline.draft_id)", "draft_id")
330 :add_field("timeline.suggestion_id", nil, { "grouped" })
331 :add_field("COUNT(*)", "count")
332 else
333 tmp
334 :add_field("1", "count")
335 end
337 if date == "last_24h" then
338 tmp:add_where{ "occurrence > now() - '24 hours'::interval" }
339 else
340 local start,stop = string.gmatch(date, "(%d+-%d+-%d+):(%d+-%d+-%d+)")()
341 if start and stop then
342 tmp:add_where{ "occurrence::date >= ?::date AND occurrence::date <= ?::date", start, stop }
343 else
344 local age = string.gmatch(date, "age:(.+)")()
345 if age then
346 tmp:add_where{ "occurrence >= now() - ?::interval", age }
347 else
348 local since = string.gmatch(date, "since:%s*(%d+-%d+-%d+)%s*")()
349 if since then
350 tmp:add_where{ "occurrence::date >= ?::date", since }
351 else
352 tmp:add_where{ "occurrence::date = ?::date", date }
353 end
354 end
355 end
356 end
357 tmp
358 :left_join("draft", nil, "draft.id = timeline.draft_id")
359 :left_join("suggestion", nil, "suggestion.id = timeline.suggestion_id")
360 :left_join("initiative", nil, "initiative.id = timeline.initiative_id or initiative.id = draft.initiative_id or initiative.id = suggestion.initiative_id")
361 :left_join("issue", nil, "issue.id = timeline.issue_id or issue.id = initiative.issue_id")
362 :left_join("area", nil, "area.id = issue.area_id")
364 :left_join("interest", "_interest", { "_interest.issue_id = issue.id AND _interest.member_id = ?", app.session.member.id} )
365 :left_join("initiator", "_initiator", { "_initiator.initiative_id = initiative.id AND _initiator.member_id = ?", app.session.member.id} )
366 :left_join("membership", "_membership", { "_membership.area_id = area.id AND _membership.member_id = ?", app.session.member.id} )
367 :left_join("supporter", "_supporter", { "_supporter.initiative_id = initiative.id AND _supporter.member_id = ?", app.session.member.id} )
369 local group
370 if event == "draft_created" then
371 group = { "grouped" }
372 tmp:add_where{"EXISTS(SELECT 1 from draft as cdraft WHERE draft.initiative_id = cdraft.initiative_id AND cdraft.id != draft.id ORDER BY cdraft.id DESC)"}
373 end
375 tmp
376 :add_field("(_interest.member_id NOTNULL)", "is_interested", group)
377 :add_field("(_initiator.member_id NOTNULL)", "is_initiator", group)
378 :add_field({"(_supporter.member_id NOTNULL) AND NOT EXISTS(SELECT NULL FROM opinion WHERE opinion.initiative_id = initiative.id AND opinion.member_id = ? AND ((opinion.degree = 2 AND NOT fulfilled) OR (opinion.degree = -2 AND fulfilled)) LIMIT 1)", app.session.member.id }, "is_supporter", group)
379 :add_field({"EXISTS(SELECT NULL FROM opinion WHERE opinion.initiative_id = initiative.id AND opinion.member_id = ? AND ((opinion.degree = 2 AND NOT fulfilled) OR (opinion.degree = -2 AND fulfilled)) LIMIT 1)", app.session.member.id }, "is_potential_supporter", group)
380 -- :left_join("member", nil, "member.id = timeline.member_id", group)
382 if #areas_ignored > 0 then
383 tmp:add_where{"area.id NOT IN ($)", areas_ignored}
384 end
386 tmp:add_where{ "event = ?", event }
388 local filters = {}
389 if param.get("option_" .. event .. "_membership", atom.boolean) then
390 filters[#filters+1] = "(timeline.initiative_id ISNULL AND timeline.issue_id ISNULL AND timeline.draft_id ISNULL AND timeline.suggestion_id ISNULL) OR _membership.member_id NOTNULL"
391 end
393 if param.get("option_" .. event .. "_supporter", atom.boolean) then
394 filters[#filters+1] = "(timeline.initiative_id ISNULL AND timeline.issue_id ISNULL AND timeline.draft_id ISNULL AND timeline.suggestion_id ISNULL) OR ((_supporter.member_id NOTNULL) AND NOT EXISTS(SELECT NULL FROM opinion WHERE opinion.initiative_id = initiative.id AND opinion.member_id = ? AND ((opinion.degree = 2 AND NOT fulfilled) OR (opinion.degree = -2 AND fulfilled)) LIMIT 1))"
395 end
397 if param.get("option_" .. event .. "_potential_supporter", atom.boolean) then
398 filters[#filters+1] = "(timeline.initiative_id ISNULL AND timeline.issue_id ISNULL AND timeline.draft_id ISNULL AND timeline.suggestion_id ISNULL) OR ((_supporter.member_id NOTNULL) AND EXISTS(SELECT NULL FROM opinion WHERE opinion.initiative_id = initiative.id AND opinion.member_id = ? AND ((opinion.degree = 2 AND NOT fulfilled) OR (opinion.degree = -2 AND fulfilled)) LIMIT 1))"
399 end
401 if param.get("option_" .. event .. "_interested", atom.boolean) then
402 filters[#filters+1] = "(timeline.initiative_id ISNULL AND timeline.issue_id ISNULL AND timeline.draft_id ISNULL AND timeline.suggestion_id ISNULL) OR _interest.member_id NOTNULL"
403 end
405 if param.get("option_" .. event .. "_initiator", atom.boolean) then
406 filters[#filters+1] = "(timeline.initiative_id ISNULL AND timeline.issue_id ISNULL AND timeline.draft_id ISNULL AND timeline.suggestion_id ISNULL) OR _initiator.member_id NOTNULL"
407 end
409 if #filters > 0 then
410 local filter_string = "(" .. table.concat(filters, ") OR (") .. ")"
411 tmp:add_where{ filter_string, app.session.member.id, app.session.member.id }
412 end
414 if not timeline_selector then
415 timeline_selector = tmp
416 else
417 timeline_selector:union_all(tmp)
418 end
419 end
420 end
422 if timeline_selector then
424 local initiatives_per_page = param.get("initiatives_per_page", atom.number)
426 local outer_timeline_selector = db:new_selector()
427 outer_timeline_selector._class = Timeline
428 outer_timeline_selector
429 :add_field{ "timeline.*" }
430 :from({"($)", { timeline_selector }}, "timeline" )
431 :add_order_by("occurrence DESC")
433 slot.put("<br />")
434 execute.view{
435 module = "timeline",
436 view = "_list",
437 params = {
438 timeline_selector = outer_timeline_selector,
439 per_page = param.get("per_page", atom.number),
440 event_names = event_names,
441 initiatives_per_page = initiatives_per_page
442 }
443 }
445 else
447 slot.put(_"No events selected to list")
449 end