diff --git a/atst/domain/environments.py b/atst/domain/environments.py index 90755052..be007740 100644 --- a/atst/domain/environments.py +++ b/atst/domain/environments.py @@ -10,3 +10,9 @@ class Environments(object): db.session.commit() return environment + @classmethod + def create_many(cls, project, names): + for name in names: + environment = Environment(project=project, name=name) + db.session.add(environment) + db.session.commit() diff --git a/atst/domain/projects.py b/atst/domain/projects.py index 16e0fc4c..d3b2848a 100644 --- a/atst/domain/projects.py +++ b/atst/domain/projects.py @@ -1,11 +1,13 @@ from atst.database import db from atst.models.project import Project +from atst.domain.environments import Environments class Projects(object): @classmethod - def create(cls, workspace, name, description): + def create(cls, workspace, name, description, environment_names): project = Project(workspace=workspace, name=name, description=description) + Environments.create_many(project, environment_names) db.session.add(project) db.session.commit() diff --git a/atst/forms/new_project.py b/atst/forms/new_project.py index 1552a1ab..65685e70 100644 --- a/atst/forms/new_project.py +++ b/atst/forms/new_project.py @@ -1,9 +1,26 @@ from flask_wtf import Form -from wtforms.fields import StringField, TextAreaField +from wtforms.fields import StringField, TextAreaField, FieldList +from wtforms.validators import Required +from atst.forms.validators import ListItemRequired class NewProjectForm(Form): - name = StringField(label="Project Name") - description = TextAreaField(label="Description") - environment_name = StringField(label="Environment Name") + EMPTY_ENVIRONMENT_NAMES = ["", None] + + name = StringField(label="Project Name", validators=[Required()]) + description = TextAreaField(label="Description", validators=[Required()]) + environment_names = FieldList( + StringField(label="Environment Name"), + validators=[ListItemRequired(message="Provide at least one environment name.")], + ) + + @property + def data(self): + _data = super(Form, self).data + _data["environment_names"] = [ + n + for n in _data["environment_names"] + if n not in self.EMPTY_ENVIRONMENT_NAMES + ] + return _data diff --git a/atst/forms/validators.py b/atst/forms/validators.py index 241a5401..85173383 100644 --- a/atst/forms/validators.py +++ b/atst/forms/validators.py @@ -51,3 +51,14 @@ def Alphabet(message="Please enter only letters."): raise ValidationError(message) return _alphabet + + +def ListItemRequired(message="Please provide at least one.", empty_values=("", None)): + def _list_item_required(form, field): + non_empty_values = [v for v in field.data if v not in empty_values] + if len(non_empty_values) == 0: + raise ValidationError(message) + + return _list_item_required + + diff --git a/atst/routes/workspaces.py b/atst/routes/workspaces.py index 6b25a04d..aab9af39 100644 --- a/atst/routes/workspaces.py +++ b/atst/routes/workspaces.py @@ -9,7 +9,6 @@ from flask import ( from atst.domain.workspaces import Workspaces from atst.domain.projects import Projects -from atst.domain.environments import Environments from atst.forms.new_project import NewProjectForm bp = Blueprint("workspaces", __name__) @@ -67,10 +66,16 @@ def update_project(workspace_id): if form.validate(): project_data = form.data - project = Projects.create( - workspace, project_data["name"], project_data["description"] + Projects.create( + workspace, + project_data["name"], + project_data["description"], + project_data["environment_names"], ) - Environments.create(project, project_data["environment_name"]) return redirect( url_for("workspaces.workspace_projects", workspace_id=workspace.id) ) + else: + return render_template( + "workspace_project_new.html", workspace=workspace, form=form + ) diff --git a/js/components/forms/new_project.js b/js/components/forms/new_project.js index cbea6161..ba4e13f5 100644 --- a/js/components/forms/new_project.js +++ b/js/components/forms/new_project.js @@ -1,5 +1,7 @@ import textinput from '../text_input' +const createEnvironment = (name) => ({ name }) + export default { name: 'new-project', @@ -16,14 +18,16 @@ export default { data: function () { const { - name, - description, - environments = [''] + environment_names, } = this.initialData + const environments = ( + environment_names.length > 0 + ? environment_names + : [""] + ).map(createEnvironment) + return { - name, - description, environments, } }, @@ -34,7 +38,7 @@ export default { methods: { addEnvironment: function (event) { - this.environments.push('') + this.environments.push(createEnvironment("")) }, removeEnvironment: function (index) { diff --git a/styles/elements/_block_lists.scss b/styles/elements/_block_lists.scss index ade36741..f0549853 100644 --- a/styles/elements/_block_lists.scss +++ b/styles/elements/_block_lists.scss @@ -17,7 +17,8 @@ justify-content: space-between; .icon-tooltip { - padding: 0.25rem 0.5rem; + margin: -$gap; + } } diff --git a/styles/sections/_project_edit.scss b/styles/sections/_project_edit.scss index 2222fd26..ef1bc39a 100644 --- a/styles/sections/_project_edit.scss +++ b/styles/sections/_project_edit.scss @@ -13,7 +13,7 @@ @include icon-link-vertical; @include icon-link-color($color-red, $color-red-lightest); - margin-bottom: -$gap; + margin-bottom: 0; margin-right: -$gap; } } diff --git a/templates/workspace_project_new.html b/templates/workspace_project_new.html index 85cdf673..874f93d3 100644 --- a/templates/workspace_project_new.html +++ b/templates/workspace_project_new.html @@ -1,6 +1,7 @@ {% from "components/icon.html" import Icon %} {% from "components/text_input.html" import TextInput %} {% from "components/tooltip.html" import Tooltip %} +{% from "components/alert.html" import Alert %} {% extends "base_workspace.html" %} @@ -24,6 +25,10 @@ + {% if form.environment_names.errors %} + {{ Alert("Missing Environments", message="Provide at least one environment name.", level="error") }} + {% endif %} +