Merge pull request #815 from dod-ccpo/add-new-env-app-settings

Add New Environment via app settings
This commit is contained in:
montana-mil 2019-05-15 11:30:29 -04:00 committed by GitHub
commit 1c4725840c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 193 additions and 48 deletions

View File

@ -85,20 +85,33 @@ def check_users_are_in_application(user_ids, application):
return True
@applications_bp.route("/applications/<application_id>/settings")
@user_can(Permissions.VIEW_APPLICATION, message="view application edit form")
def settings(application_id):
application = Applications.get(application_id)
form = ApplicationForm(name=application.name, description=application.description)
def render_settings_page(application, **kwargs):
environments_obj = get_environments_obj_for_app(application=application)
members_form = AppEnvRolesForm(data=data_for_app_env_roles_form(application))
new_env_form = EditEnvironmentForm()
if "application_form" not in kwargs:
kwargs["application_form"] = ApplicationForm(
name=application.name, description=application.description
)
return render_template(
"portfolios/applications/settings.html",
application=application,
form=form,
environments_obj=environments_obj,
members_form=members_form,
new_env_form=new_env_form,
**kwargs,
)
@applications_bp.route("/applications/<application_id>/settings")
@user_can(Permissions.VIEW_APPLICATION, message="view application edit form")
def settings(application_id):
application = Applications.get(application_id)
return render_settings_page(
application=application,
active_toggler=http_request.args.get("active_toggler"),
active_toggler_section=http_request.args.get("active_toggler_section"),
)
@ -129,16 +142,8 @@ def update_environment(environment_id):
)
else:
return (
render_template(
"portfolios/applications/settings.html",
render_settings_page(
application=application,
form=ApplicationForm(
name=application.name, description=application.description
),
environments_obj=get_environments_obj_for_app(application=application),
members_form=AppEnvRolesForm(
data=data_for_app_env_roles_form(application)
),
active_toggler=environment.id,
active_toggler_section="edit",
),
@ -146,6 +151,31 @@ def update_environment(environment_id):
)
@applications_bp.route(
"/applications/<application_id>/environments/new", methods=["POST"]
)
@user_can(Permissions.CREATE_ENVIRONMENT, message="create application environment")
def new_environment(application_id):
application = Applications.get(application_id)
env_form = EditEnvironmentForm(formdata=http_request.form)
if env_form.validate():
Environments.create(application=application, name=env_form.name.data)
flash("environment_added", environment_name=env_form.data["name"])
return redirect(
url_for(
"applications.settings",
application_id=application.id,
fragment="application-environments",
_anchor="application-environments",
)
)
else:
return (render_settings_page(application=application), 400)
@applications_bp.route("/applications/<application_id>/edit", methods=["POST"])
@user_can(Permissions.EDIT_APPLICATION, message="update application")
def update(application_id):
@ -162,12 +192,7 @@ def update(application_id):
)
)
else:
return render_template(
"portfolios/applications/settings.html",
application=application,
form=form,
environments_obj=get_environments_obj_for_app(application=application),
)
return render_settings_page(application=application, application_form=form)
@applications_bp.route("/environments/<environment_id>/roles", methods=["POST"])
@ -214,13 +239,8 @@ def update_env_roles(environment_id):
)
else:
return (
render_template(
"portfolios/applications/settings.html",
render_settings_page(
application=application,
form=ApplicationForm(
name=application.name, description=application.description
),
environments_obj=get_environments_obj_for_app(application=application),
active_toggler=environment.id,
active_toggler_section="edit",
),

View File

@ -5,6 +5,7 @@ from sqlalchemy.orm.exc import NoResultFound
from atst.database import db
from atst.domain.authz import Authorization
from atst.domain.exceptions import NotFoundError
from atst.domain.portfolios.scopes import ScopedPortfolio
from atst.models import (
Application,

View File

@ -17,6 +17,13 @@ MESSAGES = {
"message_template": "Application environment members have been updated",
"category": "success",
},
"environment_added": {
"title_template": translate("flash.success"),
"message_template": """
{{ "flash.environment_added" | translate({ "env_name": environment_name }) }}
""",
"category": "success",
},
"application_environments_updated": {
"title_template": "Application environments updated",
"message_template": "Application environments have been updated",
@ -29,7 +36,7 @@ MESSAGES = {
},
"invitation_resent": {
"title_template": "Invitation resent",
"message_template": "The {{ officer_type }} has been resent instructions to join this portfolio.",
"message_template": "The {{ officer_type }} has been resent instructions to join this portfolio.",
"category": "success",
},
"task_order_draft": {

View File

@ -0,0 +1,24 @@
import FormMixin from '../../mixins/form'
import textinput from '../text_input'
export default {
name: 'new-environment',
mixins: [FormMixin],
components: {
textinput,
},
data: function() {
return {
open: false,
}
},
methods: {
toggle: function() {
this.open = !this.open
},
},
}

View File

@ -38,6 +38,7 @@ import SidenavToggler from './components/sidenav_toggler'
import KoReview from './components/forms/ko_review'
import BaseForm from './components/forms/base_form'
import DeleteConfirmation from './components/delete_confirmation'
import NewEnvironment from './components/forms/new_environment'
Vue.config.productionTip = false
@ -78,6 +79,7 @@ const app = new Vue({
BaseForm,
DeleteConfirmation,
nestedcheckboxinput,
NewEnvironment,
},
mounted: function() {

View File

@ -42,6 +42,19 @@
.usa-input {
margin: 0;
.icon-validation {
left: 135%;
}
}
#name {
max-width: none;
border-color: black;
}
.usa-alert {
margin: 2.5rem 0;
}
select {
@ -50,6 +63,11 @@
}
}
.new-env {
margin-top: 5rem;
padding: 0 5rem;
}
.accordion-table__items {
margin: 0;

View File

@ -17,7 +17,7 @@
</button>
</form>
<div class="action-group">
<a v-on:click="deleteText = ''; $root.closeModal({{ modal_id }})" class="action-group__action icon-link icon-link--default">{{ "common.cancel" | translate }}</a>
<a v-on:click="deleteText = ''; $root.closeModal('{{ modal_id }}')" class="action-group__action icon-link icon-link--default">{{ "common.cancel" | translate }}</a>
</div>
</div>
</div>

View File

@ -0,0 +1,42 @@
{% from "components/alert.html" import Alert %}
{% from 'components/save_button.html' import SaveButton %}
{% from "components/text_input.html" import TextInput %}
<new-environment inline-template>
<div>
<div v-if="open">
<form method='POST' id="add-new-env" action='{{ url_for("applications.new_environment", application_id=application.id) }}' autocomplete="off" enctype="multipart/form-data">
{{ new_env_form.csrf_token }}
<div class="accordion-table__item-content new-env">
{{ Alert(
title=("portfolios.applications.create_new_env" | translate),
message=("portfolios.applications.create_new_env_info" | translate )
) }}
<div class="h4">{{ "portfolios.applications.enter_env_name" | translate }}</div>
{{ TextInput(new_env_form.name, label="", validation="requiredField") }}
</div>
<div class="panel__footer">
<div class="action-group">
<div class='action-group-cancel'>
<a class='action-group-cancel__action icon-link icon-link--default' v-on:click="toggle">
{{ "common.cancel" | translate }}
</a>
{{ SaveButton(text=('common.save' | translate), element="input", form="add-new-env") }}
</div>
</div>
</div>
</form>
</div>
<div v-else class="panel__footer">
<div class="action-group">
<a class='icon-link' v-on:click="toggle">
{{ "portfolios.applications.add_environment" | translate }}
{{ Icon('plus') }}
</a>
</div>
</div>
</div>
</new-environment>

View File

@ -115,10 +115,10 @@
{{
DeleteConfirmation(
modal_id=delete_modal_environment_id,
modal_id=delete_environment_modal_id,
delete_text=('portfolios.applications.environments.delete.button' | translate),
delete_action= url_for('applications.delete_environment', environment_id=env['id']),
form=form
form=edit_form
)
}}
{% endcall %}
@ -126,11 +126,3 @@
</ul>
</div>
</div>
<div class="panel__footer">
<div class="action-group">
<a class='icon-link'>
{{ "portfolios.applications.add_environment" | translate }}
{{ Icon('plus') }}
</a>
</div>
</div>

View File

@ -1,4 +1,5 @@
{% from "components/options_input.html" import OptionsInput %}
{% from "components/toggle_list.html" import ToggleButton, ToggleSection %}
{{ team_form.csrf_token }}

View File

@ -16,13 +16,13 @@
<div class="panel">
<div class="panel__content">
{{ form.csrf_token }}
{{ application_form.csrf_token }}
<p>
{{ "fragments.edit_application_form.explain" | translate }}
</p>
<div class="form-row">
<div class="form-col form-col--two-thirds">
{{ TextInput(form.name) }}
{{ TextInput(application_form.name) }}
</div>
<div class="form-col form-col--third">
{% if user_can(permissions.DELETE_APPLICATION) %}
@ -45,7 +45,7 @@
</div>
<div class="form-row">
<div class="form-col form-col--two-thirds">
{{ TextInput(form.description, paragraph=True) }}
{{ TextInput(application_form.description, paragraph=True) }}
</div>
<div class="form-col form-col--third">
&nbsp;
@ -69,6 +69,10 @@
{% if user_can(permissions.EDIT_APPLICATION) %}
{% include "fragments/applications/edit_environments.html" %}
{% if user_can(permissions.CREATE_ENVIRONMENT) %}
{% include "fragments/applications/add_new_environment.html" %}
{% endif %}
{% elif user_can(permissions.VIEW_ENVIRONMENT) %}
{% include "fragments/applications/read_only_environments.html" %}
{% endif %}
@ -89,10 +93,10 @@
{{
DeleteConfirmation(
modal_id=delete_modal_environment_id,
modal_id="delete_application",
delete_text=('portfolios.applications.delete.button' | translate),
delete_action= url_for('applications.delete', application_id=application.id),
form=form
form=application_form
)
}}
{% endcall %}

View File

@ -1,10 +1,8 @@
{% extends "portfolios/applications/base.html" %}
{% from "components/empty_state.html" import EmptyState %}
{% from "components/icon.html" import Icon %}
{% from 'components/save_button.html' import SaveButton %}
{% from "components/toggle_list.html" import ToggleButton, ToggleSection %}
{% from "components/multi_step_modal_form.html" import MultiStepModalForm %}
{% from 'components/save_button.html' import SaveButton %}
{% import "fragments/applications/new_member_modal_content.html" as member_steps %}
{% from "components/alert.html" import Alert %}
{% from "components/delete_confirmation.html" import DeleteConfirmation %}

View File

@ -54,7 +54,7 @@ def test_updating_application_environments_success(client, user_session):
assert environment.name == "new name a"
def test_updating_application_environments_failure(client, user_session):
def test_update_environment_failure(client, user_session):
portfolio = PortfolioFactory.create()
application = ApplicationFactory.create(portfolio=portfolio)
environment = EnvironmentFactory.create(
@ -391,6 +391,38 @@ def test_delete_application(client, user_session):
assert len(application.environments) == 0
def test_new_environment(client, user_session):
user = UserFactory.create()
portfolio = PortfolioFactory(owner=user)
application = ApplicationFactory.create(portfolio=portfolio)
num_envs = len(application.environments)
user_session(user)
response = client.post(
url_for("applications.new_environment", application_id=application.id),
data={"name": "dabea"},
)
assert response.status_code == 302
assert len(application.environments) == num_envs + 1
def test_new_environment_with_bad_data(client, user_session):
user = UserFactory.create()
portfolio = PortfolioFactory(owner=user)
application = ApplicationFactory.create(portfolio=portfolio)
num_envs = len(application.environments)
user_session(user)
response = client.post(
url_for("applications.new_environment", application_id=application.id),
data={"name": None},
)
assert response.status_code == 400
assert len(application.environments) == num_envs
def test_delete_environment(client, user_session):
user = UserFactory.create()
portfolio = PortfolioFactory(owner=user)

View File

@ -69,6 +69,7 @@ flash:
congrats: Congrats!
delete_member_success: 'You have successfully deleted {member_name} from the portfolio.'
deleted_member: Portfolio member deleted
environment_added: 'The environment "{env_name}" has been added to the application.'
login_required_message: After you log in, you will be redirected to your destination page.
login_required_title: Log in required
new_portfolio: You've created a new JEDI portfolio and jump-started your first task order!
@ -420,6 +421,8 @@ portfolios:
add_another_environment: Add another environment
app_settings_text: App settings
create_button_text: Create
create_new_env: Create a new environment.
create_new_env_info: Creating an environment gives you access to the Cloud Service Provider. This environment will function within the constraints of the task order, and any costs will be billed against the portfolio.
csp_console_text: CSP console
remove_member:
alert:
@ -431,6 +434,7 @@ portfolios:
message: You will lose access to this application and all of its reporting and metrics tools. The activity log will be retained.
button: Delete application
header: Are you sure you want to delete this application?
enter_env_name: "Enter environment name:"
environments:
name: Name
delete: