liquid_feedback_frontend
view app/main/timeline/index.lua @ 144:7c3e8a1678fc
fix timeline saved filters
add Members:set_setting_map code
check for empty name
update settings when saved under same name
fixes bug #305
add Members:set_setting_map code
check for empty name
update settings when saved under same name
fixes bug #305
| author | Daniel Poelzleithner <poelzi@poelzi.org> | 
|---|---|
| date | Wed Oct 06 18:15:23 2010 +0200 (2010-10-06) | 
| parents | 53a45356c107 | 
| children | 90520c9fca44 | 
 line source
     1 execute.view{
     2   module = "timeline",
     3   view = "_constants"
     4 }
     6 local active_name = ""
     7 local options_box_count = param.get("options_box_count", atom.number) or 1
     8 if options_box_count > 10 then
     9   options_box_count = 10
    10 end
    12 local function format_dow(dow)
    13   local dows = {
    14     _"Monday",
    15     _"Tuesday",
    16     _"Wednesday",
    17     _"Thursday",
    18     _"Friday",
    19     _"Saturday",
    20     _"Sunday"
    21   }
    22   return dows[dow+1]
    23 end
    24 slot.put_into("title", _"Timeline")
    26 slot.select("actions", function()
    27   local setting_key = "liquidfeedback_frontend_timeline_current_options"
    28   local setting = Setting:by_pk(app.session.member.id, setting_key)
    29   local current_options = ""
    30   if setting then
    31     current_options = setting.value
    32   end
    33   local setting_maps = app.session.member:get_setting_maps_by_key("timeline_filters")
    34   for i, setting_map in ipairs(setting_maps) do
    35     local active
    36     local options_string = setting_map.value
    37     local name = setting_map.subkey
    38     if options_string == current_options then
    39       active = true
    40       active_name = name
    41     end
    42     ui.link{
    43       image  = { static = "icons/16/time.png" },
    44       attr   = { class = active and "action_active" or nil },
    45       text   = name,
    46       module = 'timeline',
    47       action = 'update',
    48       params = {
    49         options_string = options_string
    50       },
    51     }
    52   end
    53   if #setting_maps > 0 then
    54     ui.link{
    55       content = function()
    56         ui.image{ static = "icons/16/wrench.png" }
    57         slot.put(_"Manage filter")
    58       end,
    59       module = "timeline",
    60       view = "list_filter",
    61     }
    62   end
    63   ui.link{
    64     content = function()
    65       ui.image{ static = "icons/16/bullet_disk.png" }
    66       slot.put(_"Save current filter")
    67     end,
    68     module = "timeline",
    69     view = "save_filter",
    70     params = {
    71       current_name = active_name
    72     },
    73     attr = { 
    74       onclick = "el=document.getElementById('timeline_save');el.checked=true;el.form.submit();return(false);"
    75     }
    76   }
    77 end)
    79 util.help("timeline.index", _"Timeline")
    81 ui.form{
    82   module = "timeline",
    83   action = "update",
    84   content = function()
    85     ui.container{
    87       content = function()
    89         ui.tag{
    90           tag = "input",
    91           attr = {
    92             type = "radio",
    93             id = "timeline_search_last_24h",
    94             name = "search_from",
    95             value = "last_24h",
    96             checked = param.get("date") == "last_24h" and "checked" or nil
    97           },
    98         }
   100         ui.tag{
   101           tag = "label",
   102           attr = {
   103             ["for"] = "timeline_search_last_24h" 
   104           },
   105           content = " " .. _"last 24 hours" .. " "
   106         }
   108         ui.tag{
   109           tag = "input",
   110           attr = {
   111             type = "radio",
   112             id = "timeline_search_from_date",
   113             name = "search_from",
   114             value = "date",
   115             checked = not (param.get("date") == "last_24h") and "checked" or nil
   116           },
   117         }
   119         slot.put(" ")
   120         local current_date = param.get("date")
   121         if not current_date or #current_date == 0 or current_date == "last_24h" then
   122           current_date = tostring(db:query("select now()::date as date")[1].date)
   123         end
   124         ui.tag{
   125           tag = "input",
   126           attr = {
   127             type = "text",
   128             id = "timeline_search_date",
   129             style = "width: 10em;",
   130             onchange = "this.form.submit();",
   131             onclick = "document.getElementById('timeline_search_from_date').checked = true;",
   132             name = "date",
   133             value = current_date
   134           },
   135           content = function() end
   136         }
   138         ui.script{ static = "gregor.js/gregor.js" }
   139         util.gregor("timeline_search_date", "document.getElementById('timeline_search_date').form.submit();")
   142         ui.link{
   143           attr = { style = "margin-left: 1em; font-weight: bold;", onclick = "document.getElementById('timeline_search_date').form.submit();return(false);" },
   144           content = function()
   145             ui.image{
   146               attr = { style = "margin-right: 0.25em;" },
   147               static = "icons/16/magnifier.png"
   148             }
   149             slot.put(_"Search")
   150           end,
   151           external = "#",
   152         }
   153         local show_options = param.get("show_options", atom.boolean)
   154         ui.link{
   155           attr = { style = "margin-left: 1em;", onclick = "el=document.getElementById('timeline_show_options');el.checked=" .. tostring(not show_options) .. ";el.form.submit();return(false);" },
   156           content = function()
   157             ui.image{
   158               attr = { style = "margin-right: 0.25em;" },
   159               static = "icons/16/text_list_bullets.png"
   160             }
   161             slot.put(not show_options and _"Show filter details" or _"Hide filter details")
   162           end,
   163           external = "#",
   164         }
   166         ui.field.boolean{
   167           attr = { id = "timeline_show_options", style = "display: none;", onchange="this.form.submit();" },
   168           name = "show_options",
   169           value = param.get("show_options", atom.boolean)
   170         }
   171         ui.hidden_field{ name = "current_name", value = active_name }
   172         ui.field.boolean{
   173           attr = { id = "timeline_save", style = "display: none;", onchange="this.form.submit();" },
   174           name = "save",
   175           value = false
   176         }
   178       end
   179     }
   181     ui.container{
   182       attr = { 
   183         id = "timeline_options_boxes",
   184         class = "vertical",
   185         style = not param.get("show_options", atom.boolean) and "display: none;" or nil
   186       },
   187       content = function()
   189         local function option_field(event_ident, filter_ident)
   190           local param_name
   191           if not filter_ident then
   192             param_name = "option_" .. event_ident
   193           else
   194             param_name = "option_" .. event_ident .. "_" .. filter_ident
   195           end
   196           local value = param.get(param_name, atom.boolean)
   197           ui.field.boolean{
   198             attr = { id = param_name },
   199             name = param_name,
   200             value = value,
   201           }
   202         end
   204         local function filter_option_fields(event_ident, filter_idents)
   206           for i, filter_ident in ipairs(filter_idents) do
   207               slot.put("<td>")
   208               option_field(event_ident, filter_ident)
   209               slot.put("</td><td><div class='ui_field_label label_right'>")
   210               ui.tag{
   211                 attr = { ["for"] = "option_" .. event_ident .. "_" .. filter_ident },
   212                 tag = "label",
   213                 content = filter_names[filter_ident]
   214               }
   215               slot.put("</div></td>")
   216           end
   218         end
   220         local event_groups = {
   221           {
   222             title = _"Issue events",
   223             event_idents = {
   224               "issue_created",
   225               "issue_canceled",
   226               "issue_accepted",
   227               "issue_half_frozen",
   228               "issue_finished_without_voting",
   229               "issue_voting_started",
   230               "issue_finished_after_voting",
   231             },
   232             filter_idents = {
   233               "membership",
   234               "interested"
   235             }
   236           },
   237           {
   238             title = _"Initiative events",
   239             event_idents = {
   240               "initiative_created",
   241               "initiative_revoked",
   242               "draft_created",
   243               "suggestion_created",
   244             },
   245             filter_idents = {
   246               "membership",
   247               "interested",
   248               "supporter",
   249               "potential_supporter",
   250               "initiator"
   251             }
   252           }
   253         }
   255         slot.put("<table>")
   257         for i_event_group, event_group in ipairs(event_groups) do
   258           slot.put("<tr>")
   259           slot.put("<th colspan='2'>")
   260           slot.put(event_group.title)
   261           slot.put("</th><th colspan='10'>")
   262           slot.put(_"Show only events which match... (or associtated)")
   263           slot.put("</th>")
   264           slot.put("</tr>")
   265           local event_idents = event_group.event_idents
   266           for i, event_ident in ipairs(event_idents) do
   267             slot.put("<tr><td>")
   268             option_field(event_ident)
   269             slot.put("</td><td><div class='ui_field_label label_right'>")
   270             ui.tag{
   271               attr = { ["for"] = "option_" .. event_ident },
   272               tag = "label",
   273               content = event_names[event_ident]
   274             }
   275             slot.put("</div></td>")
   276             filter_option_fields(event_ident, event_group.filter_idents)
   277             slot.put("</tr>")
   278           end
   279         end
   281         slot.put("</table>")
   283       end
   284     }
   285   end
   286 }
   288 local date = param.get("date")
   290 if not date or #date == 0 then
   291   date = "today"
   292 end
   294 local timeline_selector
   296 for event, event_name in pairs(event_names) do
   298   if param.get("option_" .. event, atom.boolean) then
   300     local tmp = Timeline:new_selector()
   301       if event == "draft_created" then
   302         tmp
   303           :reset_fields()
   304           :add_field("max(timeline.occurrence)", "occurrence")
   305           :add_field("timeline.event", nil,  { "grouped" })
   306           :add_field("timeline.issue_id", nil, { "grouped" })
   307           :add_field("draft.initiative_id", nil, { "grouped" })
   308           :add_field("max(timeline.draft_id)", "draft_id")
   309           :add_field("timeline.suggestion_id", nil, { "grouped" })
   310           :add_field("COUNT(*)", "count")
   311       else
   312         tmp
   313           :add_field("1", "count")
   314       end
   316       if date == "last_24h" then
   317         tmp:add_where{ "occurrence > now() - '24 hours'::interval" }
   318       else
   319         tmp:add_where{ "occurrence::date = ?::date", date }
   320       end
   321       tmp
   322         :left_join("draft", nil, "draft.id = timeline.draft_id")
   323         :left_join("suggestion", nil, "suggestion.id = timeline.suggestion_id")
   324         :left_join("initiative", nil, "initiative.id = timeline.initiative_id or initiative.id = draft.initiative_id or initiative.id = suggestion.initiative_id")
   325         :left_join("issue", nil, "issue.id = timeline.issue_id or issue.id = initiative.issue_id")
   326         :left_join("area", nil, "area.id = issue.area_id")
   328         :left_join("interest", "_interest", { "_interest.issue_id = issue.id AND _interest.member_id = ?", app.session.member.id} )
   329         :left_join("initiator", "_initiator", { "_initiator.initiative_id = initiative.id AND _initiator.member_id = ?", app.session.member.id} )
   330         :left_join("membership", "_membership", { "_membership.area_id = area.id AND _membership.member_id = ?", app.session.member.id} )
   331         :left_join("supporter", "_supporter", { "_supporter.initiative_id = initiative.id AND _supporter.member_id = ?", app.session.member.id} )
   333       local group
   334       if event == "draft_created" then
   335         group = { "grouped" }
   336       end
   338       tmp
   339         :add_field("(_interest.member_id NOTNULL)", "is_interested", group)
   340         :add_field("(_initiator.member_id NOTNULL)", "is_initiator", group)
   341         :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)
   342         :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)
   343   --    :left_join("member", nil, "member.id = timeline.member_id", group)
   346     tmp:add_where{ "event = ?", event }
   348     local filters = {}
   349     if param.get("option_" .. event .. "_membership", atom.boolean) then
   350       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"
   351     end
   353     if param.get("option_" .. event .. "_supporter", atom.boolean) then
   354       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))"
   355     end
   357     if param.get("option_" .. event .. "_potential_supporter", atom.boolean) then
   358       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))"
   359     end
   361     if param.get("option_" .. event .. "_interested", atom.boolean) then
   362       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"
   363     end
   365     if param.get("option_" .. event .. "_initiator", atom.boolean) then
   366       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"
   367     end
   369     if #filters > 0 then
   370       local filter_string = "(" .. table.concat(filters, ") OR (") .. ")"
   371       tmp:add_where{ filter_string, app.session.member.id, app.session.member.id }
   372     end
   374     if not timeline_selector then
   375       timeline_selector = tmp
   376     else
   377       timeline_selector:union_all(tmp)
   378     end
   379   end
   380 end
   382 if timeline_selector then
   384   local initiatives_per_page = param.get("initiatives_per_page", atom.number)
   386   local outer_timeline_selector = db:new_selector()
   387   outer_timeline_selector._class = Timeline
   388   outer_timeline_selector
   389     :add_field{ "timeline.*" }
   390     :from({"($)", { timeline_selector }}, "timeline" )
   391     :add_order_by("occurrence DESC")
   393   slot.put("<br />")
   394   execute.view{
   395     module = "timeline",
   396     view = "_list",
   397     params = {
   398       timeline_selector = outer_timeline_selector,
   399       per_page = param.get("per_page", atom.number),
   400       event_names = event_names,
   401       initiatives_per_page = initiatives_per_page
   402     }
   403   }
   405 else
   407   slot.put(_"No events selected to list")
   409 end
