liquid_feedback_frontend

annotate app/main/issue/_list.lua @ 1506:a79ffcdc49eb

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

Impressum / About Us