liquid_feedback_frontend
view app/main/issue/_list.lua @ 1482:7cdc537f991f
Show correct quorum in initiative not admitted info
| author | bsw | 
|---|---|
| date | Wed Oct 24 14:49:56 2018 +0200 (2018-10-24) | 
| parents | 32cc544d5a5b | 
| children | 3ab878ba277e | 
 line source
     1 local for_member = param.get ( "for_member", "table" )
     2 local for_unit =   param.get ( "for_unit",   "table" )
     3 local for_area =   param.get ( "for_area",   "table" )
     4 local for_issue =  param.get ( "for_issue",  "table" )
     5 local for_initiative =  param.get ( "for_initiative",  "table" )
     6 local for_sidebar = param.get("for_sidebar", atom.boolean)
     7 local no_filter =  param.get ( "no_filter",  atom.boolean )
     8 local search =     param.get ( "search" )
    10 local limit = 25
    12 local mode = request.get_param{ name = "mode" } or "issue"
    14 if for_initiative or for_issue or for_member then
    15   mode = "timeline"
    16 end
    18 local selector
    20 if search then
    22   selector = Issue:get_search_selector(search)
    25 elseif mode == "timeline" then
    27   local event_max_id = request.get_param_strings()["event_max_id"]
    29   selector = Event:new_selector()
    30     :add_order_by("event.id DESC")
    31     :join("issue", nil, "issue.id = event.issue_id")
    32     :add_field("now() - event.occurrence", "time_ago")
    33     :limit(limit + 1)
    35   if event_max_id then
    36     selector:add_where{ "event.id < ?", event_max_id }
    37   end
    39   if for_member then
    40     selector:add_where{ "event.member_id = ?", for_member.id }
    41   end
    43   if for_initiative then
    44     selector:add_where{ "event.initiative_id = ?", for_initiative.id }
    45   end
    48 elseif mode == "issue" then
    50   selector = Issue:new_selector()
    52 end
    54 if for_unit then
    55   selector:join("area", nil, "area.id = issue.area_id")
    56   selector:add_where{ "area.unit_id = ?", for_unit.id }
    57 elseif for_area then
    58   selector:add_where{ "issue.area_id = ?", for_area.id }
    59 elseif for_issue then
    60   selector:add_where{ "issue.id = ?", for_issue.id }
    61 end
    63 if not search and app.session.member_id then
    64   selector
    65     :left_join("interest", "_interest", { 
    66       "_interest.issue_id = issue.id AND _interest.member_id = ?", app.session.member.id 
    67     } )
    68     :add_field("(_interest.member_id NOTNULL)", "is_interested")
    69     :left_join("delegating_interest_snapshot", "_delegating_interest", { [[
    70       _delegating_interest.issue_id = issue.id AND 
    71       _delegating_interest.member_id = ? AND
    72       _delegating_interest.snapshot_id = issue.latest_snapshot_id
    73     ]], app.session.member.id } )
    74     :add_field("_delegating_interest.delegate_member_ids[1]", "is_interested_by_delegation_to_member_id")
    75     :add_field("_delegating_interest.delegate_member_ids[array_upper(_delegating_interest.delegate_member_ids, 1)]", "is_interested_via_member_id")    
    76     :add_field("array_length(_delegating_interest.delegate_member_ids, 1)", "delegation_chain_length")
    77 end
    79 local function doit()
    81   local last_event_id
    83   local items = selector:exec()
    85   local row_class = "sectionRow"
    86   if for_sidebar then
    87     row_class = "sidebarRow"
    88   end
    90   if mode == "timeline" then
    91     local issues = items:load ( "issue" )
    92     local initiative = items:load ( "initiative" )
    93     items:load ( "suggestion" )
    94     items:load ( "member" )
    95     issues:load_everything_for_member_id ( app.session.member_id )
    96     initiative:load_everything_for_member_id ( app.session.member_id )
    97   elseif mode == "issue" then
    98     items:load_everything_for_member_id ( app.session.member_id )
    99   end
   101   local last_event_date
   102   for i, item in ipairs(items) do
   103     local event
   104     local issue
   105     if mode == "timeline" then
   106       event = item
   107       issue = item.issue
   108     elseif mode == "issue" then
   109       event = {}
   110       issue = item
   111     end
   113     last_event_id = event.id
   115     local class = "mdl-card mdl-shadow--2dp mdl-card__fullwidth event " .. row_class
   116     if event.suggestion_id then
   117       class = class .. " suggestion"
   118     end
   120     ui.container{ attr = { class = class, }, content = function()
   121       local event_name
   122       local event_icon
   123       local negative_event = false
   125       local days_ago_text
   127       if mode == "timeline" then
   128         event_name = event.event_name
   129           if event.event == "issue_state_changed" then
   130             if event.state == "discussion" then
   131               event_name = _"Discussion started"
   132             elseif event.state == "verification" then
   133               event_name = _"Verification started"
   134             elseif event.state == "voting" then
   135               event_name = _"Voting started"
   136             elseif event.state == "finished_with_winner" then
   137               event_name = event.state_name
   138             elseif event.state == "finished_without_winner" then
   139               event_name = event.state_name
   140               negative_event = true
   141             else
   142               event_name = event.state_name
   143               negative_event = true
   144             end
   145           elseif event.event == "initiative_revoked" then
   146             negative_event = true
   147           end
   149         if event.time_ago == 0 then
   150           days_ago_text = _("today at #{time}", { time = format.time(event.occurrence) })
   151         elseif event.time_ago == 1 then
   152           days_ago_text = _("yesterday at #{time}", { time = format.time(event.occurrence) })
   153         else
   154           days_ago_text = _("#{interval} ago", { interval = format.interval_text ( event.time_ago ) } )
   155         end
   157       elseif mode == "issue" then
   158         local event_icons_map = {
   159           admission = "bubble_chart",
   160           discussion = "question_answer",
   161           verification = "find_in_page",
   162           voting = "mail",
   163           finished_with_winner = "gavel",
   164           finished_without_winner = "gavel",
   165           canceled = "clear"
   166         }
   167         event_icon = event_icons_map[issue.state] or event_icons_map["canceled"]
   168         event_name = issue.state_name
   169         if issue.state_time_left:sub(1,1) ~= "-" then
   170           days_ago_text = _( "#{interval_text} left", {
   171             interval_text = format.interval_text ( issue.state_time_left )
   172           })
   173         elseif issue.closed then
   174           days_ago_text = _( "#{interval_text} ago", {
   175             interval_text = format.interval_text ( issue.closed_ago )
   176           })
   177         else
   178           days_ago_text = _"phase ends soon" 
   179         end
   180         if issue.closed and not issue.fully_frozen then
   181           negative_event = true
   182         end
   183         if issue.state == "finished_without_winner" 
   184             or issue.state == "canceled_no_initiative_admitted"
   185             or issue.state == "canceled_by_admin"
   186         then
   187           negative_event = true
   188         end
   189       end
   191       local class= "event_info"
   193       if negative_event then
   194         class = class .. " negative"
   195       end
   197       if not for_issue and not for_initiative then
   198         ui.container{ attr = { class = "mdl-card__title mdl-card--has-fab mdl-card--border" }, content = function()
   199           if not (config.single_unit_id and config.single_area_id) then
   200             if not config.single_unit_id then
   201               slot.put ( " " )
   202               ui.link{
   203                 module = "index", view = "index", params = { unit = issue.area.unit_id },
   204                 attr = { class = "mdl-chip unit" }, content = function()
   205                   ui.tag{ attr = { class = "mdl-chip__text" }, content = function()
   206                     ui.tag{ tag = "i", attr = { class = "material-icons" }, content = "flag" }              
   207                     slot.put(" ")
   208                     ui.tag{ content = issue.area.unit.name }
   209                   end }
   210                 end 
   211               }
   212             end
   213             if not config.single_area_id then
   214               slot.put(" ")
   215               ui.link{
   216                 module = "index", view = "index", params = { unit = issue.area.unit_id, area = issue.area_id },
   217                 attr = { class = "mdl-chip area" }, content = function()
   218                   ui.tag{ attr = { class = "mdl-chip__text" }, content = function()
   219                     ui.tag{ tag = "i", attr = { class = "material-icons" }, content = "folder" }
   220                     slot.put(" ")
   221                     ui.tag{ content = issue.area.name }
   222                   end}
   223                 end 
   224               }
   225             end
   226           end
   227           --ui.heading{ level = 2, attr = { class = "mdl-card__title-text", style = "display: block;" }, content = function()
   228             slot.put(" ")
   229             ui.link{
   230               module = "issue", view = "show", id = issue.id,
   231               attr = { class = "mdl-chip issue" }, content = function()
   232                 ui.tag{ tag = "i", attr = { class = "material-icons" }, content = "label" }
   233                 slot.put(" ")
   234                 ui.tag{ attr = { class = "mdl-chip__text" }, content = issue.name }
   235             end }
   236           --end }
   237           ui.container{ attr = { class = "mdl-card__subtitle-text .mdl-cell--hide-phone" }, content = function()
   238             ui.container{ attr = { class = class }, content = function ()
   239               if event_icon then
   240                 ui.tag{ tag = "i", attr = { class = "material-icons" }, content = event_icon }
   241               end
   242               slot.put(" ")
   243               ui.tag { content = event_name }
   244               slot.put(" ")
   245               ui.tag{ content = "(" .. days_ago_text .. ")" }
   246             end }
   247           end }
   248           if app.session.member and issue.fully_frozen and not issue.closed and not issue.member_info.direct_voted and app.session.member:has_voting_right_for_unit_id(issue.area.unit_id) then
   249             ui.link {
   250               attr = { class = "mdl-button mdl-js-button mdl-button--fab mdl-button--colored" ,
   251                 style = "position: absolute; right: 20px; bottom: -27px;"
   252               },
   253               module = "vote", view = "list", 
   254               params = { issue_id = issue.id },
   255               content = function()
   256                 ui.tag{ tag = "i", attr = { class = "material-icons" }, content = config.voting_icon or "mail_outline" }
   257               end 
   258             }
   259           end
   260         end }
   261       end
   263       if event.suggestion_id then
   264         ui.container{ attr = { class = "suggestion" }, content = function()
   265           ui.link{
   266             text = format.string(event.suggestion.name, {
   267               truncate_at = 160, truncate_suffix = true
   268             }),
   269             module = "initiative", view = "show", id = event.initiative.id,
   270             params = { suggestion_id = event.suggestion_id },
   271             anchor = "s" .. event.suggestion_id
   272           }
   273         end }
   274       end
   276       if not for_initiative and (not for_issue or event.initiative_id) then
   278         ui.container{ attr = { class = "initiative_list" }, content = function()
   279           if event.initiative_id then
   280             local initiative = event.initiative
   282             execute.view{ module = "initiative", view = "_list", params = { 
   283               issue = issue,
   284               initiative = initiative,
   285               for_event = mode == "timeline" and not (event.state == issue.state)
   287             } }
   288           else
   289             local initiatives = issue.initiatives
   290             execute.view{ module = "initiative", view = "_list", params = { 
   291               issue = issue,
   292               initiatives = initiatives,
   293               for_event = mode == "timeline" and not (event.state == issue.state)
   294             } }
   295           end
   296         end }
   297       end
   298       if app.session.member_id then
   299         ui.container{ attr = { class = "mdl-card__actions mdl-card--border" }, content = function()
   300           execute.view{ 
   301             module = "delegation", view = "_info", params = { 
   302               issue = issue, member = for_member 
   303             }
   304           }
   305         end }
   306       end
   307     end }
   309   end
   311   if mode == "timeline" then
   312     if for_sidebar then
   313       ui.container { attr = { class = row_class }, content = function ()
   314         ui.link{
   315           attr = { class = "moreLink" },
   316           text = _"Show full history",
   317           module = "initiative", view = "history", id = for_initiative.id
   318         }
   319       end }
   320     elseif #items > limit then
   321       ui.container { attr = { class = row_class }, content = function ()
   322         local params = request.get_param_strings()
   323         ui.link{
   324           attr = { class = "moreLink" },
   325           text = _"Show older events",
   326           module = request.get_module(),
   327           view = request.get_view(),
   328           id = for_unit and for_unit.id or for_area and for_area.id or for_issue and for_issue.id or for_member and for_member.id,
   329           params = {
   330             mode = "timeline",
   331             event_max_id = last_event_id,
   332             tab = params["tab"],
   333             phase = params["phase"],
   334             closed = params["closed"]
   335           }
   336         }
   337       end }
   338     elseif #items < 1 then
   339       ui.container { attr = { class = row_class }, content = _"No more events available" }
   340     end
   341   end
   343   if #items < 1 then
   344     ui.section( function()
   345       ui.sectionRow( function()
   346         ui.container{ content = _"No results for this selection" }
   347       end )
   348     end )
   349   end
   352 end
   355 local filters = {}
   357 if not for_initiative and not for_issue and not no_filter then
   359   filters = execute.chunk{
   360     module = "issue", chunk = "_filters", params = {
   361     for_events = mode == "timeline" and true or false,
   362     member = app.session.member, 
   363     for_member = for_member, 
   364     state = for_state, 
   365     for_unit = for_unit and true or false, 
   366     for_area = for_area and true or false
   367   }}
   368 end
   370 filters.opened = true
   371 filters.selector = selector
   374 local function dotabs()
   375   slot.select("filter", function()
   376     ui.container{ attr = { class = "mdl-tabs mdl-js-tabs mdl-js-ripple-effect float-left" }, content = function()
   377       ui.container{ attr = { class = "mdl-tabs__tab-bar" }, content = function()
   378         local mode = request.get_param{ name = "mode" }
   379         local css_active = (not mode or mode == "issue") and " is-active" or ""
   380         ui.link{ module = request.get_module(), view = request.get_view(), id = request.get_id_string(), content = "Issues", attr = { class = "mdl-tabs__tab" .. css_active } }
   381         local css_active = mode and " is-active" or " "
   382         ui.link{ module = request.get_module(), view = request.get_view(), id = request.get_id_string(), params = { mode = "timeline" }, content = "Timeline", attr = { class = "mdl-tabs__tab" .. css_active } }
   383         ui.link{ module = "member", view = "list", content = "Member", attr = { class = "mdl-tabs__tab" } }
   384       end }
   385     end }
   386   end)
   387 end
   390 if mode == "timeline" then
   391   --dotabs()
   392   filters.content = function()
   393     execute.view{ module = "index", view = "_head" }
   394     doit()
   395   end
   396 else
   397   -- dotabs()
   398   filters.content = function()
   399     if config.voting_only then
   400       local admission_order_field = "filter_issue_order.order_in_unit"
   401       if for_area then
   402         admission_order_field = "filter_issue_order.order_in_area"
   403       end
   404       selector:left_join ( "issue_order_in_admission_state", "filter_issue_order",    "filter_issue_order.id = issue.id" )
   405       selector:add_order_by ( "issue.closed DESC NULLS FIRST" )
   406       selector:add_order_by ( "issue.accepted ISNULL" )
   407       selector:add_order_by ( "CASE WHEN issue.accepted ISNULL THEN NULL ELSE justify_interval(coalesce(issue.fully_frozen + issue.voting_time, issue.half_frozen + issue.verification_time, issue.accepted + issue.discussion_time, issue.created + issue.max_admission_time) - now()) END" )
   408       selector:add_order_by ( "CASE WHEN issue.accepted ISNULL THEN " .. admission_order_field .. " ELSE NULL END" )
   409       selector:add_order_by ( "id" )
   410     end
   411     execute.view{ module = "index", view = "_head" }
   412     ui.paginate{
   413       selector = selector,
   414       per_page = 25,
   415       content = doit
   416     }
   417   end
   418 end
   420 filters.class = "mdl-special-card mdl-card__fullwidth mdl-shadow--2dp"
   422 ui.filters(filters)
