matejak/estimagus

View on GitHub
estimage/webapp/templates/utils.j2

Summary

Maintainability
Test Coverage
{% from 'bootstrap5/utils.html' import render_icon %}
{% from 'bootstrap5/form.html' import render_form %}

{% macro render_whatever_retro(card, model, today, recursive=true) %}
{% if card.children %}
{{ render_epic_retro(card, model, today, recursive) }}
{% else %}
{{ render_task(card, "retrospective", model) }}
{% endif %}
{% endmacro %}

{% macro render_epic_retro(epic, model, today, recursive=true) %}
    <li>
        <div id="{{ epic.name }}">
        {{ epic_link(epic, "retrospective") }} &mdash; {{ epic.title }}
        <div class="container-md">
           <div class="row">
              <div class="col">

        <p>
        {{ state_to_string(epic.status) }}, {{ "%.2g" % model.remaining_point_estimate_of(epic.name).expected }} points remaining.
        </p>
        <p>
    Owner:
        {%- if epic.assignee -%}
    {{ " " ~ epic.assignee }}
        {%- else -%}
    {{ " nobody" }}
        {%- endif %}
        </p>
        {% if epic.status_summary -%}
        <p>
    Summary
        {%- if epic.status_summary_time -%}
    {{ " " ~ (today - epic.status_summary_time).days }} days old
        {%- endif -%}
    : {{ epic.status_summary | safe }}</p>
        {%- endif %}
        {% if recursive -%}
        {% for card in (epic.children | sort(attribute="name")) %}
        <ul>
            {{- render_whatever_retro(card, model, today, recursive=recursive) -}}
        </ul>
        {% endfor %}
        {%- endif %}

              </div>
              {% if model.remaining_point_estimate_of(epic.name).expected > 0 %}
              <div class="col">
    <img src="{{ head_url_for('vis.visualize_epic_burndown', epic_name=epic.name, size="small") }}" alt="Epic Burndown"/>
              </div>
              {% endif %}
           </div>
        </div>
        </div>
    </li>
{% endmacro %}

{% macro render_whatever(card, model, recursive=true) %}
{% if card.children %}
{{ render_epic(card, model, recursive=recursive) }}
{% else %}
{{ render_task(card, "projective", model) }}
{% endif %}
{% endmacro %}

{% macro refresh_whatever(card, mode, next) -%}
        <a href="{{ head_url_for("main.refresh_single", name=card.name, mode=mode, next=next) }}">{{ render_icon("arrow-clockwise") }}</a>
{%- endmacro %}

{% set task_type_to_function = {
    "projective": "main.view_projective_task",
    "retrospective": "main.view_retro_task",
} %}

{% set epic_type_to_function = {
    "projective": "main.view_epic_proj",
    "retrospective": "main.view_epic_retro",
} %}

{% macro task_or_epic_link(card, type) -%}
{% if card.children %}
{{ epic_link(card, type) }}
{% else %}
{{ task_link(card, type) }}
{% endif %}
{%- endmacro %}

{% macro task_link(task, type) -%}
        <a href="{{ head_url_for(task_type_to_function[type], task_name=task.name) }}">{{ task.name }}</a>&nbsp;<a href="{{ task.uri }}" rel="external">{{ render_icon("box-arrow-up-right") }}</a>
{%- endmacro %}

{% macro epic_external_link(epic) -%}
    <a href="{{ epic.uri }}" rel="external">{{ render_icon("box-arrow-up-right") }}</a>
{%- endmacro %}

{% macro epic_link(epic, type="projective") -%}
        <a href="{{ head_url_for(epic_type_to_function[type], epic_name=epic.name) }}">{{ epic.name }}</a>&nbsp;{{ epic_external_link(epic) }}
{%- endmacro %}

{% macro render_state_short(state) -%}
        <span class="state.style_class">state.shortcut</span>
{%- endmacro %}

{% macro render_state(state) -%}
        <span class="state.style_class">state.name</span>
{%- endmacro %}

{% macro render_task_basic(task, task_type, model) -%}
        {{ task_link(task, task_type) }} &mdash; <span class="task-state">{{ state_to_string(task.status) }}</span><span class="task-points {{- " uncounted_points" if model and model.get_element(task.name).masked }}">{{ "%.2g" % task.point_cost }}</span>
    {{ truncate_text_to(task.title, "350pt") }}
{%- endmacro %}

{% macro truncate_text_to(text, width) -%}
<span class="d-inline-block text-truncate align-top" style="max-width: {{ width }};">{{ text }}</span>
{%- endmacro %}

{% macro render_task(task, task_type, model) %}
        <li>
        <div id={{ task.name }}">
        {{- render_task_basic(task, task_type, model) -}}
        </div>
        </li>
{% endmacro %}

{% macro render_epic_basic(epic) %}
        {{ epic_link(epic) }} &mdash; {{ epic.title }}
{% endmacro %}

{% macro render_epic(epic, model, recursive=true) %}
        <li>
        <div id={{ epic.name }}">
        {{ render_epic_basic(epic) }}
        {% if model.remaining_point_estimate.expected > 0 %}
        <p>
        Left to do: {{ "%.3g" % model.remaining_point_estimate_of(epic.name).expected }}, i.e. {{ "%i %%" % (model.remaining_point_estimate_of(epic.name).expected / model.remaining_point_estimate.expected * 100) }} of the whole
        </p>
        {% endif %}
        {% if recursive -%}
        <ul>
            {% for card in (epic.children | sort(attribute="name")) %}
            {{- render_whatever(card, model, recursive=recursive) -}}
            {% endfor %}
        </ul>
        {%- endif %}
        </div>
        </li>
{% endmacro %}

{% macro render_estimate(estimate, unit="") -%}
    {{ "{expected:.3g}{unit_with_space}, 𝜎 = {sigma:.2g}{unit_with_space}".format(
        expected=estimate.expected, sigma=estimate.sigma, unit_with_space=" " ~ unit) }}
{%- endmacro %}

{% macro render_precise_estimate(number, unit="") -%}
    {{ "{expected:.3g}{unit_with_space}".format(
        expected=number, unit_with_space=" " ~ unit) }}
{%- endmacro %}


{% macro accordion_with_stuff(stem, collapsed, header_text, body_text, heading_level=4) -%}
<div class="accordion" id="accordion{{ stem }}">
<div class="accordion-item">
    <h{{ heading_level }} class="accordion-header" id="accordionHeading">
        <button class="accordion-button {{- " collapsed" if collapsed }}" type="button" data-bs-toggle="collapse" data-bs-target="#collapse{{ stem }}" aria-expanded="{{ "false" if collapsed else "true" }}" aria-controls="collapse{{ stem }}">
            {{ header_text }}
        </button>
    </h{{ heading_level }}>
    <div id="collapse{{ stem }}" class="accordion-collapse collapse {{- " show" if not collapsed }}" aria-labelledby="accordionHeading" data-bs-parent="#accordion{{ stem }}">
        <div class="accordion-body">
            {{ body_text }}
        </div>
    </div>
</div>
</div>
{%- endmacro %}


{% macro task_metadata(task) -%}
<h2>{{ task.title }}</h2>
{% if task.uri -%}
<a href="{{ task.uri }}">{{ task.uri }}</a>
{% endif -%}
<div>State: {{ state_to_string(task.status)  }}</div>
{% if (task.description | length) < 1200 %}
<h3>Description</h3>
<p>
{{ (task.description | safe) or "No description" }}
</p>
{%- else %}
{{ accordion_with_stuff("Description", true, "Description", (task.description | safe) or "No description", 3) }}
{%- endif %}
{%- endmacro %}


{% macro render_similar_sized_tasks(similar_sized_cards) -%}
    <div class="row">
    <h4>Tasks of similar sizes</h4>
    <p>
    <ul>
    {%- for card in similar_sized_cards["proj"] %}
    <li>{{ render_task_basic(card, "projective", None) }}: {{ render_estimate(card.point_estimate) }}</li>
    {%- endfor %}
    {%- for card in similar_sized_cards["retro"] %}
    <li>{{ render_task_basic(card, "retrospective", None) }}: {{ render_estimate(card.point_estimate) }}</li>
    {%- endfor %}
    </ul>
    </p>
    </div>
{%- endmacro %}


{% set states_table = {
    "todo": "To Do",
    "in_progress": "In Progress",
    "review": "Needs Peer Review",
    "done": "Done",
    "abandoned": "Abandoned",
} %}


{% macro state_to_string(state) -%}
    {{ states_table.get(state, state) }}
{%- endmacro %}