multi-step form modal with basic implementation for adding new member

This commit is contained in:
dandds 2019-03-22 13:36:21 -04:00
parent 6b59ab800b
commit 1bc434be8c
7 changed files with 159 additions and 5 deletions

View File

@ -1,10 +1,10 @@
from wtforms.fields import StringField, FormField, FieldList from wtforms.fields import StringField, FormField, FieldList
from wtforms.fields.html5 import EmailField from wtforms.fields.html5 import EmailField, TelField
from wtforms.validators import Required, Email, Length from wtforms.validators import Required, Email, Length, Optional
from atst.domain.permission_sets import PermissionSets from atst.domain.permission_sets import PermissionSets
from .forms import BaseForm from .forms import BaseForm
from atst.forms.validators import IsNumber from atst.forms.validators import IsNumber, PhoneNumber
from atst.forms.fields import SelectField from atst.forms.fields import SelectField
from atst.utils.localization import translate from atst.utils.localization import translate
@ -71,6 +71,10 @@ class NewForm(PermissionsForm):
email = EmailField( email = EmailField(
translate("forms.new_member.email_label"), validators=[Required(), Email()] translate("forms.new_member.email_label"), validators=[Required(), Email()]
) )
phone_number = TelField(
translate("forms.new_member.phone_number_label"),
validators=[Optional(), PhoneNumber()],
)
dod_id = StringField( dod_id = StringField(
translate("forms.new_member.dod_id_label"), translate("forms.new_member.dod_id_label"),
validators=[Required(), Length(min=10), IsNumber()], validators=[Required(), Length(min=10), IsNumber()],

View File

@ -8,7 +8,7 @@ from atst.domain.portfolios import Portfolios
from atst.domain.audit_log import AuditLog from atst.domain.audit_log import AuditLog
from atst.domain.common import Paginator from atst.domain.common import Paginator
from atst.forms.portfolio import PortfolioForm from atst.forms.portfolio import PortfolioForm
from atst.forms.portfolio_member import MembersPermissionsForm import atst.forms.portfolio_member as member_forms
from atst.models.permissions import Permissions from atst.models.permissions import Permissions
from atst.domain.permission_sets import PermissionSets from atst.domain.permission_sets import PermissionSets
from atst.domain.authz.decorator import user_can_access_decorator as user_can from atst.domain.authz.decorator import user_can_access_decorator as user_can
@ -63,7 +63,7 @@ def render_admin_page(portfolio, form=None):
members_data = [serialize_member_form_data(member) for member in portfolio.members] members_data = [serialize_member_form_data(member) for member in portfolio.members]
portfolio_form = PortfolioForm(data={"name": portfolio.name}) portfolio_form = PortfolioForm(data={"name": portfolio.name})
member_perms_form = MembersPermissionsForm( member_perms_form = member_forms.MembersPermissionsForm(
data={"members_permissions": members_data} data={"members_permissions": members_data}
) )
return render_template( return render_template(
@ -71,6 +71,7 @@ def render_admin_page(portfolio, form=None):
form=form, form=form,
portfolio_form=portfolio_form, portfolio_form=portfolio_form,
member_perms_form=member_perms_form, member_perms_form=member_perms_form,
member_form=member_forms.NewForm(),
portfolio=portfolio, portfolio=portfolio,
audit_events=audit_events, audit_events=audit_events,
user=g.current_user, user=g.current_user,

View File

@ -0,0 +1,43 @@
import FormMixin from '../../mixins/form'
import textinput from '../text_input'
import optionsinput from '../options_input'
import Selector from '../selector'
import Modal from '../../mixins/modal'
import toggler from '../toggler'
export default {
name: 'multi-step-modal-form',
mixins: [FormMixin, Modal],
components: {
toggler,
Modal,
Selector,
textinput,
optionsinput,
},
props: {},
data: function() {
return {
step: 0,
}
},
mounted: function() {
return {}
},
methods: {
next: function() {
this.step += 1
},
goToStep: function(step) {
this.step = step
},
},
computed: {},
}

View File

@ -18,6 +18,7 @@ import toggler from './components/toggler'
import NewApplication from './components/forms/new_application' import NewApplication from './components/forms/new_application'
import EditEnvironmentRole from './components/forms/edit_environment_role' import EditEnvironmentRole from './components/forms/edit_environment_role'
import EditApplicationRoles from './components/forms/edit_application_roles' import EditApplicationRoles from './components/forms/edit_application_roles'
import MultiStepModalForm from './components/forms/multi_step_modal_form'
import funding from './components/forms/funding' import funding from './components/forms/funding'
import uploadinput from './components/upload_input' import uploadinput from './components/upload_input'
import Modal from './mixins/modal' import Modal from './mixins/modal'
@ -59,6 +60,7 @@ const app = new Vue({
LocalDatetime, LocalDatetime,
EditEnvironmentRole, EditEnvironmentRole,
EditApplicationRoles, EditApplicationRoles,
MultiStepModalForm,
ConfirmationPopover, ConfirmationPopover,
funding, funding,
uploadinput, uploadinput,

View File

@ -0,0 +1,45 @@
{% from "components/modal.html" import Modal %}
{% set numbers = ['one', 'two', 'three', 'four', 'five'] %}
{% macro FormSteps(step_count, current_step) -%}
{% set count = numbers[step_count - 1] %}
<div class="progress-menu progress-menu--{{ count }}">
<ul>
{% for step in range(step_count) %}
<li class="progress-menu__item
{% if loop.index < current_step %}
progress-menu__item--complete
{% elif loop.index == current_step %}
progress-menu__item--active
{% else %}
progress-menu__item--incomplete
{% endif %}">
<a v-on:click="goToStep({{ step }})">
Step {{ loop.index }}
</a>
</li>
{% endfor %}
</ul>
</div>
{% endmacro %}
{% macro MultiStepModalForm(name, form, form_action, steps, button_text="", dismissable=False) -%}
{% set step_count = steps|length %}
<multi-step-modal-form inline-template>
<div>
<button v-on:click="openModal('{{ name }}')" type="button" class="icon-link">{{ button_text }}</button>
<form action="{{ form_action }}" method="POST">
{{ form.csrf_token }}
{% call Modal(name=name, dismissable=dismissable) %}
{% for step in steps %}
<div v-show="step === {{ loop.index0 }}">
{{ FormSteps(step_count, loop.index) }}
{{ step }}
</div>
{% endfor %}
{% endcall %}
</form>
</div>
</multi-step-modal-form>
{% endmacro %}

View File

@ -3,6 +3,8 @@
{% from "components/pagination.html" import Pagination %} {% from "components/pagination.html" import Pagination %}
{% from "components/icon.html" import Icon %} {% from "components/icon.html" import Icon %}
{% from "components/text_input.html" import TextInput %} {% from "components/text_input.html" import TextInput %}
{% from "components/multi_step_modal_form.html" import MultiStepModalForm %}
{% from "components/options_input.html" import OptionsInput %}
{% set secondary_breadcrumb = "navigation.portfolio_navigation.portfolio_admin" | translate %} {% set secondary_breadcrumb = "navigation.portfolio_navigation.portfolio_admin" | translate %}
@ -50,6 +52,61 @@
{% include "fragments/admin/portfolio_members.html" %} {% include "fragments/admin/portfolio_members.html" %}
{% endif %} {% endif %}
{% set step_one %}
<h1>Invite New Portfolio Member</h1>
<div class='form-row'>
<div class='form-col form-col--half'>
{{ TextInput(member_form.first_name, validation='requiredField') }}
</div>
<div class='form-col form-col--half'>
{{ TextInput(member_form.last_name, validation='requiredField') }}
</div>
</div>
<div class='form-row'>
<div class='form-col form-col--half'>
{{ TextInput(member_form.email, validation='email') }}
</div>
<div class='form-col form-col--half'>
{{ TextInput(member_form.phone_number, validation='usPhone') }}
</div>
</div>
<div class='form-row'>
<div class='form-col form-col--half'>
{{ TextInput(member_form.dod_id, validation='dodId') }}
</div>
<div class='form-col form-col--half'>
</div>
</div>
<div class='action-group'>
<a v-on:click="next()" class='action-group__action usa-button'>Next Step</a>
<a class='action-group__action icon-link icon-link--danger' v-on:click="closeModal('{{ new_port_mem }}')">Cancel</a>
</div>
{% endset %}
{% set step_two %}
<h1>Assign Member Permissions</h1>
<a class='icon-link'>
<span class='icon'>{{ Icon('info') }}</span>
{{ "portfolios.admin.permissions_info" | translate }}
</a>
{{ OptionsInput(member_form.perms_app_mgmt) }}
{{ OptionsInput(member_form.perms_funding) }}
{{ OptionsInput(member_form.perms_reporting) }}
{{ OptionsInput(member_form.perms_portfolio_mgmt) }}
<div class='action-group'>
<input type="submit" v-on:click="closeModal('{{ new_port_mem }}')" class='action-group__action usa-button' value='Invite Member'>
<a class='action-group__action icon-link icon-link--danger' v-on:click="closeModal('{{ new_port_mem }}')">Cancel</a>
</div>
{% endset %}
{{ MultiStepModalForm(
'add-port-mem',
member_form,
url_for("portfolios.create_member", portfolio_id=portfolio.id),
[step_one, step_two],
button_text="add new member")
}}
{% include "fragments/audit_events_log.html" %}
{% if user_can(permissions.VIEW_PORTFOLIO_ACTIVITY_LOG) %} {% if user_can(permissions.VIEW_PORTFOLIO_ACTIVITY_LOG) %}
{% include "fragments/audit_events_log.html" %} {% include "fragments/audit_events_log.html" %}
{{ Pagination(audit_events, 'portfolios.portfolio_admin', portfolio_id=portfolio.id) }} {{ Pagination(audit_events, 'portfolios.portfolio_admin', portfolio_id=portfolio.id) }}

View File

@ -134,6 +134,7 @@ forms:
new_member: new_member:
dod_id_label: DOD ID dod_id_label: DOD ID
email_label: Email Address email_label: Email Address
phone_number_label: Phone Number (Optional)
first_name_label: First Name first_name_label: First Name
last_name_label: Last Name last_name_label: Last Name
portfolio_role_description: 'The portfolio role controls whether a member is permitted to organize a portfolio into applications and environments, add members to this portfolio, and view billing information.' portfolio_role_description: 'The portfolio role controls whether a member is permitted to organize a portfolio into applications and environments, add members to this portfolio, and view billing information.'
@ -568,6 +569,7 @@ portfolios:
portfolio_members_subheading: These members have different levels of access to the portfolio. portfolio_members_subheading: These members have different levels of access to the portfolio.
settings_info: Learn more about these settings settings_info: Learn more about these settings
add_member: Add a New Member add_member: Add a New Member
permissions_info: Learn more about these permissions
activity_log_title: Activity Log activity_log_title: Activity Log
members: members:
archive_button: Archive User archive_button: Archive User