Delete unused Jinja macros and rearrange templates.

Templates and fragments that relate to specific resources (portfolios,
applications, task orders) should reside in directories named for the
relevant resource. This also matches the way the application routes are
distributed among modules named for each resource type.
This commit is contained in:
dandds
2019-09-24 09:55:31 -04:00
parent c8a2e9ee96
commit 4f8cbc2b68
26 changed files with 41 additions and 72 deletions

View File

@@ -53,15 +53,15 @@
</div>
{% if user_can(permissions.VIEW_PORTFOLIO_POC) %}
{% include "fragments/primary_point_of_contact.html" %}
{% include "portfolios/fragments/primary_point_of_contact.html" %}
{% endif %}
{% if user_can(permissions.ARCHIVE_PORTFOLIO) %}
{% include "fragments/delete_portfolio.html" %}
{% include "portfolios/fragments/delete_portfolio.html" %}
{% endif %}
{% if user_can(permissions.VIEW_PORTFOLIO_USERS) %}
{% include "fragments/admin/portfolio_members.html" %}
{% include "portfolios/fragments/portfolio_members.html" %}
{% endif %}
{% if user_can(permissions.VIEW_PORTFOLIO_ACTIVITY_LOG) %}

View File

@@ -1,16 +0,0 @@
{% extends "portfolios/base.html" %}
{% from "components/sticky_cta.html" import StickyCTA %}
{% block portfolio_header %}
{% include "portfolios/header.html" %}
{% if application %}
{{ StickyCTA(text=application.name, return_link_url=url_for('applications.portfolio_applications', portfolio_id=application.portfolio_id), return_link_text="BACK TO APPLICATIONS") }}
{% endif %}
{% endblock %}
{% block portfolio_content %}
<div class='application-content'>
{% block application_content %}{% endblock %}
</div>
{% endblock %}

View File

@@ -1,93 +0,0 @@
{% from "components/icon.html" import Icon %}
{% from "components/empty_state.html" import EmptyState %}
{% extends "portfolios/base.html" %}
{% set can_create_applications = user_can(permissions.CREATE_APPLICATION) %}
{% block portfolio_content %}
<div class='portfolio-applications'>
{% include "fragments/flash.html" %}
<div class='portfolio-applications__header row'>
<div class='portfolio-applications__header--title col col--grow'>Applications</div>
<div class='portfolio-applications__header--actions col'>
{% if can_create_applications %}
<a class='icon-link' href='{{ url_for('applications.view_new_application_step_1', portfolio_id=portfolio.id) }}'>
{{ 'portfolios.applications.add_application_text' | translate }}
{{ Icon("plus", classes="sidenav__link-icon") }}
</a>
{% endif %}
</div>
</div>
{% if not portfolio.applications %}
{{ EmptyState(
'This portfolio doesnt have any applications',
action_label='Add a new application' if can_create_applications else None,
action_href=url_for('applications.create_new_application_step_1', portfolio_id=portfolio.id) if can_create_applications else None,
icon='cloud',
sub_message=None if can_create_applications else 'Please contact your JEDI Cloud portfolio administrator to set up a new application.',
add_perms=can_create_applications
) }}
{% else %}
<div class='application-list'>
{% for application in portfolio.applications|sort(attribute='name') %}
{% set section_name = "application-{}".format(application.id) %}
<toggler inline-template>
<div class='accordion application-list-item'>
<header class='accordion__header row'>
<div class='col col-grow'>
<h3 class='icon-link accordion__title' v-on:click="toggleSection('{{ section_name }}')">{{ application.name }}</h3>
<p class='accordion__description'>
{{ application.description }}
</p>
<div class='accordion__actions'>
<a class='icon-link' href='{{ url_for("applications.settings", application_id=application.id) }}'>
<span>{{ "portfolios.applications.app_settings_text" | translate }}</span>
</a>
<div class='separator'></div>
{% set has_environments = 0 < (application.environments|length) %}
<a class='icon-link triangle-box' v-on:click="toggleSection('{{ section_name }}')" disabled="{{ not has_environments }}">
<span>Environments ({{ application.environments|length }})</span>
{% if has_environments %}
<span v-if="selectedSection === '{{ section_name }}'">
{{ Icon('caret_up') }}
</span>
<span v-else>
{{ Icon('caret_down') }}
</span>
<div class="triangle-up" v-if="selectedSection === '{{ section_name }}'"></div>
{% endif %}
</a>
</div>
</div>
</header>
<ul v-show="selectedSection === '{{ section_name }}'">
{% for environment in application.environments %}
<li class='accordion__item application-list-item__environment'>
<div class='application-list-item__environment__name'>
<span>{{ environment.displayname }}</span>
</div>
{% if g.current_user in environment.users %}
<a href='{{ url_for("applications.access_environment", environment_id=environment.id)}}' target='_blank' rel='noopener noreferrer' class='application-list-item__environment__csp_link icon-link'>
<span>{{ "portfolios.applications.csp_console_text" | translate }}</span>
</a>
{% endif %}
</li>
{% endfor %}
</ul>
</div>
</toggler>
{% endfor %}
</div>
{% endif %}
</div>
{% endblock %}

View File

@@ -1,51 +0,0 @@
{% extends "portfolios/applications/base.html" %}
{% from "components/alert.html" import Alert %}
{% from "components/text_input.html" import TextInput %}
{% from 'components/save_button.html' import SaveButton %}
{% 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) %}
{% else %}
{% set action = url_for('applications.create_new_application_step_1', portfolio_id=portfolio.id, application_id=application_id) %}
{% endif %}
{% block application_content %}
{% include "fragments/flash.html" %}
<div class='subheading'>{{ 'portfolios.applications.settings_heading' | translate }}</div>
<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) }}
</div>
</div>
<div class="form-row">
<div class="form-col form-col--two-thirds">
{{ TextInput(form.description, paragraph=True, optional=False) }}
</div>
</div>
</div>
</div>
<span class="action-group">
{% block next_button %}
{{ SaveButton(text=('portfolios.applications.next_button_text' | translate)) }}
{% endblock %}
</span>
</form>
</application-name-and-description>
{% endblock %}

View File

@@ -1,72 +0,0 @@
{% extends "portfolios/applications/base.html" %}
{% from "components/alert.html" import Alert %}
{% from "components/icon.html" import Icon %}
{% from "components/modal.html" import Modal %}
{% from 'components/save_button.html' import SaveButton %}
{% set secondary_breadcrumb = 'portfolios.applications.new_application_title' | translate %}
{% block application_content %}
{% set modalName = "newApplicationConfirmation" %}
{% include "fragments/flash.html" %}
<div class='subheading'>{{ 'portfolios.applications.settings_heading' | translate }}</div>
<application-environments inline-template v-bind:initial-data='{{ form.data|tojson }}'>
<form method="POST" action="{{ url_for('applications.view_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>
</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>
</div>
<span class="action-group">
{% block next_button %}
{{ SaveButton(text=('portfolios.applications.create_button_text' | translate)) }}
{% endblock %}
</span>
</form>
</application-environments>
{% endblock %}

View File

@@ -1,365 +0,0 @@
{% extends "portfolios/applications/base.html" %}
{% from "components/alert.html" import Alert %}
{% from "components/delete_confirmation.html" import DeleteConfirmation %}
{% from "components/icon.html" import Icon %}
{% import "fragments/applications/new_member_modal_content.html" as member_steps %}
{% from "fragments/applications/member_perms_form_fields.html" import MemberPermsFields %}
{% from "components/modal.html" import Modal %}
{% from "components/multi_step_modal_form.html" import MultiStepModalForm %}
{% from "components/pagination.html" import Pagination %}
{% from "components/save_button.html" import SaveButton %}
{% from "components/text_input.html" import TextInput %}
{% from "components/toggle_list.html" import ToggleButton, ToggleSection %}
{% from "components/icon.html" import Icon %}
{% from "components/text_input.html" import TextInput %}
{% from "components/checkbox_input.html" import CheckboxInput %}
{% from "components/phone_input.html" import PhoneInput %}
{% set secondary_breadcrumb = 'portfolios.applications.existing_application_title' | translate({ "application_name": application.name }) %}
{% block application_content %}
<div class='subheading'>{{ 'portfolios.applications.settings.name_description' | translate }}</div>
{% if user_can(permissions.EDIT_APPLICATION) %}
<base-form inline-template>
<form method="POST" action="{{ url_for('applications.update', application_id=application.id) }}">
<div class="panel">
<div class="panel__content">
{{ application_form.csrf_token }}
<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) }}
</div>
</div>
</div>
<div class="panel__footer">
<div class="action-group">
{{ SaveButton('common.save_changes'|translate) }}
</div>
</div>
</div>
</form>
</base-form>
{% else %}
<div class="panel">
<div class="panel__content">
<p>
{{ "fragments.edit_application_form.explain" | translate }}
</p>
<div class="form-row">
<div class="form-col">
<div class="usa-input usa-input__title__view-only">
{{ application_form.name.label() }}
</div>
<p>
{{ application_form.name.data }}
</p>
</div>
</div>
<div class="form-row">
<div class="form-col">
<div class="usa-input usa-input__title__view-only">
{{ application_form.description.label() }}
</div>
<p>
{{ application_form.description.data }}
</p>
</div>
</div>
</div>
</div>
{% endif %}
{% if not application.members %}
{% set user_can_invite = user_can(permissions.CREATE_APPLICATION_MEMBER) %}
<div class='empty-state'>
<p class='empty-state__message'>{{ ("portfolios.applications.team_settings.blank_slate.title" | translate) }}</p>
{{ Icon('avatar') }}
{% if not user_can_invite %}
<p class='empty-state__sub-message'>{{ ("portfolios.applications.team_settings.blank_slate.sub_message" | translate) }}</p>
{% endif %}
{% if user_can_invite %}
{% set new_member_modal_name = "add-app-mem" %}
<a class="usa-button usa-button-big" v-on:click="openModal('{{ new_member_modal_name }}')">
{{ "portfolios.applications.team_settings.blank_slate.action_label" | translate }}
</a>
{{ MultiStepModalForm(
name=new_member_modal_name,
form=new_member_form,
form_action=url_for("applications.create_member", application_id=application.id),
steps=[
member_steps.MemberStepOne(new_member_form),
member_steps.MemberStepTwo(new_member_form, application)
],
) }}
{% endif %}
</div>
{% else %}
<div class='subheading'>
{{ 'portfolios.applications.settings.team_members' | translate }}
{% set new_member_modal_name = "add-app-mem" %}
{% if user_can(permissions.CREATE_APPLICATION_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'>
{% if g.matchesPath("application-members") %}
{% include "fragments/flash.html" %}
{% endif %}
{% for member in members %}
{% set modal_name = "edit_member-{}".format(loop.index) %}
{% call Modal(modal_name) %}
<div class="modal__form--header">
<h1>{{ Icon('avatar') }} {{ member.user_name }}</h1>
<hr>
</div>
<base-form inline-template>
<form id='{{ modal_name }}' method="POST" action="{{ url_for('applications.update_member', application_id=application.id, application_role_id=member.role_id) }}">
{{ member.form.csrf_token }}
{{ MemberPermsFields(form=member.form, member_role_id=member.role_id) }}
<div class="action-group">
{{ SaveButton(text='Update', element='input', additional_classes='action-group__action') }}
<a class='action-group__action usa-button usa-button-secondary' v-on:click="closeModal('{{ modal_name }}')">{{ "common.cancel" | translate }}</a>
</div>
</form>
</base-form>
{% endcall %}
{% endfor %}
<table>
<thead>
<tr>
<th>Member</th>
<th>Project Permissions</th>
<th>Environment Access</th>
<th></th>
</tr>
</thead>
<tbody>
{% for member in members %}
{% set modal_name = "edit_member-{}".format(loop.index) %}
<tr>
<td>
{{ member.user_name }}
<a class="icon-link" v-on:click="openModal('{{ modal_name }}')">
{{ Icon('edit') }}
</a>
<br>
{% if member.role_status == 'pending' %}
<span class='label label--purple'>INVITE PENDING</span>
{% endif %}
</td>
<td>
{% for perm, value in member.permission_sets.items() %}
{{ ("portfolios.applications.members.{}.{}".format(perm, value)) | translate }}<br>
{% endfor %}
</td>
<td>
{% for env in member.environment_roles %}
{{ env.environment_name }}{% if not env == member.environment_roles[-1]%},{% endif %}
{% endfor %}
</td>
<td>
{% if member.role_status == 'pending' %}
<a href="#">Resend Invite</a><br>
<a href="#">Revoke Invite</a>
{% endif %}
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% if user_can(permissions.CREATE_APPLICATION_MEMBER) %}
{% import "fragments/applications/new_member_modal_content.html" as member_steps %}
{{ MultiStepModalForm(
name=new_member_modal_name,
form=new_member_form,
form_action=url_for("applications.create_member", application_id=application.id),
steps=[
member_steps.MemberStepOne(new_member_form),
member_steps.MemberStepTwo(new_member_form, application)
],
) }}
{% endif %}
</section>
{% endif %}
<div class='subheading'>
{{ 'common.resource_names.environments' | translate }}
{% if user_can(permissions.CREATE_ENVIRONMENT) %}
{% include "fragments/applications/add_new_environment.html" %}
{% endif %}
</div>
<div class="panel">
{% if g.matchesPath("application-environments") %}
{% include "fragments/flash.html" %}
{% endif %}
<div class="panel__content">
<div class="accordion-table accordion-table-list">
<ul class="accordion-table__items">
{% for env in environments_obj %}
{% set edit_form = env['edit_form'] %}
<toggler inline-template>
<li class="accordion-table__item">
<div class="accordion-table__item-content form-row">
<div class="form-col form-col--two-thirds">
<div class="environment-list__item">
<span>
{{ env['name'] }}
</span>
{% if env['pending'] %}
<span class='usa-label'>PROCESSING</span>
{% endif %}
{% if env['pending'] %}
<span class="icon-link">
{% set edit_environment_button %}
{{ Icon('edit') }}
{% endset %}
{{
ToggleButton(
open_html=edit_environment_button,
close_html=edit_environment_button,
section_name="edit"
)
}}
</span>
{% endif %}
<span class="accordion-table__item__toggler icon-link">
{% set members_button = "portfolios.applications.member_count" | translate({'count': env['member_count']}) %}
{{
ToggleButton(
open_html=members_button,
close_html=members_button,
section_name="members"
)
}}
</span>
</div>
</div>
<div class="form-col form-col--third">
{% if env['pending'] %}
<em>Cloud service provider link unavailable</em>
{% else %}
<a href='{{ url_for("applications.access_environment", environment_id=env.id)}}' target='_blank' rel='noopener noreferrer' class='application-list-item__environment__csp_link icon-link'>
<span>{{ "portfolios.applications.csp_link" | translate }} {{ Icon('link', classes="icon--tiny") }}</span>
</a>
{% endif %}
</div>
</div>
{% call ToggleSection(section_name="members") %}
<ul>
{% for member in env['members'] %}
<li class="accordion-table__item__expanded">
{{ member }}
</li>
{% endfor %}
</ul>
{% endcall %}
{% call ToggleSection(section_name="edit") %}
<ul>
<li class="accordion-table__item__expanded">
<form action="{{ url_for('applications.update_environment', environment_id=env['id']) }}" method="post" v-on:submit="handleSubmit">
{{ edit_form.csrf_token }}
{{ TextInput(edit_form.name, validation='requiredField') }}
{{
SaveButton(
text=("common.save" | translate)
)
}}
</form>
</li>
</ul>
{% endcall %}
</li>
</toggler>
{% endfor %}
</ul>
</div>
</div>
</div>
<hr>
{% if user_can(permissions.DELETE_APPLICATION) %}
{% set env_count = application.environments | length %}
{% if env_count == 1 %}
{% set pluralized_env = "environment" %}
{% else %}
{% set pluralized_env = "environments" %}
{% endif %}
<div class='subheading'>
{{ "portfolios.applications.delete.subheading" | translate }}
</div>
<div class="panel">
<div class="panel__content">
<div class="form-row">
<div class="form-col form-col--two-thirds">
{{ "portfolios.applications.delete.panel_text" | translate({"name": application.name, "env_count": env_count , "pluralized_env": pluralized_env}) | safe }}
</div>
<div class="form-col form-col--third">
<div class="usa-input">
<input
id="delete-application"
type="button"
v-on:click="openModal('delete-application')"
class='usa-button button-danger-outline'
value="{{ 'portfolios.applications.delete.button' | translate }}"
>
</div>
</div>
</div>
</div>
</div>
{% call Modal(name="delete-application") %}
<h1>{{ "portfolios.applications.delete.header" | translate }}</h1>
{{
Alert(
title=("components.modal.destructive_title" | translate),
message=("portfolios.applications.delete.alert.message" | translate),
level="warning"
)
}}
{{
DeleteConfirmation(
modal_id="delete_application",
delete_text=('portfolios.applications.delete.button' | translate),
delete_action= url_for('applications.delete', application_id=application.id),
form=application_form
)
}}
{% endcall %}
{% endif %}
{% if user_can(permissions.VIEW_APPLICATION_ACTIVITY_LOG) %}
{% include "fragments/audit_events_log.html" %}
{{ Pagination(audit_events, url=url_for('applications.settings', application_id=application.id)) }}
{% endif %}
{% endblock %}

View File

@@ -0,0 +1,83 @@
{% from "components/icon.html" import Icon %}
{% from "components/text_input.html" import TextInput %}
{% from "components/multi_step_modal_form.html" import MultiStepModalForm %}
{% macro SimpleOptionsInput(field) %}
<div class="usa-input">
<fieldset data-ally-disabled="true" class="usa-input__choices">
<legend>
<div class="usa-input__title-inline">
{{ field.label | striptags}}
</div>
</legend>
{{ field() }}
</fieldset>
</div>
{% endmacro %}
{% set step_one %}
<div class="modal__form--header">
<h1>Invite new portfolio member</h1>
</div>
<div class='form-row'>
<div class='form-col form-col--half'>
{{ TextInput(member_form.user_data.first_name, validation='requiredField', optional=False) }}
</div>
<div class='form-col form-col--half'>
{{ TextInput(member_form.user_data.last_name, validation='requiredField', optional=False) }}
</div>
</div>
<div class='form-row'>
<div class='form-col form-col--half'>
{{ TextInput(member_form.user_data.email, validation='email', optional=False) }}
</div>
<div class='form-col form-col--half'>
{{ TextInput(member_form.user_data.phone_number, validation='usPhone') }}
</div>
</div>
<div class='form-row'>
<div class='form-col form-col--half'>
{{ TextInput(member_form.user_data.dod_id, validation='dodId', optional=False) }}
</div>
<div class='form-col form-col--half'>
</div>
</div>
<div class='action-group'>
<input
type='button'
v-on:click="next()"
v-bind:disabled="invalid"
class='action-group__action usa-button'
value='Next'>
<a class='action-group__action icon-link icon-link--default' v-on:click="closeModal('{{ new_port_mem }}')">Cancel</a>
</div>
{% endset %}
{% set step_two %}
<div class="modal__form--padded">
<div class="modal__form--header">
<h1>Assign member permissions</h1>
<a class='icon-link'>
{{ Icon('info') }}
{{ "portfolios.admin.permissions_info" | translate }}
</a>
</div>
{{ SimpleOptionsInput(member_form.permission_sets.perms_app_mgmt) }}
{{ SimpleOptionsInput(member_form.permission_sets.perms_funding) }}
{{ SimpleOptionsInput(member_form.permission_sets.perms_reporting) }}
{{ SimpleOptionsInput(member_form.permission_sets.perms_portfolio_mgmt) }}
<div class='action-group'>
<input
type="submit"
class='action-group__action usa-button'
form="add-port-mem"
value='Invite member'>
<a class='action-group__action icon-link icon-link--default' v-on:click="closeModal('{{ new_port_mem }}')">Cancel</a>
</div>
</div>
{% endset %}
{{ MultiStepModalForm(
'add-port-mem',
member_form,
url_for("portfolios.invite_member", portfolio_id=portfolio.id),
[step_one, step_two],
) }}

View File

@@ -0,0 +1,83 @@
{% from "components/icon.html" import Icon %}
{% from "components/selector.html" import Selector %}
{% from "components/text_input.html" import TextInput %}
{% from "components/multi_step_modal_form.html" import MultiStepModalForm %}
{% from "components/alert.html" import Alert %}
{% from "components/options_input.html" import OptionsInput %}
{% set step_one %}
<div class="modal__form--header">
<h1>{{ "fragments.ppoc.update_ppoc_title" | translate }}</h1>
</div>
{{
Alert(
level="warning",
title=("fragments.ppoc.alert.title" | translate),
message=("fragments.ppoc.alert.message" | translate),
)
}}
<div class='form-row'>
<div class='form-col form-col--half'>
{{
OptionsInput(
assign_ppoc_form.role_id
)
}}
</div>
<div class='form-col form-col--half'>
</div>
</div>
<div class='action-group'>
<input
type='button'
v-on:click="next()"
v-bind:disabled="invalid"
class='action-group__action usa-button'
value='{{ "fragments.ppoc.assign_user_button_text" | translate }}'>
<a class='action-group__action icon-link icon-link--default' v-on:click="closeModal('change-ppoc-form')">
{{ "common.cancel" | translate }}
</a>
</div>
{% endset %}
{% set step_two %}
<div class="modal__form--padded">
<div class="modal__form--header">
<h1>{{ "fragments.ppoc.update_ppoc_confirmation_title" | translate }}</h1>
</div>
{{
Alert(
level="info",
title=("fragments.ppoc.confirm_alert.title" | translate),
)
}}
<div class='action-group'>
<input
type="submit"
class='action-group__action usa-button'
form="change-ppoc-form"
value='{{ "common.confirm" | translate }}'>
<a class='action-group__action icon-link icon-link--default' v-on:click="closeModal('change-ppoc-form')">
{{ "common.cancel" | translate }}
</a>
</div>
</div>
{% endset %}
<div class="flex-reverse-row">
<a class="usa-button-primary" v-on:click="openModal('change-ppoc-form')">
{{ "fragments.ppoc.update_btn" | translate }}
</a>
{{
MultiStepModalForm(
'change-ppoc-form',
assign_ppoc_form,
form_action=url_for("portfolios.update_ppoc", portfolio_id=portfolio.id),
steps=[step_one, step_two],
)
}}
</div>

View File

@@ -0,0 +1,42 @@
{% from "components/delete_confirmation.html" import DeleteConfirmation %}
{% from "components/alert.html" import Alert %}
{% from "components/modal.html" import Modal %}
<section id="primary-point-of-contact" class="panel">
<div class="panel__content">
<h2>{{ "fragments.delete_portfolio.title" | translate }}</h2>
<p>{{ "fragments.delete_portfolio.subtitle" | translate }}</p>
<div
class="usa-button-primary {% if applications_count == 0 %}button-danger{% else %}usa-button-disabled{% endif %}"
{% if applications_count == 0 %}v-on:click="openModal('delete_portfolio')"{% endif %}
>
{{ "common.deactivate" | translate }}
</div>
</div>
</section>
{% call Modal(name="delete_portfolio") %}
<h1>
{{ 'fragments.delete_portfolio.title' | translate }}
</h1>
{{
Alert(
level="warning",
title=('components.modal.destructive_title' | translate),
message=('components.modal.destructive_message' | translate({"resource": "portfolio"})),
)
}}
{{
DeleteConfirmation(
modal_id='delete_portfolio',
delete_text='Deactivate',
delete_action=url_for('portfolios.delete_portfolio', portfolio_id=portfolio.id),
form=portfolio_form,
confirmation_text="deactivate",
)
}}
{% endcall %}

View File

@@ -0,0 +1,39 @@
{% from "components/alert.html" import Alert %}
{% from "components/modal.html" import Modal %}
{% from "components/options_input.html" import OptionsInput %}
{% for subform in member_perms_form.members_permissions %}
{% set modal_id = "portfolio_id_{}_user_id_{}".format(portfolio.id, subform.member_id.data) %}
{% set ppoc = subform.member_id.data == ppoc_id %}
{% set archive_button_class = 'button-danger-outline' %}
<tr {% if ppoc %}class="members-table-ppoc"{% endif %}>
<td class='name'>{{ subform.member_name.data }}
<div>
{% if ppoc %}
{% set archive_button_class = 'usa-button-disabled' %}
<span class='you'>PPoC</span>
{% endif %}
{% if subform.member_id.data == current_member_id %}
{% set archive_button_class = 'usa-button-disabled' %}
<span class='you'>(<span class='green'>you</span>)</span>
{% endif %}
</div>
</td>
<td>{{ OptionsInput(subform.perms_app_mgmt, label=False, disabled=ppoc) }}</td>
<td>{{ OptionsInput(subform.perms_funding, label=False, disabled=ppoc) }}</td>
<td>{{ OptionsInput(subform.perms_reporting, label=False, disabled=ppoc) }}</td>
<td>{{ OptionsInput(subform.perms_portfolio_mgmt, label=False, disabled=ppoc) }}</td>
<td>
<a v-on:click="openModal('{{ modal_id }}')" class='usa-button {{ archive_button_class }}'>
{{ "portfolios.members.archive_button" | translate }}
</a>
</td>
{% if not ppoc %}
{{ subform.member_id() }}
{% endif %}
</tr>
{% endfor %}

View File

@@ -0,0 +1,26 @@
{% for subform in member_perms_form.members_permissions %}
{% set ppoc = subform.member_id.data == ppoc_id %}
{% set heading_perms = [subform.perms_app_mgmt, subform.perms_funding, subform.perms_reporting, subform.perms_portfolio_mgmt] %}
<tr>
<td class='name'>{{ subform.member_name.data }}
<div>
{% if ppoc %}
<span class='you'>PPoC</span>
{% endif %}
{% if subform.member_id.data == current_member_id %}
<span class='you'>(<span class='green'>you</span>)</span>
{% endif %}
</div>
</td>
{% for access in heading_perms %}
{% if dict(access.choices).get(access.data) == ('portfolios.members.permissions.edit_access' | translate) %}
<td class='green'>{{ 'portfolios.members.permissions.edit_access' | translate }}</td>
{% else %}
<td>{{ 'common.view' | translate }}</td>
{% endif %}
{% endfor %}
</tr>
{% endfor %}

View File

@@ -0,0 +1,107 @@
{% from "components/icon.html" import Icon %}
{% from 'components/save_button.html' import SaveButton %}
{% from "components/modal.html" import Modal %}
{% from "components/alert.html" import Alert %}
<section class="member-list" id="portfolio-members">
<base-form inline-template>
<div class='responsive-table-wrapper panel accordion-table'>
{% if g.matchesPath("portfolio-members") %}
{% include "fragments/flash.html" %}
{% endif %}
<form method='POST' id="member-perms" action='{{ url_for("portfolios.edit_members", portfolio_id=portfolio.id) }}' autocomplete="off" enctype="multipart/form-data">
{{ member_perms_form.csrf_token }}
<div class='application-list-item'>
<header>
<div class='responsive-table-wrapper__header'>
<div class='responsive-table-wrapper__title'>
<div class='h3'>{{ "portfolios.admin.portfolio_members_title" | translate }}</div>
<div class='subheading'>
{{ "portfolios.admin.portfolio_members_subheading" | translate }}
</div>
</div>
<a class='icon-link'>
{{ Icon('info') }}
{{ "portfolios.admin.settings_info" | translate }}
</a>
</div>
</header>
{% if not portfolio.members %}
<p>{{ "portfolios.admin.no_members" | translate }}</p>
{% else %}
<table class="atat-table">
<thead>
<tr>
<td>{{ "portfolios.members.permissions.name" | translate }}</td>
<td>{{ "portfolios.members.permissions.app_mgmt" | translate }}</td>
<td>{{ "portfolios.members.permissions.funding" | translate }}</td>
<td>{{ "portfolios.members.permissions.reporting" | translate }}</td>
<td>{{ "portfolios.members.permissions.portfolio_mgmt" | translate }}</td>
<td></td>
</tr>
</thead>
<tbody>
{% if user_can(permissions.EDIT_PORTFOLIO_USERS) %}
{% include "portfolios/fragments/members_edit.html" %}
{% elif user_can(permissions.VIEW_PORTFOLIO_USERS) %}
{% include "portfolios/fragments/members_view.html" %}
{% endif %}
</tbody>
</table>
</div>
{% endif %}
<div class="panel__footer">
<div class="action-group save">
{% if user_can(permissions.EDIT_PORTFOLIO_USERS) %}
{{ SaveButton(text=('common.save' | translate), element="input", form="member-perms") }}
{% endif %}
{% if user_can(permissions.CREATE_PORTFOLIO_USERS) %}
<a class="icon-link modal-link" v-on:click="openModal('add-port-mem')">
{{ "portfolios.admin.add_new_member" | translate }}
{{ Icon("plus") }}
</a>
{% endif %}
</div>
</div>
</form>
{% if user_can(permissions.CREATE_PORTFOLIO_USERS) %}
{% include "portfolios/fragments/add_new_portfolio_member.html" %}
{% endif %}
{% if user_can(permissions.EDIT_PORTFOLIO_USERS) %}
{% for subform in member_perms_form.members_permissions %}
{% set modal_id = "portfolio_id_{}_user_id_{}".format(portfolio.id, subform.member_id.data) %}
{% call Modal(name=modal_id, dismissable=False) %}
<h1>{{ "portfolios.admin.alert_header" | translate }}</h1>
{{
Alert(
title="portfolios.admin.alert_title" | translate,
message="portfolios.admin.alert_message" | translate,
level="warning"
)
}}
<div class="panel__footer">
<div class="action-group">
<form method="POST" action="{{ url_for('portfolios.remove_member', portfolio_id=portfolio.id, portfolio_role_id=subform.member_id.data)}}">
{{ member_perms_form.csrf_token }}
<button class="usa-button usa-button-danger">
{{ "portfolios.members.archive_button" | translate }}
</button>
</form>
<a v-on:click="closeModal('{{ modal_id }}')" class="action-group__action icon-link icon-link--default">{{ "common.cancel" | translate }}</a>
</div>
</div>
{% endcall %}
{% endfor %}
{% endif %}
</div>
</base-form>
</section>

View File

@@ -0,0 +1,25 @@
<section id="primary-point-of-contact" class="panel">
<div class="panel__content">
{% if g.matchesPath("primary-point-of-contact") %}
{% include "fragments/flash.html" %}
{% endif %}
<h2>{{ "fragments.ppoc.title" | translate }}</h2>
<p>{{ "fragments.ppoc.subtitle" | translate }}</p>
<p>
<strong>
{{ portfolio.owner.first_name }}
{{ portfolio.owner.last_name }}
</strong>
<br />
{{ portfolio.owner.email }}
<br />
{{ portfolio.owner.phone_number | usPhone }}
</p>
{% if user_can(permissions.EDIT_PORTFOLIO_POC) %}
{% include "portfolios/fragments/change_ppoc.html" %}
{% endif %}
</div>
</section>

View File

@@ -1,119 +0,0 @@
{% from "components/empty_state.html" import EmptyState %}
{% from "components/icon.html" import Icon %}
{% from "components/sticky_cta.html" import StickyCTA %}
{% extends "portfolios/base.html" %}
{% block portfolio_content %}
{% macro TaskOrderButton(task_order, route, text="Edit", secondary=False) %}
<a href="{{ url_for(route, task_order_id=task_order.id) }}" class="usa-button {{ 'usa-button-secondary' if secondary else '' }}">
{{ text }}
</a>
{% endmacro %}
{% macro TaskOrderDateTime(dt, className="") %}
<local-datetime timestamp="{{ dt }}" format="MMMM D, YYYY" class="{{ className }}"></local-datetime>
{% endmacro %}
{% macro TaskOrderDate(task_order) %}
<span class="datetime">
<!-- Draft: {Begins, Began} start_date -->
<!-- Everything else: {Starts, Started} start_date | {Ends, Ended} end_date -->
{% if task_order.is_draft %}
{% if task_order.has_begun %}
Started on
{% else %}
Starts on
{% endif %}
{{ TaskOrderDateTime(task_order.time_created) }}
{% else %}
{% if task_order.has_begun %}
Began
{% else %}
Begins
{% endif %}
{{ TaskOrderDateTime(task_order.start_date) }}
{% endif %}
{% if not task_order.is_draft %}
&nbsp;&nbsp;|&nbsp;&nbsp;
{% if task_order.has_ended %}
Ended
{% else %}
Ends
{% endif %}
{{ TaskOrderDateTime(task_order.end_date) }}
{% endif %}
</span>
{% endmacro %}
{% macro TaskOrderActions(task_order) %}
<div class="task-order-card__buttons">
{% if task_order.is_draft and user_can(permissions.EDIT_TASK_ORDER_DETAILS) %}
{{ TaskOrderButton(task_order, "task_orders.edit")}}
{% elif task_order.is_expired %}
{{ TaskOrderButton(task_order, "task_orders.review_task_order", text="View") }}
{% elif task_order.is_unsigned %}
{% if user_can(permissions.EDIT_TASK_ORDER_DETAILS) %}
{{ TaskOrderButton(task_order, "task_orders.form_step_four_review", text="Sign", secondary=True) }}
{% endif %}
{{ TaskOrderButton(task_order, "task_orders.review_task_order", text="View") }}
{% endif %}
</div>
{% endmacro %}
{% macro TaskOrderList(task_orders, label='success') %}
<div class="task-order-list">
{% for task_order in task_orders %}
<div class="card task-order-card">
<div class="card__status">
<span class='label label--{{ label_colors[task_order.status] }}'>{{ task_order.display_status }}</span>
{{ TaskOrderDate(task_order) }}
<span class="card__status-spacer"></span>
<span class="card__button">
{{ TaskOrderActions(task_order) }}
</span>
</div>
<div class="card__header">
<h3>Task Order #{{ task_order.number }}</h3>
</div>
<div class="card__body">
<b>Total amount: </b>{{ task_order.total_contract_amount | dollars }}
</div>
<div class="card__body">
<b>Obligated amount: </b>{{ task_order.total_obligated_funds | dollars }}
</div>
</div>
{% endfor %}
</div>
{% endmacro %}
{% call StickyCTA(text="Funding") %}
{% if user_can(permissions.CREATE_TASK_ORDER) %}
<a href="{{ url_for("task_orders.form_step_one_add_pdf", portfolio_id=portfolio.id) }}" class="usa-button usa-button-primary" type="submit">Start a new task order</a>
{% endif %}
{% endcall %}
{% include "fragments/flash.html" %}
<div class="portfolio-funding">
{% if task_orders %}
{{ TaskOrderList(task_orders) }}
{% else %}
{{ EmptyState(
'This portfolio doesnt have any active or pending task orders.',
action_label='Add a New Task Order',
action_href=url_for('task_orders.form_step_one_add_pdf', portfolio_id=portfolio.id),
icon='cloud',
add_perms=user_can(permissions.CREATE_TASK_ORDER)
) }}
{% endif %}
</div>
{% endblock %}

View File

@@ -1,16 +0,0 @@
{% from "components/sticky_cta.html" import StickyCTA %}
{% extends 'portfolios/base.html' %}
{% block portfolio_content %}
{% call StickyCTA(text="Task order details") %}
{% if user_can(permissions.EDIT_TASK_ORDER_DETAILS) and not task_order.is_expired %}
<a href="{{ url_for('task_orders.edit', task_order_id=task_order.id) }}" class="usa-button usa-button-secondary" type="submit">Edit</a>
{% endif %}
{% endcall %}
<div class="task-order">
{% include "fragments/task_order_review.html" %}
</div>
{% endblock %}