liquid_feedback_frontend

diff app/main/issue/_list.lua @ 1309:32cc544d5a5b

Cumulative patch for upcoming frontend version 4
author bsw/jbe
date Sun Jul 15 14:07:29 2018 +0200 (2018-07-15)
parents
children 3ab878ba277e
line diff
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/app/main/issue/_list.lua	Sun Jul 15 14:07:29 2018 +0200
     1.3 @@ -0,0 +1,425 @@
     1.4 +local for_member = param.get ( "for_member", "table" )
     1.5 +local for_unit =   param.get ( "for_unit",   "table" )
     1.6 +local for_area =   param.get ( "for_area",   "table" )
     1.7 +local for_issue =  param.get ( "for_issue",  "table" )
     1.8 +local for_initiative =  param.get ( "for_initiative",  "table" )
     1.9 +local for_sidebar = param.get("for_sidebar", atom.boolean)
    1.10 +local no_filter =  param.get ( "no_filter",  atom.boolean )
    1.11 +local search =     param.get ( "search" )
    1.12 +
    1.13 +local limit = 25
    1.14 +
    1.15 +local mode = request.get_param{ name = "mode" } or "issue"
    1.16 +
    1.17 +if for_initiative or for_issue or for_member then
    1.18 +  mode = "timeline"
    1.19 +end
    1.20 +
    1.21 +local selector
    1.22 +
    1.23 +if search then
    1.24 +
    1.25 +  selector = Issue:get_search_selector(search)
    1.26 +
    1.27 +  
    1.28 +elseif mode == "timeline" then
    1.29 +
    1.30 +  local event_max_id = request.get_param_strings()["event_max_id"]
    1.31 +
    1.32 +  selector = Event:new_selector()
    1.33 +    :add_order_by("event.id DESC")
    1.34 +    :join("issue", nil, "issue.id = event.issue_id")
    1.35 +    :add_field("now() - event.occurrence", "time_ago")
    1.36 +    :limit(limit + 1)
    1.37 +    
    1.38 +  if event_max_id then
    1.39 +    selector:add_where{ "event.id < ?", event_max_id }
    1.40 +  end
    1.41 +
    1.42 +  if for_member then
    1.43 +    selector:add_where{ "event.member_id = ?", for_member.id }
    1.44 +  end
    1.45 +
    1.46 +  if for_initiative then
    1.47 +    selector:add_where{ "event.initiative_id = ?", for_initiative.id }
    1.48 +  end
    1.49 +
    1.50 +  
    1.51 +elseif mode == "issue" then
    1.52 +  
    1.53 +  selector = Issue:new_selector()
    1.54 +
    1.55 +end
    1.56 +
    1.57 +if for_unit then
    1.58 +  selector:join("area", nil, "area.id = issue.area_id")
    1.59 +  selector:add_where{ "area.unit_id = ?", for_unit.id }
    1.60 +elseif for_area then
    1.61 +  selector:add_where{ "issue.area_id = ?", for_area.id }
    1.62 +elseif for_issue then
    1.63 +  selector:add_where{ "issue.id = ?", for_issue.id }
    1.64 +end
    1.65 +  
    1.66 +if not search and app.session.member_id then
    1.67 +  selector
    1.68 +    :left_join("interest", "_interest", { 
    1.69 +      "_interest.issue_id = issue.id AND _interest.member_id = ?", app.session.member.id 
    1.70 +    } )
    1.71 +    :add_field("(_interest.member_id NOTNULL)", "is_interested")
    1.72 +    :left_join("delegating_interest_snapshot", "_delegating_interest", { [[
    1.73 +      _delegating_interest.issue_id = issue.id AND 
    1.74 +      _delegating_interest.member_id = ? AND
    1.75 +      _delegating_interest.snapshot_id = issue.latest_snapshot_id
    1.76 +    ]], app.session.member.id } )
    1.77 +    :add_field("_delegating_interest.delegate_member_ids[1]", "is_interested_by_delegation_to_member_id")
    1.78 +    :add_field("_delegating_interest.delegate_member_ids[array_upper(_delegating_interest.delegate_member_ids, 1)]", "is_interested_via_member_id")    
    1.79 +    :add_field("array_length(_delegating_interest.delegate_member_ids, 1)", "delegation_chain_length")
    1.80 +end
    1.81 +
    1.82 +local function doit()
    1.83 +
    1.84 +  local last_event_id
    1.85 +
    1.86 +  local items = selector:exec()
    1.87 +
    1.88 +  local row_class = "sectionRow"
    1.89 +  if for_sidebar then
    1.90 +    row_class = "sidebarRow"
    1.91 +  end
    1.92 +  
    1.93 +  if mode == "timeline" then
    1.94 +    local issues = items:load ( "issue" )
    1.95 +    local initiative = items:load ( "initiative" )
    1.96 +    items:load ( "suggestion" )
    1.97 +    items:load ( "member" )
    1.98 +    issues:load_everything_for_member_id ( app.session.member_id )
    1.99 +    initiative:load_everything_for_member_id ( app.session.member_id )
   1.100 +  elseif mode == "issue" then
   1.101 +    items:load_everything_for_member_id ( app.session.member_id )
   1.102 +  end
   1.103 +
   1.104 +  local last_event_date
   1.105 +  for i, item in ipairs(items) do
   1.106 +    local event
   1.107 +    local issue
   1.108 +    if mode == "timeline" then
   1.109 +      event = item
   1.110 +      issue = item.issue
   1.111 +    elseif mode == "issue" then
   1.112 +      event = {}
   1.113 +      issue = item
   1.114 +    end
   1.115 +    
   1.116 +    last_event_id = event.id
   1.117 +
   1.118 +    local class = "mdl-card mdl-shadow--2dp mdl-card__fullwidth event " .. row_class
   1.119 +    if event.suggestion_id then
   1.120 +      class = class .. " suggestion"
   1.121 +    end
   1.122 +    
   1.123 +    ui.container{ attr = { class = class, }, content = function()
   1.124 +      local event_name
   1.125 +      local event_icon
   1.126 +      local negative_event = false
   1.127 +      
   1.128 +      local days_ago_text
   1.129 +
   1.130 +      if mode == "timeline" then
   1.131 +        event_name = event.event_name
   1.132 +          if event.event == "issue_state_changed" then
   1.133 +            if event.state == "discussion" then
   1.134 +              event_name = _"Discussion started"
   1.135 +            elseif event.state == "verification" then
   1.136 +              event_name = _"Verification started"
   1.137 +            elseif event.state == "voting" then
   1.138 +              event_name = _"Voting started"
   1.139 +            elseif event.state == "finished_with_winner" then
   1.140 +              event_name = event.state_name
   1.141 +            elseif event.state == "finished_without_winner" then
   1.142 +              event_name = event.state_name
   1.143 +              negative_event = true
   1.144 +            else
   1.145 +              event_name = event.state_name
   1.146 +              negative_event = true
   1.147 +            end
   1.148 +          elseif event.event == "initiative_revoked" then
   1.149 +            negative_event = true
   1.150 +          end
   1.151 +
   1.152 +        if event.time_ago == 0 then
   1.153 +          days_ago_text = _("today at #{time}", { time = format.time(event.occurrence) })
   1.154 +        elseif event.time_ago == 1 then
   1.155 +          days_ago_text = _("yesterday at #{time}", { time = format.time(event.occurrence) })
   1.156 +        else
   1.157 +          days_ago_text = _("#{interval} ago", { interval = format.interval_text ( event.time_ago ) } )
   1.158 +        end
   1.159 +        
   1.160 +      elseif mode == "issue" then
   1.161 +        local event_icons_map = {
   1.162 +          admission = "bubble_chart",
   1.163 +          discussion = "question_answer",
   1.164 +          verification = "find_in_page",
   1.165 +          voting = "mail",
   1.166 +          finished_with_winner = "gavel",
   1.167 +          finished_without_winner = "gavel",
   1.168 +          canceled = "clear"
   1.169 +        }
   1.170 +        event_icon = event_icons_map[issue.state] or event_icons_map["canceled"]
   1.171 +        event_name = issue.state_name
   1.172 +        if issue.state_time_left:sub(1,1) ~= "-" then
   1.173 +          days_ago_text = _( "#{interval_text} left", {
   1.174 +            interval_text = format.interval_text ( issue.state_time_left )
   1.175 +          })
   1.176 +        elseif issue.closed then
   1.177 +          days_ago_text = _( "#{interval_text} ago", {
   1.178 +            interval_text = format.interval_text ( issue.closed_ago )
   1.179 +          })
   1.180 +        else
   1.181 +          days_ago_text = _"phase ends soon" 
   1.182 +        end
   1.183 +        if issue.closed and not issue.fully_frozen then
   1.184 +          negative_event = true
   1.185 +        end
   1.186 +        if issue.state == "finished_without_winner" 
   1.187 +            or issue.state == "canceled_no_initiative_admitted"
   1.188 +            or issue.state == "canceled_by_admin"
   1.189 +        then
   1.190 +          negative_event = true
   1.191 +        end
   1.192 +      end
   1.193 +
   1.194 +      local class= "event_info"
   1.195 +      
   1.196 +      if negative_event then
   1.197 +        class = class .. " negative"
   1.198 +      end
   1.199 +
   1.200 +      if not for_issue and not for_initiative then
   1.201 +        ui.container{ attr = { class = "mdl-card__title mdl-card--has-fab mdl-card--border" }, content = function()
   1.202 +          if not (config.single_unit_id and config.single_area_id) then
   1.203 +            if not config.single_unit_id then
   1.204 +              slot.put ( " " )
   1.205 +              ui.link{
   1.206 +                module = "index", view = "index", params = { unit = issue.area.unit_id },
   1.207 +                attr = { class = "mdl-chip unit" }, content = function()
   1.208 +                  ui.tag{ attr = { class = "mdl-chip__text" }, content = function()
   1.209 +                    ui.tag{ tag = "i", attr = { class = "material-icons" }, content = "flag" }              
   1.210 +                    slot.put(" ")
   1.211 +                    ui.tag{ content = issue.area.unit.name }
   1.212 +                  end }
   1.213 +                end 
   1.214 +              }
   1.215 +            end
   1.216 +            if not config.single_area_id then
   1.217 +              slot.put(" ")
   1.218 +              ui.link{
   1.219 +                module = "index", view = "index", params = { unit = issue.area.unit_id, area = issue.area_id },
   1.220 +                attr = { class = "mdl-chip area" }, content = function()
   1.221 +                  ui.tag{ attr = { class = "mdl-chip__text" }, content = function()
   1.222 +                    ui.tag{ tag = "i", attr = { class = "material-icons" }, content = "folder" }
   1.223 +                    slot.put(" ")
   1.224 +                    ui.tag{ content = issue.area.name }
   1.225 +                  end}
   1.226 +                end 
   1.227 +              }
   1.228 +            end
   1.229 +          end
   1.230 +          --ui.heading{ level = 2, attr = { class = "mdl-card__title-text", style = "display: block;" }, content = function()
   1.231 +            slot.put(" ")
   1.232 +            ui.link{
   1.233 +              module = "issue", view = "show", id = issue.id,
   1.234 +              attr = { class = "mdl-chip issue" }, content = function()
   1.235 +                ui.tag{ tag = "i", attr = { class = "material-icons" }, content = "label" }
   1.236 +                slot.put(" ")
   1.237 +                ui.tag{ attr = { class = "mdl-chip__text" }, content = issue.name }
   1.238 +            end }
   1.239 +          --end }
   1.240 +          ui.container{ attr = { class = "mdl-card__subtitle-text .mdl-cell--hide-phone" }, content = function()
   1.241 +            ui.container{ attr = { class = class }, content = function ()
   1.242 +              if event_icon then
   1.243 +                ui.tag{ tag = "i", attr = { class = "material-icons" }, content = event_icon }
   1.244 +              end
   1.245 +              slot.put(" ")
   1.246 +              ui.tag { content = event_name }
   1.247 +              slot.put(" ")
   1.248 +              ui.tag{ content = "(" .. days_ago_text .. ")" }
   1.249 +            end }
   1.250 +          end }
   1.251 +          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
   1.252 +            ui.link {
   1.253 +              attr = { class = "mdl-button mdl-js-button mdl-button--fab mdl-button--colored" ,
   1.254 +                style = "position: absolute; right: 20px; bottom: -27px;"
   1.255 +              },
   1.256 +              module = "vote", view = "list", 
   1.257 +              params = { issue_id = issue.id },
   1.258 +              content = function()
   1.259 +                ui.tag{ tag = "i", attr = { class = "material-icons" }, content = config.voting_icon or "mail_outline" }
   1.260 +              end 
   1.261 +            }
   1.262 +          end
   1.263 +        end }
   1.264 +      end
   1.265 +
   1.266 +      if event.suggestion_id then
   1.267 +        ui.container{ attr = { class = "suggestion" }, content = function()
   1.268 +          ui.link{
   1.269 +            text = format.string(event.suggestion.name, {
   1.270 +              truncate_at = 160, truncate_suffix = true
   1.271 +            }),
   1.272 +            module = "initiative", view = "show", id = event.initiative.id,
   1.273 +            params = { suggestion_id = event.suggestion_id },
   1.274 +            anchor = "s" .. event.suggestion_id
   1.275 +          }
   1.276 +        end }
   1.277 +      end
   1.278 +
   1.279 +      if not for_initiative and (not for_issue or event.initiative_id) then
   1.280 +        
   1.281 +        ui.container{ attr = { class = "initiative_list" }, content = function()
   1.282 +          if event.initiative_id then
   1.283 +            local initiative = event.initiative
   1.284 +              
   1.285 +            execute.view{ module = "initiative", view = "_list", params = { 
   1.286 +              issue = issue,
   1.287 +              initiative = initiative,
   1.288 +              for_event = mode == "timeline" and not (event.state == issue.state)
   1.289 +
   1.290 +            } }
   1.291 +          else
   1.292 +            local initiatives = issue.initiatives
   1.293 +            execute.view{ module = "initiative", view = "_list", params = { 
   1.294 +              issue = issue,
   1.295 +              initiatives = initiatives,
   1.296 +              for_event = mode == "timeline" and not (event.state == issue.state)
   1.297 +            } }
   1.298 +          end
   1.299 +        end }
   1.300 +      end
   1.301 +      if app.session.member_id then
   1.302 +        ui.container{ attr = { class = "mdl-card__actions mdl-card--border" }, content = function()
   1.303 +          execute.view{ 
   1.304 +            module = "delegation", view = "_info", params = { 
   1.305 +              issue = issue, member = for_member 
   1.306 +            }
   1.307 +          }
   1.308 +        end }
   1.309 +      end
   1.310 +    end }
   1.311 +
   1.312 +  end
   1.313 +  
   1.314 +  if mode == "timeline" then
   1.315 +    if for_sidebar then
   1.316 +      ui.container { attr = { class = row_class }, content = function ()
   1.317 +        ui.link{
   1.318 +          attr = { class = "moreLink" },
   1.319 +          text = _"Show full history",
   1.320 +          module = "initiative", view = "history", id = for_initiative.id
   1.321 +        }
   1.322 +      end }
   1.323 +    elseif #items > limit then
   1.324 +      ui.container { attr = { class = row_class }, content = function ()
   1.325 +        local params = request.get_param_strings()
   1.326 +        ui.link{
   1.327 +          attr = { class = "moreLink" },
   1.328 +          text = _"Show older events",
   1.329 +          module = request.get_module(),
   1.330 +          view = request.get_view(),
   1.331 +          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,
   1.332 +          params = {
   1.333 +            mode = "timeline",
   1.334 +            event_max_id = last_event_id,
   1.335 +            tab = params["tab"],
   1.336 +            phase = params["phase"],
   1.337 +            closed = params["closed"]
   1.338 +          }
   1.339 +        }
   1.340 +      end }
   1.341 +    elseif #items < 1 then
   1.342 +      ui.container { attr = { class = row_class }, content = _"No more events available" }
   1.343 +    end
   1.344 +  end
   1.345 +  
   1.346 +  if #items < 1 then
   1.347 +    ui.section( function()
   1.348 +      ui.sectionRow( function()
   1.349 +        ui.container{ content = _"No results for this selection" }
   1.350 +      end )
   1.351 +    end )
   1.352 +  end
   1.353 +  
   1.354 +  
   1.355 +end
   1.356 +
   1.357 +
   1.358 +local filters = {}
   1.359 +
   1.360 +if not for_initiative and not for_issue and not no_filter then
   1.361 +  
   1.362 +  filters = execute.chunk{
   1.363 +    module = "issue", chunk = "_filters", params = {
   1.364 +    for_events = mode == "timeline" and true or false,
   1.365 +    member = app.session.member, 
   1.366 +    for_member = for_member, 
   1.367 +    state = for_state, 
   1.368 +    for_unit = for_unit and true or false, 
   1.369 +    for_area = for_area and true or false
   1.370 +  }}
   1.371 +end
   1.372 +
   1.373 +filters.opened = true
   1.374 +filters.selector = selector
   1.375 +
   1.376 +
   1.377 +local function dotabs()
   1.378 +  slot.select("filter", function()
   1.379 +    ui.container{ attr = { class = "mdl-tabs mdl-js-tabs mdl-js-ripple-effect float-left" }, content = function()
   1.380 +      ui.container{ attr = { class = "mdl-tabs__tab-bar" }, content = function()
   1.381 +        local mode = request.get_param{ name = "mode" }
   1.382 +        local css_active = (not mode or mode == "issue") and " is-active" or ""
   1.383 +        ui.link{ module = request.get_module(), view = request.get_view(), id = request.get_id_string(), content = "Issues", attr = { class = "mdl-tabs__tab" .. css_active } }
   1.384 +        local css_active = mode and " is-active" or " "
   1.385 +        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 } }
   1.386 +        ui.link{ module = "member", view = "list", content = "Member", attr = { class = "mdl-tabs__tab" } }
   1.387 +      end }
   1.388 +    end }
   1.389 +  end)
   1.390 +end
   1.391 +
   1.392 +
   1.393 +if mode == "timeline" then
   1.394 +  --dotabs()
   1.395 +  filters.content = function()
   1.396 +    execute.view{ module = "index", view = "_head" }
   1.397 +    doit()
   1.398 +  end
   1.399 +else
   1.400 +  -- dotabs()
   1.401 +  filters.content = function()
   1.402 +    if config.voting_only then
   1.403 +      local admission_order_field = "filter_issue_order.order_in_unit"
   1.404 +      if for_area then
   1.405 +        admission_order_field = "filter_issue_order.order_in_area"
   1.406 +      end
   1.407 +      selector:left_join ( "issue_order_in_admission_state", "filter_issue_order",    "filter_issue_order.id = issue.id" )
   1.408 +      selector:add_order_by ( "issue.closed DESC NULLS FIRST" )
   1.409 +      selector:add_order_by ( "issue.accepted ISNULL" )
   1.410 +      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" )
   1.411 +      selector:add_order_by ( "CASE WHEN issue.accepted ISNULL THEN " .. admission_order_field .. " ELSE NULL END" )
   1.412 +      selector:add_order_by ( "id" )
   1.413 +    end
   1.414 +    execute.view{ module = "index", view = "_head" }
   1.415 +    ui.paginate{
   1.416 +      selector = selector,
   1.417 +      per_page = 25,
   1.418 +      content = doit
   1.419 +    }
   1.420 +  end
   1.421 +end
   1.422 +
   1.423 +filters.class = "mdl-special-card mdl-card__fullwidth mdl-shadow--2dp"
   1.424 +
   1.425 +ui.filters(filters)
   1.426 +
   1.427 +
   1.428 +      

Impressum / About Us