bsw@1045: local issue = param.get("issue", "table") bsw@1045: local initiative = param.get("initiative", "table") bsw@1045: bsw@1045: local view_module bsw@1045: local view_id bsw@1045: bsw@1045: if initiative then bsw@1045: issue = initiative.issue bsw@1045: view_module = "initiative" bsw@1045: view_id = initiative.id bsw@1045: else bsw@1045: view_module = "issue" bsw@1045: view_id = issue.id bsw@1045: end bsw@1045: bsw/jbe@1309: local current_occured = false bsw/jbe@1309: local failed = false bsw/jbe@1309: bsw/jbe@1309: ui.tag{ tag = "table", content = function() bsw@1045: bsw/jbe@1309: local function quorum_text(policy, quorum) bsw/jbe@1309: local num bsw/jbe@1309: local den bsw@1481: bsw/jbe@1309: if quorum == 1 then bsw/jbe@1309: return math.max(policy.issue_quorum or 0, issue.issue_quorum or 0) bsw/jbe@1309: elseif quorum == 2 then bsw/jbe@1309: num = policy.initiative_quorum_num bsw/jbe@1309: den = policy.initiative_quorum_den bsw/jbe@1309: end bsw@1481: bsw@1481: local quorums = {} bsw@1481: bsw@1481: if num and num > 0 and den == 100 or den == 10 then bsw@1481: table.insert(quorums, _("#{percentage}%", { percentage = num * 100 / den })) bsw@1481: elseif num and num > 0 and den and den > 0 then bsw@1481: table.insert(quorums, num .. "/" .. den) bsw/jbe@1309: end bsw@1481: bsw@1481: if policy.initiative_quorum then bsw@1481: table.insert(quorums, policy.initiative_quorum) bsw/jbe@1309: end bsw@1481: bsw@1481: return table.concat(quorums, " / ") bsw/jbe@1309: end bsw@1045: bsw/jbe@1309: local phases = { "admission", "discussion", "verification", "voting" } bsw/jbe@1309: bsw/jbe@1309: for i, state in ipairs(phases) do bsw/jbe@1309: local current = state == issue.state bsw/jbe@1309: bsw/jbe@1309: if current then bsw/jbe@1309: current_occured = true bsw/jbe@1309: end bsw@1045: bsw/jbe@1309: local phase_success = ( bsw/jbe@1309: (state == "admission" and issue.accepted) bsw/jbe@1309: or (state == "discussion" and issue.half_frozen) bsw/jbe@1309: or (state == "verification" and issue.fully_frozen and issue.state ~= "canceled_no_initiative_admitted") bsw/jbe@1309: or (state == "voting" and issue.closed and issue.state ~= "canceled_no_initiative_admitted" and issue.state ~= "canceled_by_admin") bsw/jbe@1309: ) bsw/jbe@1309: bsw/jbe@1309: if not failed then bsw/jbe@1309: ui.container{ tag = "div", attr = { id = "phase-" .. state, class = current and "phase-current" or nil }, content = function() bsw@1045: bsw/jbe@1309: local state_names = { bsw/jbe@1309: admission = _"Admission", bsw/jbe@1309: discussion = _"Discussion", bsw/jbe@1309: verification = _"Verification", bsw/jbe@1309: voting = _"Voting" bsw/jbe@1309: } bsw@1045: bsw/jbe@1309: local state_name = state_names[state] or state bsw/jbe@1309: bsw/jbe@1309: local quorum bsw/jbe@1309: if state == "admission" then bsw/jbe@1309: quorum = quorum_text(issue.policy, 1) bsw/jbe@1309: elseif state == "verification" then bsw/jbe@1309: quorum = quorum_text(issue.policy, 2) bsw/jbe@1309: end bsw/jbe@1309: bsw/jbe@1309: local time_text bsw/jbe@1309: if current then bsw/jbe@1309: local time_left bsw/jbe@1309: if issue.state_time_left:sub(1,1) ~= "-" then bsw/jbe@1309: time_text = format.interval_text(issue.state_time_left, { mode = "time_left" }) bsw/jbe@1309: else bsw/jbe@1309: time_text = "phase ends soon" bsw/jbe@1309: end bsw/jbe@1309: elseif current_occured then bsw/jbe@1309: local phase_duration = issue[state .. "_time_text"] bsw/jbe@1309: time_text = _("#{duration}", { duration = format.interval_text(phase_duration) } ) bsw/jbe@1309: else bsw/jbe@1309: local text = "failed" bsw/jbe@1309: if quorum then bsw/jbe@1309: text = _("failed #{quorum}", { quorum = quorum }) bsw/jbe@1309: end bsw/jbe@1309: if phase_success then bsw/jbe@1309: if quorum == 0 then bsw/jbe@1309: text = _"without quorum" bsw/jbe@1309: elseif quorum then bsw/jbe@1309: text = _("reached #{quorum}", { quorum = quorum }) bsw/jbe@1309: else bsw/jbe@1309: text = _"finished" bsw/jbe@1309: end bsw/jbe@1309: elseif issue.state == "canceled_revoked_before_accepted" or bsw/jbe@1309: issue.state == "canceled_after_revocation_during_discussion" or bsw/jbe@1309: issue.state == "canceled_after_revocation_during_verification" bsw/jbe@1309: then bsw/jbe@1309: text = _"revoked" bsw/jbe@1309: elseif issue.state == "canceled_by_admin" then bsw/jbe@1309: text = _"canceled" bsw/jbe@1309: end bsw/jbe@1309: time_text = text bsw/jbe@1309: end bsw@1045: bsw/jbe@1309: if not config.voting_only or state == "voting" then bsw/jbe@1309: if current then bsw/jbe@1309: ui.tag{ tag = "i", attr = { class = "material-icons" }, content = "play_arrow" } bsw/jbe@1309: elseif not current_occured and not phase_success then bsw/jbe@1309: ui.tag{ tag = "i", attr = { class = "material-icons" }, content = "clear" } bsw/jbe@1309: elseif current_occured and issue.accepted then bsw/jbe@1309: ui.tag{ tag = "i", attr = { class = "material-icons" }, content = "schedule" } bsw/jbe@1309: elseif current_occured then bsw/jbe@1309: ui.tag{ tag = "i", attr = { class = "material-icons" }, content = "lock" } bsw/jbe@1309: else bsw/jbe@1309: ui.tag{ tag = "i", attr = { class = "material-icons" }, content = "check" } bsw@1045: end bsw@1045: bsw/jbe@1309: if not config.voting_only then bsw/jbe@1309: slot.put(" ") bsw@1045: end bsw@1045: bsw/jbe@1309: ui.tag{ attr = { class = "mdl-data-table__cell--non-numeric" }, content = function() bsw/jbe@1309: if not config.voting_only then bsw/jbe@1309: ui.tag{ content = i .. "." } bsw@1045: end bsw@1045: slot.put(" ") bsw/jbe@1309: ui.tag{ content = state_name } bsw/jbe@1309: end} bsw/jbe@1309: ui.tag{ content = " (" .. time_text .. ")"} bsw/jbe@1309: bsw/jbe@1309: slot.put(" ") bsw/jbe@1309: bsw/jbe@1309: if not current then bsw/jbe@1309: ui.tag{ tag = "i", attr = { onclick = "document.getElementById('phase-info-" .. i .. "').classList.toggle('hidden');", class = "material-icons material-icons-small clickable" }, content = "info_outline" } bsw/jbe@1309: end bsw/jbe@1309: end bsw/jbe@1309: bsw/jbe@1309: end } bsw/jbe@1309: bsw/jbe@1309: local help_texts = { bsw/jbe@1309: admission = _("As soon as one initiative of this issue reaches the 1st quorum of #{quorum} support, the issue will proceed to discussion phase.", { quorum = quorum_text(issue.policy, 1) }), bsw/jbe@1309: discussion = _"During the discussion phase, the issue is debated on while the initiators improve the proposals and reasons in their initiatives. Supporters of initiatives can write and rate suggestions for improvement.", bsw/jbe@1309: verification = _("During the verification phase, existing initiatives cannot be changed anymore. Initiatives need to pass the 2nd quorum of #{quorum} at end of verification phase to become admitted for voting.", { quorum = quorum_text(issue.policy, 2) }), bsw/jbe@1309: voting = _"During the voting phase, votes for all admitted initiatives in this issue can be cast. The final result will be calculated as soon as this phase ends." bsw/jbe@1309: } bsw/jbe@1309: bsw/jbe@1309: local class = "phase-info" bsw/jbe@1309: if not current then bsw/jbe@1309: class = class .. " hidden" bsw/jbe@1309: end bsw@1060: bsw/jbe@1309: if not config.voting_only then bsw/jbe@1309: ui.container { attr = { id = "phase-info-" .. i, class = class }, content = help_texts[state] } bsw@1045: end bsw@1045: bsw/jbe@1309: end bsw/jbe@1309: bsw/jbe@1309: if not phase_success and not current and not current_occured then bsw/jbe@1309: failed = true bsw@1045: end bsw/jbe@1309: end bsw/jbe@1309: bsw/jbe@1309: end } bsw/jbe@1309: bsw/jbe@1309: if issue.closed then bsw/jbe@1309: ui.tag{ content = issue.state_name } bsw/jbe@1309: end