diff --git a/atst/forms/new_project.py b/atst/forms/new_project.py index 65685e70..b6007364 100644 --- a/atst/forms/new_project.py +++ b/atst/forms/new_project.py @@ -1,7 +1,7 @@ from flask_wtf import Form from wtforms.fields import StringField, TextAreaField, FieldList from wtforms.validators import Required -from atst.forms.validators import ListItemRequired +from atst.forms.validators import ListItemRequired, ListItemsUnique class NewProjectForm(Form): @@ -12,7 +12,10 @@ class NewProjectForm(Form): description = TextAreaField(label="Description", validators=[Required()]) environment_names = FieldList( StringField(label="Environment Name"), - validators=[ListItemRequired(message="Provide at least one environment name.")], + validators=[ + ListItemRequired(message="Provide at least one environment name."), + ListItemsUnique(message="Environment names must be unique."), + ], ) @property diff --git a/atst/forms/validators.py b/atst/forms/validators.py index 5be056e3..9d007ecf 100644 --- a/atst/forms/validators.py +++ b/atst/forms/validators.py @@ -60,3 +60,11 @@ def ListItemRequired(message="Please provide at least one.", empty_values=("", N raise ValidationError(message) return _list_item_required + + +def ListItemsUnique(message="Items must be unique"): + def _list_items_unique(form, field): + if len(field.data) > len(set(field.data)): + raise ValidationError(message) + + return _list_items_unique diff --git a/atst/routes/requests/financial_verification.py b/atst/routes/requests/financial_verification.py index 8c4e5666..29f5ce39 100644 --- a/atst/routes/requests/financial_verification.py +++ b/atst/routes/requests/financial_verification.py @@ -45,7 +45,7 @@ def update_financial_verification(request_id): new_workspace = Requests.approve_and_create_workspace(updated_request) return redirect( url_for( - "workspaces.workspace_projects", + "workspaces.new_project", workspace_id=new_workspace.id, newWorkspace=True, ) diff --git a/styles/elements/_block_lists.scss b/styles/elements/_block_lists.scss index f0549853..ac6936c0 100644 --- a/styles/elements/_block_lists.scss +++ b/styles/elements/_block_lists.scss @@ -18,7 +18,14 @@ .icon-tooltip { margin: -$gap; + } + &--grow { + display: inline-block; + width: 100%; + p { + margin-bottom: 0; + } } } diff --git a/templates/components/alert.html b/templates/components/alert.html index 80f99196..1fa86489 100644 --- a/templates/components/alert.html +++ b/templates/components/alert.html @@ -31,6 +31,10 @@
{{ message | safe }}
{% endif %} + {% if caller %} +
{{ caller() }}
+ {% endif %} + {% if fragment %}
{% include fragment %} diff --git a/templates/workspace_project_new.html b/templates/workspace_project_new.html index b32178c7..71daf9cc 100644 --- a/templates/workspace_project_new.html +++ b/templates/workspace_project_new.html @@ -9,6 +9,14 @@ {% block workspace_content %} {% set modalName = "newProjectConfirmation" %} +{% if request.args.get("newWorkspace") %} + {{ Alert('Workspace created!', + message="\ +

You are now ready to create projects and environments within the JEDI Cloud.

+ ", + level='success' + ) }} +{% endif %}
@@ -32,30 +40,29 @@

Add a new project

- {{ Tooltip( - "AT-AT allows you to organize your workspace into multiple projects, each of which may have environments.", - title="learn more" - )}}
-
+

+ AT-AT allows you to organize your workspace into multiple projects, each of which may have environments. +

{{ TextInput(form.name) }} {{ TextInput(form.description, paragraph=True) }}
{% if form.environment_names.errors %} - {{ Alert("Missing Environments", message="Provide at least one environment name.", level="error") }} + {% for error in form.environment_names.errors %} + {{ Alert(error, level="error") }} + {% endfor %} {% endif %}
-
+

Project Environments

- {{ Tooltip( - "Each environment created within a project is an enclave of cloud resources that is logically separated from each other for increased security.", - title="learn more" - )}} +

+ Each environment created within a project is an enclave of cloud resources that is logically separated from each other for increased security. +

    diff --git a/templates/workspace_projects.html b/templates/workspace_projects.html index cd2a1308..d2af0e17 100644 --- a/templates/workspace_projects.html +++ b/templates/workspace_projects.html @@ -5,15 +5,6 @@ {% block workspace_content %} -{% if request.args.get("newWorkspace") %} - {{ Alert('Workspace created!', - message="\ -

    You are now ready to create projects and environments within the JEDI Cloud.

    - ", - level='success' - ) }} -{% endif %} - {% for project in workspace.projects %}
    diff --git a/tests/forms/test_validators.py b/tests/forms/test_validators.py index 794310ac..3f3dd978 100644 --- a/tests/forms/test_validators.py +++ b/tests/forms/test_validators.py @@ -1,7 +1,7 @@ from wtforms.validators import ValidationError import pytest -from atst.forms.validators import Alphabet, IsNumber, PhoneNumber +from atst.forms.validators import Alphabet, IsNumber, PhoneNumber, ListItemsUnique class TestIsNumber: @@ -51,3 +51,22 @@ class TestAlphabet: dummy_field.data = invalid with pytest.raises(ValidationError): validator(dummy_form, dummy_field) + + +class TestListItemsUnique: + @pytest.mark.parametrize("valid", [["a", "aa", "aaa"], ["one", "two", "three"]]) + def test_ListItemsUnique_allows_unique_items(self, valid, dummy_form, dummy_field): + validator = ListItemsUnique() + dummy_field.data = valid + validator(dummy_form, dummy_field) + + @pytest.mark.parametrize( + "invalid", [["a", "a", "a"], ["one", "two", "two", "three"]] + ) + def test_ListItemsUnique_rejects_duplicate_names( + self, invalid, dummy_form, dummy_field + ): + validator = ListItemsUnique() + dummy_field.data = invalid + with pytest.raises(ValidationError): + validator(dummy_form, dummy_field) diff --git a/tests/routes/test_financial_verification.py b/tests/routes/test_financial_verification.py index 7748ebe8..b39bc77f 100644 --- a/tests/routes/test_financial_verification.py +++ b/tests/routes/test_financial_verification.py @@ -137,4 +137,4 @@ class TestPENumberInForm: response = self.submit_data(client, data, extended=True) assert response.status_code == 302 - assert "/workspaces" in response.headers.get("Location") + assert "/projects/new" in response.headers.get("Location")