liquid_feedback_frontend

annotate app/main/issue/_list.lua @ 1525:628e1b9126c0

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

Impressum / About Us