Skip to content

Commit

Permalink
Big Prio and refactoring leap forward
Browse files Browse the repository at this point in the history
  • Loading branch information
matejak committed Sep 8, 2024
1 parent a6395e3 commit f63393d
Show file tree
Hide file tree
Showing 16 changed files with 260 additions and 83 deletions.
5 changes: 4 additions & 1 deletion estimage/plugins/base/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,8 @@ def __init__(self, ** kwargs):
super().__init__(** kwargs)

@classmethod
def supporting_js(cls, forms):
def bulk_supporting_js(cls, forms):
return ""

def supporting_js(self):
return self.bulk_supporting_js([self])
8 changes: 4 additions & 4 deletions estimage/plugins/crypto/templates/crypto-issue_view.html
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
{% extends "issue_view.html" %}

{% block forms %}
{% block estimation %}
<div class="col">
<h3>Jira values</h3>
<p>
{{ format_tracker_task_size() | indent(8) -}}
{% if "authoritative" in forms -%}
{{ render_form(forms["authoritative"], action=head_url_for("main.move_consensus_estimate_to_authoritative", task_name=task.name)) }}
{% if "authoritative" in card_details.forms -%}
{{ render_form(card_details.forms["authoritative"], action=head_url_for("main.move_consensus_estimate_to_authoritative", task_name=task.name)) }}
{%- endif %}
</p>
</div>
<div class="col">
<h3>Estimagus values</h3>
{{ estimation_form_in_accordion(context.own_estimation_exists) }}
</div>
{% endblock %}
{% endblock estimation %}
2 changes: 1 addition & 1 deletion estimage/plugins/crypto/templates/crypto.html
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,5 @@ <h1>Crypto Plugin</h1>

{% block footer %}
{{ super() }}
{{ plugin_form.supporting_js([plugin_form]) | safe }}
{{ plugin_form.supporting_js() | safe }}
{% endblock %}
2 changes: 1 addition & 1 deletion estimage/plugins/jira/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ def _perform_work_with_token_encryption(self):
return True

@classmethod
def supporting_js(cls, forms):
def bulk_supporting_js(cls, forms):
template = textwrap.dedent("""
<script type="text/javascript">
function tokenName() {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
{% extends ancestor_of_redhat_compliance %}

{% block forms %}
{% block estimation %}
<div class="col">
<h3>Jira values</h3>
<p>
{{ format_tracker_task_size() | indent(8) -}}
{% if "authoritative" in forms -%}
{{ render_form(forms["authoritative"], action=head_url_for("main.move_consensus_estimate_to_authoritative", task_name=task.name)) }}
{% if "authoritative" in card_details.forms -%}
{{ render_form(card_details.forms["authoritative"], action=head_url_for("main.move_consensus_estimate_to_authoritative", task_name=task.name)) }}
{%- endif %}
</p>
</div>
<div class="col">
<h3>Estimagus values</h3>
{{ estimation_form_in_accordion(context.own_estimation_exists) }}
</div>
{% endblock %}
{% endblock estimation %}
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,5 @@ <h1>Red Hat Compliance Plugin</h1>

{% block footer %}
{{ super() }}
{{ plugin_form.supporting_js([plugin_form]) | safe }}
{{ plugin_form.supporting_js() | safe }}
{% endblock %}
2 changes: 1 addition & 1 deletion estimage/plugins/redhat_jira/templates/jira.html
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,5 @@ <h1>Jira Plugin</h1>

{% block footer %}
{{ super() }}
{{ plugin_form.supporting_js([plugin_form]) | safe }}
{{ plugin_form.supporting_js() | safe }}
{% endblock %}
19 changes: 19 additions & 0 deletions estimage/plugins/wsjf/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from ... import persistence
from . import forms


TEMPLATE_OVERRIDES = {
Expand All @@ -7,9 +8,27 @@

EXPORTS = {
"BaseCard": "WSJFCard",
"ProjectiveForms": "ProjectiveForms",
}


class ProjectiveForms:
def add_sections(self):
super().add_sections()
self._add_section(20, name="wsjf", title="Prioritization")

def instantiate_forms(self, app):
super().instantiate_forms(app)
form = forms.WSJFForm()
self.forms["wsjf"] = form

def setup_forms_according_to_context(self, context, card):
super().setup_forms_according_to_context(context, card)
self.forms["wsjf"].business_value.data = card.business_value
self.forms["wsjf"].time_sensitivity.data = card.time_sensitivity
self.forms["wsjf"].risk_and_opportunity.data = card.risk_and_opportunity


class WSJFCard:
business_value: float = 0
risk_and_opportunity: float = 0
Expand Down
2 changes: 1 addition & 1 deletion estimage/plugins/wsjf/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

class WSJFForm(BaseForm):
business_value = wtforms.DecimalField("Business Value")
risk_opportunity = wtforms.DecimalField("Risk Reduction / Opportunity Enablement")
risk_and_opportunity = wtforms.DecimalField("Risk Reduction / Opportunity Enablement")
time_sensitivity = wtforms.DecimalField("Time Sensitivity")
task_name = wtforms.HiddenField('task_name')
submit = wtforms.SubmitField("Update Priority")
22 changes: 18 additions & 4 deletions estimage/plugins/wsjf/routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,29 @@
import flask_login

from . import forms
from ...webapp import web_utils, routers
from ...webapp.main import cards

bp = flask.Blueprint("wsjf", __name__, template_folder="templates")


@bp.route('/prioritize', methods=("POST",))
def _update_card_priority(card_name, io_cls, form):
card_cls = flask.current_app.get_final_class("BaseCard")
card = card_cls.load_metadata(card_name, io_cls)
card.business_value = form.business_value.data
card.risk_and_opportunity = form.risk_and_opportunity.data
card.time_sensitivity = form.time_sensitivity.data
card.save_metadata(io_cls)


@bp.route('/prioritize/<task_name>', methods=("POST",))
@flask_login.login_required
def sync():
def prioritize(task_name):
form = forms.WSJFForm()
if form.validate_on_submit():
pass
io_cls = routers.IORouter().get_card_io("proj")
_update_card_priority(task_name, io_cls, form)
routers.CardRouter.clear_cache()
form.task_name.data = task_name

return flask.url_for()
return cards.view_projective_task(task_name=task_name, known_forms=dict(wsjf=form))
26 changes: 23 additions & 3 deletions estimage/plugins/wsjf/templates/prio_issue_fields.html
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
{% extends ancestor_of_wsjf %}

{% block forms %}
{{ super() }}
{% macro prio_table() %}
<div class="col">
<h3>Priority etc.</h3>
<h4>WSJF Score</h4>
Expand Down Expand Up @@ -47,6 +46,7 @@ <h4>Intrinsic Priority</h4>
</tbody>
</table>
<h4>Inherited Priority</h4>
{% if task.inherited_priority %}
<table class="table table-sm">
<thead>
<tr>
Expand All @@ -63,5 +63,25 @@ <h4>Inherited Priority</h4>
{% endfor %}
</tbody>
</table>
{% else %}
No prioritized items depend on this card.
{% endif %}
</div>
{% endmacro %}

{% macro prio_form() %}
<div class="col">
<h3>Set Priority</h3>
{{ render_form(card_details.forms["wsjf"], button_map={"submit": "primary"}, action=head_url_for("wsjf.prioritize", task_name=task.name)) }}
</div>
{% endblock %}
{% endmacro %}

{% block card_details %}
{{ super() }}
{% call specific_issue_content("wsjf") %}
{% block wsjf %}
{{ prio_table() }}
{{ prio_form() }}
{% endblock wsjf %}
{% endcall %}
{% endblock card_details %}
124 changes: 81 additions & 43 deletions estimage/webapp/main/cards.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import datetime
import dataclasses
import collections

import flask
Expand All @@ -9,7 +10,7 @@
from ... import simpledata as webdata
from ... import history
from ... import data
from ... import utilities, statops
from ... import utilities, statops, PluginResolver


def give_data_to_context(context, user_pollster, global_pollster):
Expand All @@ -32,39 +33,7 @@ def feed_estimation_to_form(estimation, form_data):
form_data.pessimistic.data = estimation.source.pessimistic


def _setup_forms_according_to_context(request_forms, context):
if context.own_estimation_exists:
request_forms["estimation"].enable_delete_button()
request_forms["consensus"].enable_submit_button()
if context.global_estimation_exists:
request_forms["consensus"].enable_delete_button()
request_forms["authoritative"].clear_to_go()
request_forms["authoritative"].task_name.data = context.task_name
request_forms["authoritative"].point_cost.data = ""

if context.estimation_source == "none":
fallback_estimation = data.Estimate.from_input(data.EstimInput(context.task_point_cost))
feed_estimation_to_form(fallback_estimation, request_forms["estimation"])
else:
feed_estimation_to_form(context.estimation, request_forms["estimation"])


def _setup_simple_forms_according_to_context(request_forms, context):
if context.own_estimation_exists:
request_forms["estimation"].enable_delete_button()
if context.global_estimation_exists:
request_forms["authoritative"].clear_to_go()
request_forms["authoritative"].task_name.data = context.task_name
request_forms["authoritative"].point_cost.data = ""

if context.estimation_source == "none":
fallback_estimation = data.Estimate.from_input(data.EstimInput(context.task_point_cost))
feed_estimation_to_form(fallback_estimation, request_forms["estimation"])
else:
feed_estimation_to_form(context.estimation, request_forms["estimation"])


def view_task(task_name, breadcrumbs, mode, request_forms=None):
def view_task(task_name, breadcrumbs, mode, card_details=None):
card_r = routers.CardRouter(mode=mode)
task = card_r.all_cards_by_id[task_name]

Expand All @@ -78,8 +47,8 @@ def view_task(task_name, breadcrumbs, mode, request_forms=None):
context = webdata.Context(task)
give_data_to_context(context, pollster, c_pollster)

if request_forms:
_setup_simple_forms_according_to_context(request_forms, context)
if card_details:
card_details.setup_forms_according_to_context(context, task)

similar_cards = []
if context.estimation_source != "none":
Expand All @@ -90,7 +59,7 @@ def view_task(task_name, breadcrumbs, mode, request_forms=None):

return web_utils.render_template(
'issue_view.html', title='Estimate Issue', breadcrumbs=breadcrumbs, mode=mode,
user=poll_r.user, forms=request_forms, task=task, context=context, similar_sized_cards=similar_cards)
user=poll_r.user, card_details=card_details, task=task, context=context, similar_sized_cards=similar_cards)


def get_projective_breadcrumbs():
Expand All @@ -105,20 +74,89 @@ def get_retro_breadcrumbs():
return breadcrumbs


@dataclasses.dataclass
class Section:
name: str
title: str


@PluginResolver.class_is_extendable("ProjectiveForms")
class ProjectiveDetails:
def __init__(self):
self.forms = dict()
self.sections_by_priority = dict()
self._known_section_names = set()
self.add_sections()

def get_category(self, name):
for section in self.sections_by_priority.values():
if section.name == name:
return section
msg = f"Couldn't find category '{name}', knows only {list(self._known_section_names)}"
raise KeyError(msg)

@property
def ordered_sections(self):
ordered_keys = sorted(self.sections_by_priority.keys())
ordered_values = [self.sections_by_priority[key] for key in ordered_keys]
return ordered_values

def _add_section(self, priority, ** kwargs):
section = Section(** kwargs)
self.sections_by_priority[priority] = section
self._known_section_names.add(kwargs["name"])

def add_sections(self):
self._add_section(10, name="estimation", title="Estimation")

def instantiate_forms(self, app):
self.forms["estimation"] = forms.SimpleEstimationForm()
self.forms["authoritative"] = app.get_final_class("AuthoritativeForm")()

def setup_forms_according_to_context(self, context, card):
if context.own_estimation_exists:
self.forms["estimation"].enable_delete_button()
if context.global_estimation_exists:
self.forms["authoritative"].clear_to_go()
self.forms["authoritative"].task_name.data = context.task_name
self.forms["authoritative"].point_cost.data = ""

if context.estimation_source == "none":
fallback_estimation = data.Estimate.from_input(data.EstimInput(context.task_point_cost))
feed_estimation_to_form(fallback_estimation, self.forms["estimation"])
else:
feed_estimation_to_form(context.estimation, self.forms["estimation"])


def _setup_forms_according_to_context(request_forms, context):
if context.own_estimation_exists:
request_forms["estimation"].enable_delete_button()
request_forms["consensus"].enable_submit_button()
if context.global_estimation_exists:
request_forms["consensus"].enable_delete_button()
request_forms["authoritative"].clear_to_go()
request_forms["authoritative"].task_name.data = context.task_name
request_forms["authoritative"].point_cost.data = ""

if context.estimation_source == "none":
fallback_estimation = data.Estimate.from_input(data.EstimInput(context.task_point_cost))
feed_estimation_to_form(fallback_estimation, request_forms["estimation"])
else:
feed_estimation_to_form(context.estimation, request_forms["estimation"])


@bp.route('/projective/task/<task_name>')
@flask_login.login_required
def view_projective_task(task_name, known_forms=None):
if known_forms is None:
known_forms = dict()

request_forms = dict(
estimation=forms.SimpleEstimationForm(),
authoritative=flask.current_app.get_final_class("AuthoritativeForm")(),
)
request_forms.update(known_forms)
card_details = flask.current_app.get_final_class("ProjectiveForms")()
card_details.instantiate_forms(flask.current_app)
card_details.forms.update(known_forms)

breadcrumbs = get_projective_breadcrumbs()
return view_task(task_name, breadcrumbs, "proj", request_forms)
return view_task(task_name, breadcrumbs, "proj", card_details)


@bp.route('/retrospective/task/<task_name>')
Expand Down
2 changes: 1 addition & 1 deletion estimage/webapp/templates/base.html
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@
{%- endif %}
{{ render_messages() }}
{% block content %}{% endblock %}
{% block footer %}{{ dark_mode() | safe }} {{ footer.get_footer_html() | safe }}{% endblock %}
{{ bootstrap.load_js() }}
{% block footer %}{{ dark_mode() | safe }} {{ footer.get_footer_html() | safe }}{% endblock %}
</body>
</html>
Loading

0 comments on commit f63393d

Please sign in to comment.