Merge pull request #1107 from dod-ccpo/multistep-app-provisioning-design-tweaks
Multistep app provisioning design tweaks
This commit is contained in:
commit
0870959477
@ -0,0 +1,31 @@
|
||||
"""Make application description optional
|
||||
|
||||
Revision ID: f50596c5ffbb
|
||||
Revises: e3d93f9caba7
|
||||
Create Date: 2019-10-08 09:41:11.835664
|
||||
|
||||
"""
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = "f50596c5ffbb" # pragma: allowlist secret
|
||||
down_revision = "e3d93f9caba7" # pragma: allowlist secret
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
|
||||
def upgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.alter_column(
|
||||
"applications", "description", existing_type=sa.VARCHAR(), nullable=True
|
||||
)
|
||||
# ### end Alembic commands ###
|
||||
|
||||
|
||||
def downgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.alter_column(
|
||||
"applications", "description", existing_type=sa.VARCHAR(), nullable=False
|
||||
)
|
||||
# ### end Alembic commands ###
|
@ -1,6 +1,6 @@
|
||||
from .forms import BaseForm
|
||||
from wtforms.fields import StringField, TextAreaField, FieldList
|
||||
from wtforms.validators import Required
|
||||
from wtforms.validators import Required, Optional
|
||||
from atst.forms.validators import ListItemRequired, ListItemsUnique
|
||||
from atst.utils.localization import translate
|
||||
|
||||
@ -16,7 +16,9 @@ class NameAndDescriptionForm(BaseForm):
|
||||
label=translate("forms.application.name_label"), validators=[Required()]
|
||||
)
|
||||
description = TextAreaField(
|
||||
label=translate("forms.application.description_label"), validators=[Required()]
|
||||
label=translate("forms.application.description_label"),
|
||||
validators=[Optional()],
|
||||
filters=[lambda x: x or None],
|
||||
)
|
||||
|
||||
|
||||
|
@ -15,7 +15,7 @@ class Application(
|
||||
|
||||
id = Id()
|
||||
name = Column(String, nullable=False)
|
||||
description = Column(String, nullable=False)
|
||||
description = Column(String)
|
||||
|
||||
portfolio_id = Column(ForeignKey("portfolios.id"), nullable=False)
|
||||
portfolio = relationship("Portfolio")
|
||||
|
@ -37,11 +37,9 @@ def render_new_application_form(
|
||||
|
||||
|
||||
@applications_bp.route("/portfolios/<portfolio_id>/applications/new")
|
||||
@applications_bp.route(
|
||||
"/portfolios/<portfolio_id>/applications/<application_id>/step_1"
|
||||
)
|
||||
@applications_bp.route("/applications/<application_id>/new/step_1")
|
||||
@user_can(Permissions.CREATE_APPLICATION, message="view create new application form")
|
||||
def view_new_application_step_1(portfolio_id, application_id=None):
|
||||
def view_new_application_step_1(portfolio_id=None, application_id=None):
|
||||
return render_new_application_form(
|
||||
"applications/new/step_1.html",
|
||||
NameAndDescriptionForm,
|
||||
@ -56,13 +54,12 @@ def view_new_application_step_1(portfolio_id, application_id=None):
|
||||
methods=["POST"],
|
||||
)
|
||||
@applications_bp.route(
|
||||
"/portfolios/<portfolio_id>/applications/<application_id>/step_1",
|
||||
"/applications/<application_id>/new/step_1",
|
||||
endpoint="update_new_application_step_1",
|
||||
methods=["POST"],
|
||||
)
|
||||
@user_can(Permissions.CREATE_APPLICATION, message="view create new application form")
|
||||
def create_or_update_new_application_step_1(portfolio_id, application_id=None):
|
||||
portfolio = Portfolios.get_for_update(portfolio_id)
|
||||
def create_or_update_new_application_step_1(portfolio_id=None, application_id=None):
|
||||
form = get_new_application_form(
|
||||
{**http_request.form}, NameAndDescriptionForm, application_id
|
||||
)
|
||||
@ -72,12 +69,14 @@ def create_or_update_new_application_step_1(portfolio_id, application_id=None):
|
||||
if application_id:
|
||||
application = Applications.get(application_id)
|
||||
application = Applications.update(application, form.data)
|
||||
flash("application_updated", application_name=application.name)
|
||||
else:
|
||||
portfolio = Portfolios.get_for_update(portfolio_id)
|
||||
application = Applications.create(g.current_user, portfolio, **form.data)
|
||||
flash("application_created", application_name=application.name)
|
||||
return redirect(
|
||||
url_for(
|
||||
"applications.update_new_application_step_2",
|
||||
portfolio_id=portfolio_id,
|
||||
application_id=application.id,
|
||||
)
|
||||
)
|
||||
@ -94,11 +93,9 @@ def create_or_update_new_application_step_1(portfolio_id, application_id=None):
|
||||
)
|
||||
|
||||
|
||||
@applications_bp.route(
|
||||
"/portfolios/<portfolio_id>/applications/<application_id>/step_2"
|
||||
)
|
||||
@applications_bp.route("/applications/<application_id>/new/step_2")
|
||||
@user_can(Permissions.CREATE_APPLICATION, message="view create new application form")
|
||||
def view_new_application_step_2(portfolio_id, application_id):
|
||||
def view_new_application_step_2(application_id):
|
||||
application = Applications.get(application_id)
|
||||
render_args = {
|
||||
"form": EnvironmentsForm(
|
||||
@ -114,11 +111,9 @@ def view_new_application_step_2(portfolio_id, application_id):
|
||||
return render_template("applications/new/step_2.html", **render_args)
|
||||
|
||||
|
||||
@applications_bp.route(
|
||||
"/portfolios/<portfolio_id>/applications/<application_id>/step_2", methods=["POST"]
|
||||
)
|
||||
@applications_bp.route("/applications/<application_id>/new/step_2", methods=["POST"])
|
||||
@user_can(Permissions.CREATE_APPLICATION, message="view create new application form")
|
||||
def update_new_application_step_2(portfolio_id, application_id):
|
||||
def update_new_application_step_2(application_id):
|
||||
form = get_new_application_form(
|
||||
{**http_request.form}, EnvironmentsForm, application_id
|
||||
)
|
||||
@ -137,15 +132,14 @@ def update_new_application_step_2(portfolio_id, application_id):
|
||||
render_new_application_form(
|
||||
"applications/new/step_2.html",
|
||||
EnvironmentsForm,
|
||||
portfolio_id,
|
||||
application_id,
|
||||
form,
|
||||
application_id=application_id,
|
||||
form=form,
|
||||
),
|
||||
400,
|
||||
)
|
||||
|
||||
|
||||
@applications_bp.route("/applications/<application_id>/step_3")
|
||||
@applications_bp.route("/applications/<application_id>/new/step_3")
|
||||
@user_can(Permissions.CREATE_APPLICATION, message="view create new application form")
|
||||
def view_new_application_step_3(application_id):
|
||||
application = Applications.get(application_id)
|
||||
@ -161,7 +155,7 @@ def view_new_application_step_3(application_id):
|
||||
)
|
||||
|
||||
|
||||
@applications_bp.route("/applications/<application_id>/step_3", methods=["POST"])
|
||||
@applications_bp.route("/applications/<application_id>/new/step_3", methods=["POST"])
|
||||
@user_can(Permissions.CREATE_APPLICATION, message="view create new application form")
|
||||
def update_new_application_step_3(application_id):
|
||||
|
||||
|
@ -14,6 +14,13 @@ MESSAGES = {
|
||||
""",
|
||||
"category": "success",
|
||||
},
|
||||
"application_updated": {
|
||||
"title_template": translate("flash.success"),
|
||||
"message_template": """
|
||||
{{ "flash.application.updated" | translate({"application_name": application_name}) }}
|
||||
""",
|
||||
"category": "success",
|
||||
},
|
||||
"application_deleted": {
|
||||
"title_template": translate("flash.success"),
|
||||
"message_template": """
|
||||
|
@ -138,85 +138,22 @@
|
||||
color: $color-gray;
|
||||
}
|
||||
|
||||
.responsive-table-wrapper {
|
||||
padding-bottom: $gap * 3;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
table {
|
||||
margin: 0;
|
||||
width: 100%;
|
||||
min-width: 100%;
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
thead {
|
||||
th:first-child {
|
||||
padding-left: 3 * $gap;
|
||||
}
|
||||
|
||||
tr:first-child {
|
||||
padding: 0 2 * $gap 0 5 * $gap;
|
||||
}
|
||||
|
||||
td {
|
||||
font-weight: bold;
|
||||
font-size: 1.4rem;
|
||||
border-top: 0;
|
||||
}
|
||||
}
|
||||
|
||||
th {
|
||||
background-color: $color-gray-lightest;
|
||||
padding: $gap 2 * $gap;
|
||||
border-top: none;
|
||||
border-bottom: none;
|
||||
color: $color-gray;
|
||||
}
|
||||
|
||||
td:first-child {
|
||||
padding: 2 * $gap 2 * $gap 2 * $gap 5 * $gap;
|
||||
}
|
||||
|
||||
tbody {
|
||||
td {
|
||||
border-bottom: 1px solid $color-gray-lightest;
|
||||
font-size: 1.6rem;
|
||||
border-top: 0;
|
||||
padding: 3 * $gap 2 * $gap;
|
||||
|
||||
.usa-button-disabled {
|
||||
color: $color-gray-medium;
|
||||
background-color: $color-gray-lightest;
|
||||
box-shadow: inset 0 0 0 1px $color-gray-medium;
|
||||
}
|
||||
|
||||
button {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
font-size: 1.5rem;
|
||||
width: 11rem;
|
||||
height: 3rem;
|
||||
}
|
||||
}
|
||||
|
||||
.name {
|
||||
font-weight: bold;
|
||||
|
||||
.you {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
}
|
||||
|
||||
.usa-input.usa-input--success {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
select {
|
||||
border: none;
|
||||
}
|
||||
}
|
||||
|
||||
.add-member-link {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.usa-button-primary .usa-button {
|
||||
padding: 2 * $gap;
|
||||
float: right;
|
||||
}
|
||||
a.create-member {
|
||||
display: inherit;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
max-width: 50%;
|
||||
margin-top: 3rem;
|
||||
}
|
||||
|
||||
input.usa-button.usa-button-primary {
|
||||
|
@ -2,6 +2,11 @@
|
||||
margin-left: -$gap * 4;
|
||||
margin-right: -$gap * 5;
|
||||
z-index: 10;
|
||||
background-color: $color-gray-lightest;
|
||||
border-top: 1px solid $color-gray-lighter;
|
||||
border-bottom: 1px solid $color-gray-lighter;
|
||||
padding: 0 $gap * 5 0 $gap * 5;
|
||||
box-shadow: $box-shadow;
|
||||
|
||||
@include media($medium-screen) {
|
||||
margin-right: -$gap * 5;
|
||||
@ -16,12 +21,6 @@
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
background-color: $color-gray-lightest;
|
||||
border-top: 1px solid $color-gray-lighter;
|
||||
border-bottom: 1px solid $color-gray-lighter;
|
||||
padding: 0 $gap * 5 0 $gap * 5;
|
||||
box-shadow: $box-shadow;
|
||||
|
||||
.usa-button {
|
||||
margin: $gap $gap * 1.5 $gap 0;
|
||||
width: 20rem;
|
||||
@ -32,6 +31,12 @@
|
||||
|
||||
&-text {
|
||||
flex-grow: 1;
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
}
|
||||
&-context {
|
||||
color: $color-gray;
|
||||
margin-left: $gap;
|
||||
}
|
||||
|
||||
&-buttons {
|
||||
|
@ -120,9 +120,10 @@
|
||||
@include panel-actions;
|
||||
}
|
||||
|
||||
hr {
|
||||
hr,
|
||||
&__break {
|
||||
border: 0;
|
||||
border-bottom: 1px dashed $color-gray-light;
|
||||
border-bottom: 1px solid $color-gray-light;
|
||||
margin: ($gap * 4) ($site-margins * -4);
|
||||
}
|
||||
}
|
||||
|
@ -66,7 +66,7 @@ table.atat-table {
|
||||
|
||||
display: table-cell;
|
||||
white-space: nowrap;
|
||||
border-bottom-style: dashed;
|
||||
border-bottom-style: solid;
|
||||
border-top: none;
|
||||
|
||||
&:last-child {
|
||||
@ -88,18 +88,14 @@ table.atat-table {
|
||||
th,
|
||||
td {
|
||||
@include block-list-header;
|
||||
|
||||
display: table-cell;
|
||||
white-space: nowrap;
|
||||
color: black;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@at-root .panel #{&} {
|
||||
tr:last-child td {
|
||||
border-bottom: 0;
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
@ -138,10 +134,6 @@ table.atat-table {
|
||||
}
|
||||
|
||||
@at-root .panel #{&} {
|
||||
tr:last-child td {
|
||||
border-bottom: 0;
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
@ -7,14 +7,14 @@
|
||||
{% set secondary_breadcrumb = 'portfolios.applications.new_application_title' | translate %}
|
||||
|
||||
{% if application_id %}
|
||||
{% set action = url_for('applications.update_new_application_step_1', portfolio_id=portfolio.id, application_id=application_id) %}
|
||||
{% set action = url_for('applications.update_new_application_step_1', application_id=application_id) %}
|
||||
{% else %}
|
||||
{% set action = url_for('applications.create_new_application_step_1', portfolio_id=portfolio.id, application_id=application_id) %}
|
||||
{% endif %}
|
||||
|
||||
{% block portfolio_header %}
|
||||
{% include "portfolios/header.html" %}
|
||||
{{ StickyCTA(text="Name and Describe New Application") }}
|
||||
{{ StickyCTA(text=('portfolios.applications.new.step_1_header' | translate | safe), context="Step 1 of 3") }}
|
||||
{% endblock %}
|
||||
|
||||
{% block application_content %}
|
||||
@ -23,30 +23,32 @@
|
||||
|
||||
<application-name-and-description inline-template v-bind:initial-data='{{ form.data|tojson }}'>
|
||||
<form method="POST" action="{{ action }}" v-on:submit="handleSubmit">
|
||||
<div class="panel">
|
||||
<div class="panel__content">
|
||||
{{ 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, optional=False) }}
|
||||
{{ ('portfolios.applications.new.step_1_form_help_text.description' | translate | safe) }}
|
||||
</div>
|
||||
</div>
|
||||
<hr class="panel__break">
|
||||
<div class="form-row">
|
||||
<div class="form-col form-col--two-thirds">
|
||||
{{ TextInput(form.description, paragraph=True, optional=False) }}
|
||||
{{ TextInput(form.description, paragraph=True, optional=True) }}
|
||||
{{ ('portfolios.applications.new.step_1_form_help_text.description' | translate | safe) }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<span class="action-group">
|
||||
{% block next_button %}
|
||||
{{ SaveButton(text=('portfolios.applications.new.step_1_button_text' | translate)) }}
|
||||
{% endblock %}
|
||||
</span>
|
||||
<span class="action-group">
|
||||
{% block next_button %}
|
||||
{{ SaveButton(text=('portfolios.applications.new.step_1_button_text' | translate)) }}
|
||||
{% endblock %}
|
||||
<a class="usa-button usa-button-secondary" href="{{ url_for('applications.portfolio_applications', portfolio_id=portfolio.id) }}">
|
||||
Cancel
|
||||
</a>
|
||||
</span>
|
||||
</form>
|
||||
</application-name-and-description>
|
||||
|
||||
|
@ -8,68 +8,74 @@
|
||||
{% set secondary_breadcrumb = 'portfolios.applications.new_application_title' | translate %}
|
||||
|
||||
{% block portfolio_header %}
|
||||
{{ StickyCTA(text=application.name) }}
|
||||
{% include "portfolios/header.html" %}
|
||||
{{ StickyCTA(text=('portfolios.applications.new.step_2_header' | translate({"application_name": application.name}) ), context="Step 2 of 3") }}
|
||||
{% endblock %}
|
||||
|
||||
{% block application_content %}
|
||||
|
||||
{% set modalName = "newApplicationConfirmation" %}
|
||||
{% include "fragments/flash.html" %}
|
||||
|
||||
<application-environments inline-template v-bind:initial-data='{{ form.data|tojson }}'>
|
||||
<form method="POST" action="{{ url_for('applications.update_new_application_step_2', portfolio_id=portfolio.id, application_id=application.id) }}" v-on:submit="handleSubmit">
|
||||
<div class="panel">
|
||||
<div class="panel__content">
|
||||
{{ form.csrf_token }}
|
||||
<div> {# this extra div prevents this bug: https://www.pivotaltracker.com/story/show/160768940 #}
|
||||
<div v-cloak v-for="title in errors" :key="title">
|
||||
{{ Alert(message=None, level="error", vue_template=True) }}
|
||||
<div class="panel__content">
|
||||
<p>
|
||||
{{ 'portfolios.applications.new.step_2_description' | translate }}
|
||||
</p>
|
||||
<hr class="panel__break">
|
||||
<application-environments inline-template v-bind:initial-data='{{ form.data|tojson }}'>
|
||||
<form method="POST" action="{{ url_for('applications.update_new_application_step_2', portfolio_id=portfolio.id, application_id=application.id) }}" v-on:submit="handleSubmit">
|
||||
<div class="subheading">{{ 'portfolios.applications.environments_heading' | translate }}</div>
|
||||
<div class="panel">
|
||||
<div class="panel__content">
|
||||
{{ form.csrf_token }}
|
||||
<div> {# this extra div prevents this bug: https://www.pivotaltracker.com/story/show/160768940 #}
|
||||
<div v-cloak v-for="title in errors" :key="title">
|
||||
{{ Alert(message=None, level="error", vue_template=True) }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="application-list-item">
|
||||
<header>
|
||||
<h2 class="block-list__title">{{ 'portfolios.applications.environments_heading' | translate }}</h2>
|
||||
<p>
|
||||
{{ 'portfolios.applications.environments_description' | translate }}
|
||||
</p>
|
||||
</header>
|
||||
|
||||
<ul>
|
||||
<li v-for="(environment, i) in environments" class="application-edit__env-list-item">
|
||||
<div class="usa-input">
|
||||
<label :for="'environment_names-' + i">Environment Name</label>
|
||||
<input type="text" :id="'environment_names-' + i" v-model="environment.name" @input="onInput" placeholder="e.g. Development, Staging, Production"/> <input type="hidden" :name="'environment_names-' + i" v-model="environment.name"/>
|
||||
</div>
|
||||
<div class="application-edit__env-list-item-block">
|
||||
<button v-on:click="removeEnvironment(i)" v-if="environments.length > 1" type="button" class="application-edit__env-list-item__remover">
|
||||
{{ Icon('trash') }}
|
||||
<span>Remove</span>
|
||||
</button>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<div class="block-list__footer">
|
||||
<button
|
||||
v-on:click="addEnvironment"
|
||||
class="icon-link"
|
||||
tabindex="0"
|
||||
type="button">
|
||||
{{ 'portfolios.applications.add_another_environment' | translate }}
|
||||
{{ Icon("plus") }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="application-list-item">
|
||||
<ul>
|
||||
<li v-for="(environment, i) in environments" class="application-edit__env-list-item">
|
||||
<div class="usa-input">
|
||||
<label :for="'environment_names-' + i">Environment Name</label>
|
||||
<input type="text" :id="'environment_names-' + i" v-model="environment.name" @input="onInput" placeholder="e.g. Development, Staging, Production"/> <input type="hidden" :name="'environment_names-' + i" v-model="environment.name"/>
|
||||
</div>
|
||||
<div class="application-edit__env-list-item-block">
|
||||
<button v-on:click="removeEnvironment(i)" v-if="environments.length > 1" type="button" class="application-edit__env-list-item__remover">
|
||||
{{ Icon('trash') }}
|
||||
<span>Remove</span>
|
||||
</button>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<div class="block-list__footer">
|
||||
<button
|
||||
v-on:click="addEnvironment"
|
||||
class="icon-link"
|
||||
tabindex="0"
|
||||
type="button">
|
||||
{{ 'portfolios.applications.add_another_environment' | translate }}
|
||||
{{ Icon("plus") }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<span class="action-group">
|
||||
{% block next_button %}
|
||||
{{ SaveButton(text=('portfolios.applications.new.step_2_button_text' | translate)) }}
|
||||
{% endblock %}
|
||||
</span>
|
||||
</form>
|
||||
</application-environments>
|
||||
</div>
|
||||
|
||||
<span class="action-group">
|
||||
{% block next_button %}
|
||||
{{ SaveButton(text=('portfolios.applications.new.step_2_button_text' | translate)) }}
|
||||
{% endblock %}
|
||||
<a class="usa-button usa-button-secondary" href="{{ url_for('applications.view_new_application_step_1', application_id=application.id) }}">
|
||||
Previous
|
||||
</a>
|
||||
<a href="{{ url_for('applications.portfolio_applications', portfolio_id=portfolio.id) }}">
|
||||
Cancel
|
||||
</a>
|
||||
</span>
|
||||
</form>
|
||||
</application-environments>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
|
@ -6,21 +6,36 @@
|
||||
|
||||
{% block portfolio_header %}
|
||||
{% include "portfolios/header.html" %}
|
||||
{{ StickyCTA(text=application.name) }}
|
||||
{{ StickyCTA(text=('portfolios.applications.new.step_3_header' | translate({"application_name": application.name}) ), context="Step 3 of 3") }}
|
||||
{% endblock %}
|
||||
|
||||
{% block application_content %}
|
||||
{% include "fragments/flash.html" %}
|
||||
<div class="panel__content">
|
||||
<p>
|
||||
{{ ('portfolios.applications.new.step_3_description' | translate) }}
|
||||
</p>
|
||||
<hr class="panel__break">
|
||||
|
||||
{{ MemberManagementTemplate(
|
||||
application,
|
||||
members,
|
||||
new_member_form,
|
||||
"applications.update_new_application_step_3",
|
||||
user_can(permissions.CREATE_APPLICATION_MEMBER)) }}
|
||||
|
||||
<span class="action-group">
|
||||
<a class="usa-button" href="{{ url_for('applications.settings', application_id=application_id) }}">
|
||||
Return to Application Settings
|
||||
</a>
|
||||
</span>
|
||||
application,
|
||||
members,
|
||||
new_member_form,
|
||||
"applications.update_new_application_step_3",
|
||||
user_can(permissions.CREATE_APPLICATION_MEMBER)) }}
|
||||
|
||||
|
||||
<span class="action-group">
|
||||
<a class="usa-button" href="{{ url_for('applications.settings', application_id=application_id) }}">
|
||||
Return to Application Settings
|
||||
</a>
|
||||
<a class="usa-button usa-button-secondary" href="{{ url_for('applications.view_new_application_step_2', application_id=application.id) }}">
|
||||
Previous
|
||||
</a>
|
||||
<a href="{{ url_for('applications.portfolio_applications', portfolio_id=portfolio.id) }}">
|
||||
Cancel
|
||||
</a>
|
||||
</span>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
|
@ -32,7 +32,7 @@
|
||||
<div class="form-row">
|
||||
<div class="form-col form-col--two-thirds">
|
||||
{{ TextInput(application_form.name, optional=False) }}
|
||||
{{ TextInput(application_form.description, paragraph=True, optional=False) }}
|
||||
{{ TextInput(application_form.description, paragraph=True, optional=True) }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -81,14 +81,9 @@
|
||||
"applications.create_member",
|
||||
user_can(permissions.CREATE_APPLICATION_MEMBER)) }}
|
||||
|
||||
<div class='subheading'>
|
||||
<div class="subheading">
|
||||
{{ 'common.resource_names.environments' | translate }}
|
||||
|
||||
{% if user_can(permissions.CREATE_ENVIRONMENT) %}
|
||||
{% include "applications/fragments/add_new_environment.html" %}
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<div class="panel">
|
||||
{% if g.matchesPath("application-environments") %}
|
||||
{% include "fragments/flash.html" %}
|
||||
@ -178,8 +173,13 @@
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
{% if user_can(permissions.CREATE_ENVIRONMENT) %}
|
||||
<div class='subheading'>
|
||||
{% include "applications/fragments/add_new_environment.html" %}
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
|
||||
<hr>
|
||||
|
||||
{% if user_can(permissions.DELETE_APPLICATION) %}
|
||||
|
@ -1,23 +1,26 @@
|
||||
{% from 'components/icon.html' import Icon %}
|
||||
|
||||
{% macro StickyCTA(text, return_link_url=None, return_link_text=None) -%}
|
||||
<div class="sticky-cta" v-sticky='{ "stickyBitStickyOffset": 76 }'>
|
||||
<div class="sticky-cta-container">
|
||||
<div class="sticky-cta-text">
|
||||
{% if return_link_url and return_link_text %}
|
||||
<div class="sticky-cta-return-link">
|
||||
<a href="{{ return_link_url }}">
|
||||
{{ Icon('caret_left', classes="icon--tiny icon--blue") }} {{ return_link_text}}
|
||||
</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
<h3>{{ text }}</h3>
|
||||
</div>
|
||||
{% if caller %}
|
||||
<div class="sticky-cta-buttons">
|
||||
{{ caller() }}
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% macro StickyCTA(text, context=None, return_link_url=None, return_link_text=None) -%}
|
||||
<div class="sticky-cta" v-sticky='{ "stickyBitStickyOffset": 76 }'>
|
||||
{% if return_link_url and return_link_text %}
|
||||
<div class="sticky-cta-return-link">
|
||||
<a href="{{ return_link_url }}">
|
||||
{{ Icon('caret_left', classes="icon--tiny icon--blue") }} {{ return_link_text}}
|
||||
</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
<div class="sticky-cta-container">
|
||||
<div class="sticky-cta-text">
|
||||
<h3>{{ text }}</h3>
|
||||
{% if context %}
|
||||
<span class="sticky-cta-context"> {{ context }} </span>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% if caller %}
|
||||
<div class="sticky-cta-buttons">
|
||||
{{ caller() }}
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{%- endmacro %}
|
||||
|
@ -15,10 +15,16 @@
|
||||
) %}
|
||||
|
||||
|
||||
{% include "fragments/flash.html" %}
|
||||
{% if g.matchesPath("application-members") %}
|
||||
{% include "fragments/flash.html" %}
|
||||
{% endif %}
|
||||
|
||||
<div class="subheading">
|
||||
{{ 'portfolios.applications.settings.team_members' | translate }}
|
||||
</div>
|
||||
<div class="panel">
|
||||
{% if not application.members %}
|
||||
<div class='empty-state'>
|
||||
<div class='empty-state panel__content'>
|
||||
<p class='empty-state__message'>{{ ("portfolios.applications.team_settings.blank_slate.title" | translate) }}</p>
|
||||
|
||||
{{ Icon('avatar') }}
|
||||
@ -45,21 +51,9 @@
|
||||
</div>
|
||||
|
||||
{% else %}
|
||||
<div class='subheading'>
|
||||
{{ 'portfolios.applications.settings.team_members' | translate }}
|
||||
|
||||
{% set new_member_modal_name = "add-app-mem" %}
|
||||
{% if user_can_create_app_member %}
|
||||
<a class="icon-link modal-link icon-link__add" v-on:click="openModal('{{ new_member_modal_name }}')">
|
||||
{{ Icon("plus") }}
|
||||
{{ "portfolios.applications.add_member" | translate }}
|
||||
</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<section class="member-list application-list" id="application-members">
|
||||
<div class='responsive-table-wrapper panel'>
|
||||
{% for member in members %}
|
||||
{% set new_member_modal_name = "add-app-mem" %}
|
||||
|
||||
{% for member in members %}
|
||||
{% set modal_name = "edit_member-{}".format(loop.index) %}
|
||||
{% call Modal(modal_name) %}
|
||||
<div class="modal__form--header">
|
||||
@ -78,11 +72,15 @@
|
||||
</base-form>
|
||||
{% endcall %}
|
||||
{% endfor %}
|
||||
<table>
|
||||
|
||||
|
||||
<section class="member-list application-list" id="application-members">
|
||||
<div class='responsive-table-wrapper'>
|
||||
<table class="atat-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Member</th>
|
||||
<th>Project Permissions</th>
|
||||
<th>Application Permissions</th>
|
||||
<th>Environment Access</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
@ -92,7 +90,7 @@
|
||||
{% set modal_name = "edit_member-{}".format(loop.index) %}
|
||||
<tr>
|
||||
<td>
|
||||
{{ member.user_name }}
|
||||
<strong>{{ member.user_name }}</strong>
|
||||
<a class="icon-link" v-on:click="openModal('{{ modal_name }}')">
|
||||
{{ Icon('edit') }}
|
||||
</a>
|
||||
@ -123,6 +121,11 @@
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
{% if user_can_create_app_member %}
|
||||
<a class="usa-button usa-button-secondary create-member" v-on:click="openModal('{{ new_member_modal_name }}')">
|
||||
{{ "portfolios.applications.add_member" | translate }}
|
||||
</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
{% if user_can_create_app_member %}
|
||||
@ -139,5 +142,6 @@
|
||||
{% endif %}
|
||||
</section>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
{% endmacro %}
|
||||
|
@ -107,6 +107,7 @@ email:
|
||||
flash:
|
||||
application:
|
||||
created: 'You have successfully created the {application_name} application.'
|
||||
updated: 'You have successfully updated the {application_name} application.'
|
||||
deleted: 'You have successfully deleted the {application_name} application. To view the retained activity log, visit the portfolio administration page.'
|
||||
delete_member_success: 'You have successfully deleted {member_name} from the portfolio.'
|
||||
deleted_member: Portfolio member deleted
|
||||
@ -308,8 +309,38 @@ portfolios:
|
||||
add_another_environment: Add another environment
|
||||
app_settings_text: App settings
|
||||
new:
|
||||
step_1_header: Name and Describe New Application
|
||||
step_1_button_text: "Save and Add Environments"
|
||||
step_1_form_help_text:
|
||||
name: |
|
||||
<div style="margin-top: -3rem;">
|
||||
<p>
|
||||
The name of your application should be intuitive and easily recognizable for all of your team members.
|
||||
</p>
|
||||
<p>
|
||||
<strong>Writer's Block? A naming example includes:</strong>
|
||||
<ul>
|
||||
<li>Army Security Infrastructure Application</li>
|
||||
</ul>
|
||||
</p>
|
||||
</div>
|
||||
description: |
|
||||
<div style="margin-top: -3rem;">
|
||||
<p>
|
||||
Add a brief one to two sentence description of your application. You should be able to reference your TO Description of Work.
|
||||
</p>
|
||||
<p>
|
||||
<strong>Writer's Block? A naming example includes:</strong>
|
||||
<ul>
|
||||
<li>Build security applications for FOB Clark</li>
|
||||
</ul>
|
||||
</p>
|
||||
</div>
|
||||
step_2_header: Add Environments to {application_name}
|
||||
step_2_description: "Production, Staging, Testing, and Development environments are included by default. However, you can add, edit, and delete environments based on the needs of your Application."
|
||||
step_2_button_text: "Save and Add Members"
|
||||
step_3_header: Invite Members to {application_name}
|
||||
step_3_description: "To proceed, you will need each member's email address and DOD ID. Within this section, you will also assign application-level permissions and environment-level roles for each member."
|
||||
step_3_button_text: Save Application
|
||||
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.
|
||||
@ -333,8 +364,7 @@ portfolios:
|
||||
delete:
|
||||
button: Delete environment
|
||||
edit_name: Edit name
|
||||
environments_description: Each environment created within an application is logically separated from one another for easier management and security.
|
||||
environments_heading: Application environments
|
||||
environments_heading: Application Environments
|
||||
existing_application_title: '{application_name} Application Settings'
|
||||
member_count: '{count} members'
|
||||
new_application_title: New Application
|
||||
|
Loading…
x
Reference in New Issue
Block a user