diff --git a/atst/forms/application_member.py b/atst/forms/application_member.py index 03c85953..4e54a17b 100644 --- a/atst/forms/application_member.py +++ b/atst/forms/application_member.py @@ -2,9 +2,10 @@ from wtforms.fields import FormField, FieldList, HiddenField, BooleanField from .forms import BaseForm from .member import NewForm as BaseNewMemberForm -from .data import ENV_ROLES +from .data import FORMATTED_ENV_ROLES as ENV_ROLES from atst.forms.fields import SelectField from atst.domain.permission_sets import PermissionSets +from atst.utils.localization import translate class EnvironmentForm(BaseForm): @@ -14,9 +15,15 @@ class EnvironmentForm(BaseForm): class PermissionsForm(BaseForm): - perms_env_mgmt = BooleanField(None, default=False) - perms_team_mgmt = BooleanField(None, default=False) - perms_del_env = BooleanField(None, default=False) + perms_env_mgmt = BooleanField( + translate("portfolios.applications.members.new.manage_envs"), default=False + ) + perms_team_mgmt = BooleanField( + translate("portfolios.applications.members.new.manage_team"), default=False + ) + perms_del_env = BooleanField( + translate("portfolios.applications.members.new.delete_envs"), default=False + ) @property def data(self): diff --git a/atst/forms/data.py b/atst/forms/data.py index 515a70e9..24e2cb7d 100644 --- a/atst/forms/data.py +++ b/atst/forms/data.py @@ -219,3 +219,6 @@ REQUIRED_DISTRIBUTIONS = [ ] ENV_ROLES = [(role.value, role.value) for role in CSPRole] + [(None, "No access")] +FORMATTED_ENV_ROLES = [(role.value, "- {} -".format(role.value)) for role in CSPRole] + [ + (None, "- No Access -") +] diff --git a/atst/routes/applications/team.py b/atst/routes/applications/team.py index 7fb75f0e..5bfbfaf5 100644 --- a/atst/routes/applications/team.py +++ b/atst/routes/applications/team.py @@ -6,6 +6,7 @@ from atst.domain.environments import Environments from atst.domain.applications import Applications from atst.domain.authz.decorator import user_can_access_decorator as user_can from atst.domain.permission_sets import PermissionSets +from atst.domain.exceptions import AlreadyExistsError from atst.forms.application_member import NewForm as NewMemberForm from atst.models.permissions import Permissions from atst.services.invitation import Invitation as InvitationService @@ -45,10 +46,17 @@ def team(application_id): ), } + env_roles = [ + {"environment_id": e.id, "environment_name": e.name} + for e in application.environments + ] + member_form = NewMemberForm(data={"environment_roles": env_roles}) + return render_template( "portfolios/applications/team.html", application=application, environment_users=environment_users, + member_form=member_form, ) diff --git a/js/components/forms/multi_step_modal_form.js b/js/components/forms/multi_step_modal_form.js index 5824e08c..ff50e373 100644 --- a/js/components/forms/multi_step_modal_form.js +++ b/js/components/forms/multi_step_modal_form.js @@ -1,6 +1,7 @@ import FormMixin from '../../mixins/form' import textinput from '../text_input' import optionsinput from '../options_input' +import checkboxinput from '../checkbox_input' import Selector from '../selector' import Modal from '../../mixins/modal' import toggler from '../toggler' @@ -16,6 +17,7 @@ export default { Selector, textinput, optionsinput, + checkboxinput, }, props: { diff --git a/styles/components/_forms.scss b/styles/components/_forms.scss index f78f2dc3..696a71ce 100644 --- a/styles/components/_forms.scss +++ b/styles/components/_forms.scss @@ -46,6 +46,14 @@ flex-basis: 16.66%; } + &.form-col--quarter { + flex-basis: 25%; + } + + &.form-col--three-quarters { + flex-basis: 75%; + } + .usa-input { margin-left: ($gap * 4); margin-right: ($gap * 4); @@ -171,3 +179,11 @@ } } +.input__inline-fields { + margin: 1rem 0 1rem 0; + + &> fieldset.usa-input__choices label { + display: inline; + font-weight: $font-normal; + } + } diff --git a/styles/sections/_application_edit.scss b/styles/sections/_application_edit.scss index c11c2f87..ab642442 100644 --- a/styles/sections/_application_edit.scss +++ b/styles/sections/_application_edit.scss @@ -59,3 +59,29 @@ } } } + +.environment-roles-new { + margin-top: 5*$gap; + margin-bottom: 8*$gap; + + .usa-input { + margin: 2rem 0 2rem 0; + + .usa-input__title-inline { + line-height: $hit-area; + } + + legend { + font-size: $lead-font-size; + padding: 0; + } + } + + .form-row { + margin: 0; + } +} + +.environment-roles-new__head { + font-weight: $font-bold; +} diff --git a/templates/components/checkbox_input.html b/templates/components/checkbox_input.html index 2f016517..998d825d 100644 --- a/templates/components/checkbox_input.html +++ b/templates/components/checkbox_input.html @@ -1,6 +1,6 @@ {% macro CheckboxInput( field, - label=field.label | striptags, + label=field.label, inline=False, classes="") -%} @@ -9,9 +9,7 @@
{{ field() }} - + {{ label | safe }} {% if field.description %} {{ field.description | safe }} diff --git a/templates/fragments/applications/add_new_application_member.html b/templates/fragments/applications/add_new_application_member.html new file mode 100644 index 00000000..1f55efde --- /dev/null +++ b/templates/fragments/applications/add_new_application_member.html @@ -0,0 +1,104 @@ +{% from "components/icon.html" import Icon %} +{% from "components/text_input.html" import TextInput %} +{% from "components/checkbox_input.html" import CheckboxInput %} +{% from "components/multi_step_modal_form.html" import MultiStepModalForm %} + +{% set step_one %} + +
+
+ {{ TextInput(member_form.user_data.first_name, validation='requiredField') }} +
+
+ {{ TextInput(member_form.user_data.last_name, validation='requiredField') }} +
+
+
+
+ {{ TextInput(member_form.user_data.email, validation='email') }} +
+
+ {{ TextInput(member_form.user_data.phone_number, validation='usPhone', optional=True) }} +
+
+
+
+ {{ TextInput(member_form.user_data.dod_id, validation='dodId') }} +
+
+
+
+
+ + Cancel +
+{% endset %} +{% set step_two %} + +{% endset %} +{{ MultiStepModalForm( + 'add-app-mem', + member_form, + url_for("applications.create_member", application_id=application.id), + [step_one, step_two], + button_text=("portfolios.admin.add_new_member" | translate), + button_icon="plus-circle-solid", + ) }} diff --git a/templates/portfolios/applications/team.html b/templates/portfolios/applications/team.html index 2cb6f896..d8e70ffd 100644 --- a/templates/portfolios/applications/team.html +++ b/templates/portfolios/applications/team.html @@ -28,93 +28,95 @@ {% if g.matchesPath("application-members") %} {% include "fragments/flash.html" %} {% endif %} -
-
-
-
-
- {{ "portfolios.applications.team_settings.section.title" | translate({ "application_name": application.name }) }} -
+
+
+
+
+ {{ "portfolios.applications.team_settings.section.title" | translate({ "application_name": application.name }) }}
- - {{ Icon('info') }} - {{ "portfolios.admin.settings_info" | translate }} -
-
- -
-
- - - {{ "portfolios.applications.team_settings.user" | translate }} - - - {{ "portfolios.applications.team_settings.section.table.delete_access" | translate }} - - - {{ "portfolios.applications.team_settings.section.table.environment_management" | translate }} - - - {{ "portfolios.applications.team_settings.section.table.team_management" | translate }} - - - -
-
    - {% for member in application.members %} - {% set user = member.user %} - {% set user_info = environment_users[user.id] %} - {% set user_permissions = user_info["permissions"] %} - - - -
  • -
    - - {{ name }} - {{ user.full_name }} - {{ user_permissions["delete_access"] }} - {{ user_permissions["environment_management"] }} - {{ user_permissions["team_management"] }} - - - {% set open_html %} - {{ "common.show" | translate }} {{ "portfolios.applications.team_settings.environments" | translate }} ({{ user_info['environments'] | length }}) - {% endset %} - - {% set close_html %} - {{ "common.hide" | translate }} {{ "portfolios.applications.team_settings.environments" | translate }} ({{ user_info['environments'] | length }}) - {% endset %} - - {{ - ToggleButton( - open_html=open_html, - close_html=close_html, - section_name="environments" - ) - }} - -
    - {% call ToggleSection(section_name="environments") %} -
      - {% for environment in user_info["environments"] %} -
    • -
      - {{ environment.name }} -
      -
    • - {% endfor %} -
    - {% endcall %} -
  • -
    - {% endfor %} -
+ + {{ Icon('info') }} + {{ "portfolios.admin.settings_info" | translate }} +
+
+ +
+
+ + + {{ "portfolios.applications.team_settings.user" | translate }} + + + {{ "portfolios.applications.team_settings.section.table.delete_access" | translate }} + + + {{ "portfolios.applications.team_settings.section.table.environment_management" | translate }} + + + {{ "portfolios.applications.team_settings.section.table.team_management" | translate }} + + + +
+
    + {% for member in application.members %} + {% set user = member.user %} + {% set user_info = environment_users[user.id] %} + {% set user_permissions = user_info["permissions"] %} + + + +
  • +
    + + {{ name }} + {{ user.full_name }} + {{ user_permissions["delete_access"] }} + {{ user_permissions["environment_management"] }} + {{ user_permissions["team_management"] }} + + + {% set open_html %} + {{ "common.show" | translate }} {{ "portfolios.applications.team_settings.environments" | translate }} ({{ user_info['environments'] | length }}) + {% endset %} + + {% set close_html %} + {{ "common.hide" | translate }} {{ "portfolios.applications.team_settings.environments" | translate }} ({{ user_info['environments'] | length }}) + {% endset %} + + {{ + ToggleButton( + open_html=open_html, + close_html=close_html, + section_name="environments" + ) + }} + +
    + {% call ToggleSection(section_name="environments") %} +
      + {% for environment in user_info["environments"] %} +
    • +
      + {{ environment.name }} +
      +
    • + {% endfor %} +
    + {% endcall %} +
  • +
    + {% endfor %} +
+
diff --git a/translations.yaml b/translations.yaml index 7ec5a4e8..2f124d4b 100644 --- a/translations.yaml +++ b/translations.yaml @@ -35,6 +35,9 @@ common: save_and_continue: Save & continue show: Show sign: Sign + resource_names: + environments: Environments + choose_role: Choose a role components: modal: close: Close @@ -434,6 +437,14 @@ portfolios: user: User team_text: Team update_button_text: Save + members: + new: + assign_roles: Assign Member Environments and Roles + learn_more: Learn more about these roles + manage_perms: 'Manage permissions for {application_name}' + manage_envs: 'Allow member to add and rename environments within the application.' + delete_envs: 'Allow member to delete environments within the application.' + manage_team: 'Allow member to add, update and remove members from the application team.' index: empty: start_button: Start a new JEDI portfolio