multi-step form modal with basic implementation for adding new member
This commit is contained in:
parent
6b59ab800b
commit
1bc434be8c
@ -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()],
|
||||||
|
@ -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,
|
||||||
|
43
js/components/forms/multi_step_modal_form.js
Normal file
43
js/components/forms/multi_step_modal_form.js
Normal 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: {},
|
||||||
|
}
|
@ -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,
|
||||||
|
45
templates/components/multi_step_modal_form.html
Normal file
45
templates/components/multi_step_modal_form.html
Normal 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 %}
|
@ -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) }}
|
||||||
|
@ -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
|
||||||
|
Loading…
x
Reference in New Issue
Block a user