estimage/webapp/templates/issue_view.html
{%- if mode == "proj" %}
{% extends "general_plan.html" %}
{%- else %}
{% extends "general_retro.html" %}
{%- endif %}
{% import "utils.j2" as utils with context %}
{% from 'bootstrap5/form.html' import render_form %}
{% macro format_tracker_task_size() -%}
{% set time_cost_is_relevant = task.time_cost -%}
{% set point_cost_is_relevant = task.point_cost or not time_cost_is_relevant -%}
{% if point_cost_is_relevant -%}
<p>Point cost: {{ task.point_cost }}</p>
{%- endif -%}
{% if time_cost_is_relevant -%}
<p>Time cost: {{ task.time_cost }}{% if task.TIME_UNIT %} {{ task.TIME_UNIT }} {%- endif %}</p>
{%- endif -%}
{%- endmacro %}
{% set all_story_points = [1, 2, 3, 5, 8, 13] %}
{% macro id_of_populate_btn(sp) -%}
populate-{{ sp }}
{%- endmacro %}
{% macro populate_btn(sp) -%}
<div><a type="button" class="btn btn-outline-primary" id="{{ id_of_populate_btn(sp) }}">{{ sp }} SP</a></div>
{%- endmacro %}
{% macro space_evenly(elements) -%}
<div class="d-flex justify-content-evenly">{{ "".join(elements) | safe }}</div>
{%- endmacro %}
{% macro estimation_form_in_accordion(estimate_exists) -%}
{% set fillers_str = [] %}
{% for pval in all_story_points %}
{% set temp = fillers_str.append(populate_btn(pval)) %}
{% endfor %}
{{ utils.accordion_with_stuff(
"Estimation", estimate_exists,
("Modify" if estimate_exists else "Create") ~ " the estimate",
space_evenly(fillers_str) | safe ~
render_form(forms["estimation"], button_map={"submit": "primary", "delete": "danger"}, action=head_url_for("main.estimate", task_name=task.name))
)
}}
{%- endmacro %}
{% block content %}
<div class="container">
<div class="row">
<h1>Estimate</h1>
{{ utils.task_metadata(task) | indent(4) }}
<h2>Estimates</h2>
<div class="row">
<div class="col">
{%- if context.estimation_source == "none" %}
<p>Point estimate: {{ utils.render_precise_estimate(task.point_cost) }}</p>
{%- else %}
<p>Point estimate: {{ utils.render_estimate(context.estimation) }}</p>
{%- endif %}
{%- if context.estimation_source == "own" %}
<p>The estimate is based on your personal estimate that is not visible to others.</p>
{%- endif %}
{%- if context.estimation_source == "global" %}
<p>The estimate is based on the consensus estimate.</p>
{%- endif %}
{%- if context.estimation_source == "none" %}
<p>The estimate is based on the data from the issue tracker.</p>
{%- endif %}
{%- if context.estimate_status == "duplicate" %}
<p>Your personal estimate and consensus are the same. Remove the redundant personal estimate.</p>
{%- elif context.estimate_status == "contradictory" %}
<p>Your personal estimate is different than the global consensus, and overrides it for you.</p>
{%- endif %}
{%- if not context.authoritative_record_exists %}
<p>The issue doesn't seem to be estimated in the issue tracker.</p>
{%- elif context.estimation_source == "global" %}
{%- if context.authoritative_record_consistent %}
<p>The estimation and its record in the issue tracker are consistent.</p>
{%- else %}
<p>The estimation and its record in the issue tracker aren't consistent, consider updating whatever is invalid.</p>
{%- endif %}
{%- endif %}
</div>
<div class="col">
<img src="{{ head_url_for('vis.visualize_task_nominal', task_name=task.name, mode=mode) }}" alt="PERT prob density function for {{ task.name }}"/>
</div>
{% if not forms %}
<div class="col">
<img src="{{ head_url_for('vis.visualize_epic_burndown', epic_name=task.name, size='normal') }}" alt="Burndown for {{ task.name }}"/>
</div>
{%- endif %}
</div>
{% if forms %}
<div class="row">
{% block forms %}
<h3>Consensus values</h3>
{% if context.global_estimate_exists %}
<p>Point cost: {{ utils.render_estimate(context.global_estimate) }}</p>
{% endif %}
{% if "consensus" in forms %}
{{ render_form(forms["consensus"], button_map={"submit": "primary", "delete": "danger"}, action=head_url_for("main.act_on_global_estimate", task_name=task.name)) }}
{% endif %}
</div>
<div class="col">
<h3>Our values</h3>
{{ estimation_form_in_accordion(context.own_estimation_exists) }}
{% endblock %}
</div>
{%- if similar_sized_cards %}
{{ utils.render_similar_sized_tasks(similar_sized_cards) }}
{%- endif %}
{%- endif %}
</div>
{% endblock %}
{% block footer %}
{{ super() }}
{% if forms %}
{% if "authoritative" in forms -%}
{{ forms["authoritative"].supporting_js([forms["authoritative"]]) | safe }}
<script>
{% for pval in all_story_points %}
// JavaScript to handle button click and populate form fields
document.getElementById("{{ id_of_populate_btn(pval) }}").addEventListener('click', function() {
document.getElementById('optimistic').value = {{ "%.3g" % (pval * 0.468) }};
document.getElementById('most_likely').value = {{ "%.3g" % (pval * 0.904) }};
document.getElementById('pessimistic').value = {{ "%.3g" % (pval * 1.92) }};
});
{% endfor %}
</script>
{%- endif %}
{%- endif %}
{% endblock %}