Merge pull request #696 from dod-ccpo/form-page-complete-indicator
Fix TO Form progress bar
This commit is contained in:
commit
4c282354bd
@ -18,11 +18,16 @@ class BaseForm(FlaskForm):
|
|||||||
def data(self):
|
def data(self):
|
||||||
# remove 'csrf_token' key/value pair
|
# remove 'csrf_token' key/value pair
|
||||||
# remove empty strings and None from list fields
|
# remove empty strings and None from list fields
|
||||||
|
# prevent values that are not an option in a RadioField from being saved to the DB
|
||||||
_data = super().data
|
_data = super().data
|
||||||
_data.pop("csrf_token", None)
|
_data.pop("csrf_token", None)
|
||||||
for field in _data:
|
for field in _data:
|
||||||
if _data[field].__class__.__name__ == "list":
|
if _data[field].__class__.__name__ == "list":
|
||||||
_data[field] = [el for el in _data[field] if el not in EMPTY_LIST_FIELD]
|
_data[field] = [el for el in _data[field] if el not in EMPTY_LIST_FIELD]
|
||||||
|
if self[field].__class__.__name__ == "RadioField":
|
||||||
|
choices = [el[0] for el in self[field].choices]
|
||||||
|
if _data[field] not in choices:
|
||||||
|
_data[field] = None
|
||||||
return _data
|
return _data
|
||||||
|
|
||||||
def validate(self, *args, **kwargs):
|
def validate(self, *args, **kwargs):
|
||||||
|
@ -27,6 +27,10 @@ from .data import (
|
|||||||
from atst.utils.localization import translate
|
from atst.utils.localization import translate
|
||||||
|
|
||||||
|
|
||||||
|
def remove_empty_string(value):
|
||||||
|
return value or None
|
||||||
|
|
||||||
|
|
||||||
class AppInfoWithExistingPortfolioForm(BaseForm):
|
class AppInfoWithExistingPortfolioForm(BaseForm):
|
||||||
scope = TextAreaField(
|
scope = TextAreaField(
|
||||||
translate("forms.task_order.scope_label"),
|
translate("forms.task_order.scope_label"),
|
||||||
@ -50,20 +54,30 @@ class AppInfoWithExistingPortfolioForm(BaseForm):
|
|||||||
translate("forms.task_order.complexity.label"),
|
translate("forms.task_order.complexity.label"),
|
||||||
description=translate("forms.task_order.complexity.description"),
|
description=translate("forms.task_order.complexity.description"),
|
||||||
choices=APPLICATION_COMPLEXITY,
|
choices=APPLICATION_COMPLEXITY,
|
||||||
default="",
|
default=None,
|
||||||
|
filters=[remove_empty_string],
|
||||||
widget=ListWidget(prefix_label=False),
|
widget=ListWidget(prefix_label=False),
|
||||||
option_widget=CheckboxInput(),
|
option_widget=CheckboxInput(),
|
||||||
)
|
)
|
||||||
complexity_other = StringField(translate("forms.task_order.complexity_other_label"))
|
complexity_other = StringField(
|
||||||
|
translate("forms.task_order.complexity_other_label"),
|
||||||
|
default=None,
|
||||||
|
filters=[remove_empty_string],
|
||||||
|
)
|
||||||
dev_team = SelectMultipleField(
|
dev_team = SelectMultipleField(
|
||||||
translate("forms.task_order.dev_team.label"),
|
translate("forms.task_order.dev_team.label"),
|
||||||
description=translate("forms.task_order.dev_team.description"),
|
description=translate("forms.task_order.dev_team.description"),
|
||||||
choices=DEV_TEAM,
|
choices=DEV_TEAM,
|
||||||
default="",
|
default=None,
|
||||||
|
filters=[remove_empty_string],
|
||||||
widget=ListWidget(prefix_label=False),
|
widget=ListWidget(prefix_label=False),
|
||||||
option_widget=CheckboxInput(),
|
option_widget=CheckboxInput(),
|
||||||
)
|
)
|
||||||
dev_team_other = StringField(translate("forms.task_order.dev_team_other_label"))
|
dev_team_other = StringField(
|
||||||
|
translate("forms.task_order.dev_team_other_label"),
|
||||||
|
default=None,
|
||||||
|
filters=[remove_empty_string],
|
||||||
|
)
|
||||||
team_experience = RadioField(
|
team_experience = RadioField(
|
||||||
translate("forms.task_order.team_experience.label"),
|
translate("forms.task_order.team_experience.label"),
|
||||||
description=translate("forms.task_order.team_experience.description"),
|
description=translate("forms.task_order.team_experience.description"),
|
||||||
@ -77,6 +91,7 @@ class AppInfoForm(AppInfoWithExistingPortfolioForm):
|
|||||||
portfolio_name = StringField(
|
portfolio_name = StringField(
|
||||||
translate("forms.task_order.portfolio_name_label"),
|
translate("forms.task_order.portfolio_name_label"),
|
||||||
description=translate("forms.task_order.portfolio_name_description"),
|
description=translate("forms.task_order.portfolio_name_description"),
|
||||||
|
filters=[remove_empty_string],
|
||||||
validators=[
|
validators=[
|
||||||
Required(),
|
Required(),
|
||||||
Length(
|
Length(
|
||||||
@ -87,7 +102,10 @@ class AppInfoForm(AppInfoWithExistingPortfolioForm):
|
|||||||
],
|
],
|
||||||
)
|
)
|
||||||
defense_component = SelectField(
|
defense_component = SelectField(
|
||||||
translate("forms.task_order.defense_component_label"), choices=SERVICE_BRANCHES
|
translate("forms.task_order.defense_component_label"),
|
||||||
|
choices=SERVICE_BRANCHES,
|
||||||
|
default="",
|
||||||
|
filters=[remove_empty_string],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@ -129,29 +147,36 @@ class FundingForm(BaseForm):
|
|||||||
class UnclassifiedFundingForm(FundingForm):
|
class UnclassifiedFundingForm(FundingForm):
|
||||||
clin_02 = StringField(
|
clin_02 = StringField(
|
||||||
translate("forms.task_order.unclassified_clin_02_label"),
|
translate("forms.task_order.unclassified_clin_02_label"),
|
||||||
filters=[lambda x: x or None],
|
filters=[remove_empty_string],
|
||||||
)
|
)
|
||||||
clin_04 = StringField(
|
clin_04 = StringField(
|
||||||
translate("forms.task_order.unclassified_clin_04_label"),
|
translate("forms.task_order.unclassified_clin_04_label"),
|
||||||
filters=[lambda x: x or None],
|
filters=[remove_empty_string],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class OversightForm(BaseForm):
|
class OversightForm(BaseForm):
|
||||||
ko_first_name = StringField(
|
ko_first_name = StringField(
|
||||||
translate("forms.task_order.oversight_first_name_label")
|
translate("forms.task_order.oversight_first_name_label"),
|
||||||
|
filters=[remove_empty_string],
|
||||||
|
)
|
||||||
|
ko_last_name = StringField(
|
||||||
|
translate("forms.task_order.oversight_last_name_label"),
|
||||||
|
filters=[remove_empty_string],
|
||||||
)
|
)
|
||||||
ko_last_name = StringField(translate("forms.task_order.oversight_last_name_label"))
|
|
||||||
ko_email = StringField(
|
ko_email = StringField(
|
||||||
translate("forms.task_order.oversight_email_label"),
|
translate("forms.task_order.oversight_email_label"),
|
||||||
validators=[Optional(), Email()],
|
validators=[Optional(), Email()],
|
||||||
|
filters=[remove_empty_string],
|
||||||
)
|
)
|
||||||
ko_phone_number = TelField(
|
ko_phone_number = TelField(
|
||||||
translate("forms.task_order.oversight_phone_label"),
|
translate("forms.task_order.oversight_phone_label"),
|
||||||
validators=[Optional(), PhoneNumber()],
|
validators=[Optional(), PhoneNumber()],
|
||||||
|
filters=[remove_empty_string],
|
||||||
)
|
)
|
||||||
ko_dod_id = StringField(
|
ko_dod_id = StringField(
|
||||||
translate("forms.task_order.oversight_dod_id_label"),
|
translate("forms.task_order.oversight_dod_id_label"),
|
||||||
|
filters=[remove_empty_string],
|
||||||
validators=[
|
validators=[
|
||||||
RequiredIf(lambda form: form._fields.get("ko_invite").data),
|
RequiredIf(lambda form: form._fields.get("ko_invite").data),
|
||||||
Length(min=10),
|
Length(min=10),
|
||||||
@ -161,15 +186,21 @@ class OversightForm(BaseForm):
|
|||||||
|
|
||||||
am_cor = BooleanField(translate("forms.task_order.oversight_am_cor_label"))
|
am_cor = BooleanField(translate("forms.task_order.oversight_am_cor_label"))
|
||||||
cor_first_name = StringField(
|
cor_first_name = StringField(
|
||||||
translate("forms.task_order.oversight_first_name_label")
|
translate("forms.task_order.oversight_first_name_label"),
|
||||||
|
filters=[remove_empty_string],
|
||||||
|
)
|
||||||
|
cor_last_name = StringField(
|
||||||
|
translate("forms.task_order.oversight_last_name_label"),
|
||||||
|
filters=[remove_empty_string],
|
||||||
)
|
)
|
||||||
cor_last_name = StringField(translate("forms.task_order.oversight_last_name_label"))
|
|
||||||
cor_email = StringField(
|
cor_email = StringField(
|
||||||
translate("forms.task_order.oversight_email_label"),
|
translate("forms.task_order.oversight_email_label"),
|
||||||
|
filters=[remove_empty_string],
|
||||||
validators=[Optional(), Email()],
|
validators=[Optional(), Email()],
|
||||||
)
|
)
|
||||||
cor_phone_number = TelField(
|
cor_phone_number = TelField(
|
||||||
translate("forms.task_order.oversight_phone_label"),
|
translate("forms.task_order.oversight_phone_label"),
|
||||||
|
filters=[remove_empty_string],
|
||||||
validators=[
|
validators=[
|
||||||
RequiredIf(lambda form: not form._fields.get("am_cor").data),
|
RequiredIf(lambda form: not form._fields.get("am_cor").data),
|
||||||
Optional(),
|
Optional(),
|
||||||
@ -178,6 +209,7 @@ class OversightForm(BaseForm):
|
|||||||
)
|
)
|
||||||
cor_dod_id = StringField(
|
cor_dod_id = StringField(
|
||||||
translate("forms.task_order.oversight_dod_id_label"),
|
translate("forms.task_order.oversight_dod_id_label"),
|
||||||
|
filters=[remove_empty_string],
|
||||||
validators=[
|
validators=[
|
||||||
RequiredIf(
|
RequiredIf(
|
||||||
lambda form: not form._fields.get("am_cor").data
|
lambda form: not form._fields.get("am_cor").data
|
||||||
@ -189,19 +221,26 @@ class OversightForm(BaseForm):
|
|||||||
)
|
)
|
||||||
|
|
||||||
so_first_name = StringField(
|
so_first_name = StringField(
|
||||||
translate("forms.task_order.oversight_first_name_label")
|
translate("forms.task_order.oversight_first_name_label"),
|
||||||
|
filters=[remove_empty_string],
|
||||||
|
)
|
||||||
|
so_last_name = StringField(
|
||||||
|
translate("forms.task_order.oversight_last_name_label"),
|
||||||
|
filters=[remove_empty_string],
|
||||||
)
|
)
|
||||||
so_last_name = StringField(translate("forms.task_order.oversight_last_name_label"))
|
|
||||||
so_email = StringField(
|
so_email = StringField(
|
||||||
translate("forms.task_order.oversight_email_label"),
|
translate("forms.task_order.oversight_email_label"),
|
||||||
|
filters=[remove_empty_string],
|
||||||
validators=[Optional(), Email()],
|
validators=[Optional(), Email()],
|
||||||
)
|
)
|
||||||
so_phone_number = TelField(
|
so_phone_number = TelField(
|
||||||
translate("forms.task_order.oversight_phone_label"),
|
translate("forms.task_order.oversight_phone_label"),
|
||||||
|
filters=[remove_empty_string],
|
||||||
validators=[Optional(), PhoneNumber()],
|
validators=[Optional(), PhoneNumber()],
|
||||||
)
|
)
|
||||||
so_dod_id = StringField(
|
so_dod_id = StringField(
|
||||||
translate("forms.task_order.oversight_dod_id_label"),
|
translate("forms.task_order.oversight_dod_id_label"),
|
||||||
|
filters=[remove_empty_string],
|
||||||
validators=[
|
validators=[
|
||||||
RequiredIf(lambda form: form._fields.get("so_invite").data),
|
RequiredIf(lambda form: form._fields.get("so_invite").data),
|
||||||
Length(min=10),
|
Length(min=10),
|
||||||
|
@ -190,9 +190,17 @@ class UpdateTaskOrderWorkflow(ShowTaskOrderWorkflow):
|
|||||||
to_data.pop("defense_component")
|
to_data.pop("defense_component")
|
||||||
|
|
||||||
# don't save other text in DB unless "other" is checked
|
# don't save other text in DB unless "other" is checked
|
||||||
if "complexity" in to_data and "other" not in to_data["complexity"]:
|
if (
|
||||||
|
"complexity" in to_data
|
||||||
|
and bool(to_data["complexity"])
|
||||||
|
and "other" not in to_data["complexity"]
|
||||||
|
):
|
||||||
to_data["complexity_other"] = None
|
to_data["complexity_other"] = None
|
||||||
if "dev_team" in to_data and "other" not in to_data["dev_team"]:
|
if (
|
||||||
|
"dev_team" in to_data
|
||||||
|
and bool(to_data["dev_team"])
|
||||||
|
and "other" not in to_data["dev_team"]
|
||||||
|
):
|
||||||
to_data["dev_team_other"] = None
|
to_data["dev_team_other"] = None
|
||||||
|
|
||||||
if self.form_data.get("am_cor"):
|
if self.form_data.get("am_cor"):
|
||||||
|
36
tests/forms/test_base_form.py
Normal file
36
tests/forms/test_base_form.py
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
import pytest
|
||||||
|
from wtforms.fields import RadioField
|
||||||
|
from werkzeug.datastructures import ImmutableMultiDict
|
||||||
|
|
||||||
|
from atst.forms.forms import BaseForm
|
||||||
|
|
||||||
|
|
||||||
|
class FormWithChoices(BaseForm):
|
||||||
|
force_side = RadioField(
|
||||||
|
"Choose your side",
|
||||||
|
choices=[
|
||||||
|
("light", "Light Side"),
|
||||||
|
("dark", "Dark Side"),
|
||||||
|
("neutral", "Chaotic Neutral"),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class TestBaseForm:
|
||||||
|
class Foo:
|
||||||
|
person = {"force_side": None}
|
||||||
|
|
||||||
|
obj = Foo()
|
||||||
|
|
||||||
|
def test_radio_field_saves_only_as_choice(self):
|
||||||
|
form_data_1 = ImmutableMultiDict({"force_side": "None"})
|
||||||
|
form_1 = FormWithChoices(form_data_1, obj=self.obj)
|
||||||
|
assert form_1.data["force_side"] is None
|
||||||
|
|
||||||
|
form_data_2 = ImmutableMultiDict({"force_side": "a fake choice"})
|
||||||
|
form_2 = FormWithChoices(form_data_2, obj=self.obj)
|
||||||
|
assert form_2.data["force_side"] is None
|
||||||
|
|
||||||
|
form_data_3 = ImmutableMultiDict({"force_side": "dark"})
|
||||||
|
form_3 = FormWithChoices(form_data_3, obj=self.obj)
|
||||||
|
assert form_3.data["force_side"] is "dark"
|
Loading…
x
Reference in New Issue
Block a user