workspace -> portfolio everywhere

This commit is contained in:
dandds
2019-01-11 09:58:00 -05:00
parent 3fc323d785
commit d3d36822df
122 changed files with 2156 additions and 2129 deletions

View File

@@ -1,5 +1,5 @@
{% extends "audit_log/events/_base.html" %}
{% block content %}
in Portfolio <code>{{ event.workspace_id }}</code> ({{ event.workspace.name }})
in Portfolio <code>{{ event.portfolio_id }}</code> ({{ event.portfolio.name }})
{% endblock %}

View File

@@ -14,6 +14,6 @@
<br>
in Application <code>{{ event.event_details["application_id"] }}</code> ({{ event.event_details["application"] }})
<br>
in Portfolio <code>{{ event.event_details["workspace_id"] }}</code> ({{ event.event_details["workspace"] }})
in Portfolio <code>{{ event.event_details["portfolio_id"] }}</code> ({{ event.event_details["portfolio"] }})
{% endif %}
{% endblock %}

View File

@@ -10,5 +10,5 @@
invited {{ event.event_details.email }} (DOD <code>{{ event.event_details.dod_id }}</code>)
<br>
{% endif %}
in Portfolio <code>{{ event.workspace_id }}</code> ({{ event.workspace.name }})
in Portfolio <code>{{ event.portfolio_id }}</code> ({{ event.portfolio.name }})
{% endblock %}

View File

@@ -2,7 +2,7 @@
{% block content %}
for User <code>{{ event.event_details.updated_user_id }}</code> ({{ event.event_details.updated_user_name }})
in Portfolio <code>{{ event.workspace_id }}</code> ({{ event.workspace.name }})
in Portfolio <code>{{ event.portfolio_id }}</code> ({{ event.portfolio.name }})
{% if event.changed_state.status %}
from status "{{ event.changed_state.status[0] }}" to "{{ event.changed_state.status[1] }}"

View File

@@ -1,4 +1,4 @@
{% macro Page(pagination, route, i, label=None, disabled=False, workspace_id=None) -%}
{% macro Page(pagination, route, i, label=None, disabled=False, portfolio_id=None) -%}
{% set label = label or i %}
{% set button_class = "page usa-button " %}
@@ -11,42 +11,42 @@
{% set button_class = button_class + "usa-button-secondary" %}
{% endif %}
<a id="{{ label }}" type="button" class="{{ button_class }}" href="{{ url_for(route, workspace_id=workspace_id, page=i, perPage=pagination.per_page) if not disabled else 'null' }}">{{ label }}</a>
<a id="{{ label }}" type="button" class="{{ button_class }}" href="{{ url_for(route, portfolio_id=portfolio_id, page=i, perPage=pagination.per_page) if not disabled else 'null' }}">{{ label }}</a>
{%- endmacro %}
{% macro Pagination(pagination, route, workspace_id=None) -%}
{% macro Pagination(pagination, route, portfolio_id=None) -%}
<div class="pagination">
{% if pagination.page == 1 %}
{{ Page(pagination, route, 1, label="first", disabled=True, workspace_id=workspace_id) }}
{{ Page(pagination, route, pagination.page - 1, label="prev", disabled=True, workspace_id=workspace_id) }}
{{ Page(pagination, route, 1, label="first", disabled=True, portfolio_id=portfolio_id) }}
{{ Page(pagination, route, pagination.page - 1, label="prev", disabled=True, portfolio_id=portfolio_id) }}
{% else %}
{{ Page(pagination, route, 1, label="first", workspace_id=workspace_id) }}
{{ Page(pagination, route, pagination.page - 1, label="prev", workspace_id=workspace_id) }}
{{ Page(pagination, route, 1, label="first", portfolio_id=portfolio_id) }}
{{ Page(pagination, route, pagination.page - 1, label="prev", portfolio_id=portfolio_id) }}
{% endif %}
{% if pagination.page == 1 %}
{% set max_page = [pagination.pages, 5] | min %}
{% for i in range(1, max_page + 1) %}
{{ Page(pagination, route, i, workspace_id=workspace_id) }}
{{ Page(pagination, route, i, portfolio_id=portfolio_id) }}
{% endfor %}
{% elif pagination.page == pagination.pages %}
{% for i in range(pagination.pages - 4, pagination.pages + 1) %}
{{ Page(pagination, route, i, workspace_id=workspace_id) }}
{{ Page(pagination, route, i, portfolio_id=portfolio_id) }}
{% endfor %}
{% else %}
{% set window = pagination | pageWindow %}
{% for i in range(window.0, window.1 + 1) %}
{{ Page(pagination, route, i, workspace_id=workspace_id) }}
{{ Page(pagination, route, i, portfolio_id=portfolio_id) }}
{% endfor %}
{% endif %}
{% if pagination.page == pagination.pages %}
{{ Page(pagination, route, pagination.page + 1, label="next", disabled=True, workspace_id=workspace_id) }}
{{ Page(pagination, route, pagination.pages, label="last", disabled=True, workspace_id=workspace_id) }}
{{ Page(pagination, route, pagination.page + 1, label="next", disabled=True, portfolio_id=portfolio_id) }}
{{ Page(pagination, route, pagination.pages, label="last", disabled=True, portfolio_id=portfolio_id) }}
{% else %}
{{ Page(pagination, route, pagination.page + 1, label="next", workspace_id=workspace_id) }}
{{ Page(pagination, route, pagination.pages, label="last", workspace_id=workspace_id) }}
{{ Page(pagination, route, pagination.page + 1, label="next", portfolio_id=portfolio_id) }}
{{ Page(pagination, route, pagination.pages, label="last", portfolio_id=portfolio_id) }}
{% endif %}
</div>

View File

@@ -1,7 +1,7 @@
Join this JEDI Cloud Portfolio
{{ owner }} has invited you to join a JEDI Cloud Portfolio. Login now to view or use your JEDI Cloud resources.
{{ url_for("workspaces.accept_invitation", token=token, _external=True) }}
{{ url_for("portfolios.accept_invitation", token=token, _external=True) }}
What is JEDI Cloud?
JEDI Cloud is a DoD enterprise-wide solution for commercial cloud services.

View File

@@ -1,6 +1,6 @@
{% from "components/sidenav_item.html" import SidenavItem %}
<div class="global-navigation sidenav {% if workspace %}global-navigation__context--workspace{% endif %}">
<div class="global-navigation sidenav {% if portfolio %}global-navigation__context--portfolio{% endif %}">
<ul>
{{ SidenavItem("New Task Order",
href=url_for("task_orders.get_started"),
@@ -8,8 +8,8 @@
active=g.matchesPath('/task_orders/new'),
) }}
{% if g.current_user.has_workspaces %}
{{ SidenavItem("Portfolios", href="/workspaces", icon="cloud", active=g.matchesPath('/workspaces')) }}
{% if g.current_user.has_portfolios %}
{{ SidenavItem("Portfolios", href="/portfolios", icon="cloud", active=g.matchesPath('/portfolios')) }}
{% endif %}
{% if g.Authorization.has_atat_permission(g.current_user, g.Permissions.VIEW_AUDIT_LOG) %}

View File

@@ -0,0 +1,68 @@
{% from "components/sidenav_item.html" import SidenavItem %}
<nav class='sidenav portfolio-navigation'>
<ul>
{{ SidenavItem(
("navigation.portfolio_navigation.applications" | translate),
href=url_for("portfolios.portfolio_applications", portfolio_id=portfolio.id),
active=request.url_rule.rule.startswith('/portfolios/<portfolio_id>/applications'),
subnav=None if not user_can(permissions.ADD_APPLICATION_IN_WORKSPACE) else [
{
"label": ("navigation.portfolio_navigation.add_new_application_label" | translate),
"href": url_for('portfolios.new_application', portfolio_id=portfolio.id),
"active": g.matchesPath('\/portfolios\/[A-Za-z0-9-]*\/applications'),
"icon": "plus"
}
]
) }}
{% if user_can(permissions.VIEW_WORKSPACE_MEMBERS) %}
{{ SidenavItem(
("navigation.portfolio_navigation.members" | translate),
href=url_for("portfolios.portfolio_members", portfolio_id=portfolio.id),
active=request.url_rule.rule.startswith('/portfolios/<portfolio_id>/members'),
subnav=None if not user_can(permissions.ASSIGN_AND_UNASSIGN_ATAT_ROLE) else [
{
"label": ("navigation.portfolio_navigation.add_new_member_label" | translate),
"href": url_for("portfolios.new_member", portfolio_id=portfolio.id),
"active": request.url_rule.rule.startswith('/portfolios/<portfolio_id>/members/new'),
"icon": "plus"
}
]
) }}
{% endif %}
{% if user_can(permissions.VIEW_USAGE_DOLLARS) %}
{{ SidenavItem(
("navigation.portfolio_navigation.budget_report" | translate),
href=url_for("portfolios.portfolio_reports", portfolio_id=portfolio.id),
active=request.url_rule.rule.startswith('/portfolios/<portfolio_id>/reports')
) }}
{% endif %}
{{ SidenavItem(
("navigation.portfolio_navigation.task_orders" | translate),
href=url_for("portfolios.portfolio_task_orders", portfolio_id=portfolio.id),
active=request.url_rule.rule.startswith('/portfolios/<portfolio_id>/task_order'),
subnav=None
) }}
{% if user_can(permissions.EDIT_WORKSPACE_INFORMATION) %}
{{ SidenavItem(
("navigation.portfolio_navigation.portfolio_settings" | translate),
href=url_for("portfolios.portfolio", portfolio_id=portfolio.id),
active=request.url_rule.rule.startswith('/portfolios/<portfolio_id>/edit'),
subnav=None
) }}
{% endif %}
{% if user_can(permissions.VIEW_WORKSPACE_AUDIT_LOG) %}
{{ SidenavItem(
("navigation.portfolio_navigation.activity_log" | translate),
href=url_for("portfolios.portfolio_activity", portfolio_id=portfolio.id),
active=request.url_rule.rule.startswith('/portfolios/<portfolio_id>/activity')
) }}
{% endif %}
</ul>
</nav>

View File

@@ -2,7 +2,7 @@
<header class="topbar">
<nav class="topbar__navigation">
{% if not workspace %}
{% if not portfolio %}
<a href="{{ url_for('atst.home') }}" class="topbar__link topbar__link--home">
{{ Icon('shield', classes='topbar__link-icon') }}
<span class="topbar__link-label">
@@ -15,31 +15,31 @@
</a>
{% endif %}
<div class="topbar__context {% if workspace %}topbar__context--workspace{% endif %}">
{% if workspace %}
<div class="topbar__context {% if portfolio %}topbar__context--portfolio{% endif %}">
{% if portfolio %}
<div is='toggler' class='topbar__workspace-menu'>
<div is='toggler' class='topbar__portfolio-menu'>
<template slot-scope='props'>
<button
v-on:click='props.toggle'
class="topbar__link topbar__workspace-menu__toggle"
v-bind:class="{ 'topbar__workspace-menu__toggle--open': props.isVisible }">
<span class="topbar__link-label">{{ "navigation.topbar.named_workspace" | translate({ "workspace": workspace.name }) }}</span>
class="topbar__link topbar__portfolio-menu__toggle"
v-bind:class="{ 'topbar__portfolio-menu__toggle--open': props.isVisible }">
<span class="topbar__link-label">{{ "navigation.topbar.named_portfolio" | translate({ "portfolio": portfolio.name }) }}</span>
<template v-if='props.isVisible'>{{ Icon('caret_up', classes='topbar__link-icon') }}</template>
<template v-else>{{ Icon('caret_down', classes='topbar__link-icon') }}</template>
</button>
<div v-show='props.isVisible' class='topbar__workspace-menu__panel menu'>
<div v-show='props.isVisible' class='topbar__portfolio-menu__panel menu'>
<h2 class='menu__heading'>
{{ "navigation.topbar.other_active_workspaces" | translate }}
{{ "navigation.topbar.other_active_portfolios" | translate }}
</h2>
{% if workspaces %}
{% if portfolios %}
<ul class='menu__list'>
{% for other_workspace in workspaces %}
{% for other_portfolio in portfolios %}
<li class='menu__list__item'>
<a href="{{ url_for('workspaces.show_workspace', workspace_id=other_workspace.id)}}">
{{ other_workspace.name }}
<a href="{{ url_for('portfolios.show_portfolio', portfolio_id=other_portfolio.id)}}">
{{ other_portfolio.name }}
{{ Icon('caret_right', classes='topbar__link-icon') }}
</a>
</li>
@@ -49,7 +49,7 @@
{% else %}
<p class='menu__message'>
{{ "navigation.topbar.no_other_active_workspaces" | translate }}
{{ "navigation.topbar.no_other_active_portfolios" | translate }}
</p>
{% endif %}

View File

@@ -1,68 +0,0 @@
{% from "components/sidenav_item.html" import SidenavItem %}
<nav class='sidenav workspace-navigation'>
<ul>
{{ SidenavItem(
("navigation.workspace_navigation.applications" | translate),
href=url_for("workspaces.workspace_applications", workspace_id=workspace.id),
active=request.url_rule.rule.startswith('/workspaces/<workspace_id>/applications'),
subnav=None if not user_can(permissions.ADD_APPLICATION_IN_WORKSPACE) else [
{
"label": ("navigation.workspace_navigation.add_new_application_label" | translate),
"href": url_for('workspaces.new_application', workspace_id=workspace.id),
"active": g.matchesPath('\/workspaces\/[A-Za-z0-9-]*\/applications'),
"icon": "plus"
}
]
) }}
{% if user_can(permissions.VIEW_WORKSPACE_MEMBERS) %}
{{ SidenavItem(
("navigation.workspace_navigation.members" | translate),
href=url_for("workspaces.workspace_members", workspace_id=workspace.id),
active=request.url_rule.rule.startswith('/workspaces/<workspace_id>/members'),
subnav=None if not user_can(permissions.ASSIGN_AND_UNASSIGN_ATAT_ROLE) else [
{
"label": ("navigation.workspace_navigation.add_new_member_label" | translate),
"href": url_for("workspaces.new_member", workspace_id=workspace.id),
"active": request.url_rule.rule.startswith('/workspaces/<workspace_id>/members/new'),
"icon": "plus"
}
]
) }}
{% endif %}
{% if user_can(permissions.VIEW_USAGE_DOLLARS) %}
{{ SidenavItem(
("navigation.workspace_navigation.budget_report" | translate),
href=url_for("workspaces.workspace_reports", workspace_id=workspace.id),
active=request.url_rule.rule.startswith('/workspaces/<workspace_id>/reports')
) }}
{% endif %}
{{ SidenavItem(
("navigation.workspace_navigation.task_orders" | translate),
href=url_for("workspaces.workspace_task_orders", workspace_id=workspace.id),
active=request.url_rule.rule.startswith('/workspaces/<workspace_id>/task_order'),
subnav=None
) }}
{% if user_can(permissions.EDIT_WORKSPACE_INFORMATION) %}
{{ SidenavItem(
("navigation.workspace_navigation.workspace_settings" | translate),
href=url_for("workspaces.workspace", workspace_id=workspace.id),
active=request.url_rule.rule.startswith('/workspaces/<workspace_id>/edit'),
subnav=None
) }}
{% endif %}
{% if user_can(permissions.VIEW_WORKSPACE_AUDIT_LOG) %}
{{ SidenavItem(
("navigation.workspace_navigation.activity_log" | translate),
href=url_for("workspaces.workspace_activity", workspace_id=workspace.id),
active=request.url_rule.rule.startswith('/workspaces/<workspace_id>/activity')
) }}
{% endif %}
</ul>
</nav>

View File

@@ -0,0 +1,9 @@
{% extends "portfolios/base.html" %}
{% from "components/pagination.html" import Pagination %}
{% block portfolio_content %}
<div v-cloak>
{% include "fragments/audit_events_log.html" %}
{{ Pagination(audit_events, 'portfolios.portfolio_activity', portfolio_id=portfolio_id) }}
</div>
{% endblock %}

View File

@@ -1,10 +1,10 @@
{% extends "workspaces/base.html" %}
{% extends "portfolios/base.html" %}
{% from "components/text_input.html" import TextInput %}
{% block workspace_content %}
{% block portfolio_content %}
<form method="POST" action="{{ url_for('workspaces.edit_application', workspace_id=workspace.id, application_id=application.id) }}">
<form method="POST" action="{{ url_for('portfolios.edit_application', portfolio_id=portfolio.id, application_id=application.id) }}">
{% include "fragments/edit_application_form.html" %}

View File

@@ -1,31 +1,31 @@
{% from "components/icon.html" import Icon %}
{% from "components/empty_state.html" import EmptyState %}
{% extends "workspaces/base.html" %}
{% extends "portfolios/base.html" %}
{% block workspace_content %}
{% block portfolio_content %}
{% if not workspace.applications %}
{% if not portfolio.applications %}
{% set can_create_applications = user_can(permissions.ADD_APPLICATION_IN_WORKSPACE) %}
{{ EmptyState(
'This portfolio doesnt have any applications yet.',
action_label='Add a New Application' if can_create_applications else None,
action_href=url_for('workspaces.new_application', workspace_id=workspace.id) if can_create_applications else None,
action_href=url_for('portfolios.new_application', 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.'
) }}
{% else %}
{% for application in workspace.applications %}
{% for application in portfolio.applications %}
<div v-cloak class='block-list application-list-item'>
<header class='block-list__header'>
<h2 class='block-list__title'>{{ application.name }} ({{ application.environments|length }} environments)</h2>
{% if user_can(permissions.RENAME_APPLICATION_IN_WORKSPACE) %}
<a class='icon-link' href='{{ url_for("workspaces.edit_application", workspace_id=workspace.id, application_id=application.id) }}'>
<a class='icon-link' href='{{ url_for("portfolios.edit_application", portfolio_id=portfolio.id, application_id=application.id) }}'>
{{ Icon('edit') }}
<span>edit</span>
</a>
@@ -34,7 +34,7 @@
<ul>
{% for environment in application.environments %}
<li class='block-list__item application-list-item__environment'>
<a href='{{ url_for("workspaces.access_environment", workspace_id=workspace.id, environment_id=environment.id)}}' target='_blank' rel='noopener noreferrer' class='application-list-item__environment__link'>
<a href='{{ url_for("portfolios.access_environment", portfolio_id=portfolio.id, environment_id=environment.id)}}' target='_blank' rel='noopener noreferrer' class='application-list-item__environment__link'>
{{ Icon('link') }}
<span>{{ environment.name }}</span>
</a>

View File

@@ -1,17 +1,17 @@
{% extends "workspaces/base.html" %}
{% extends "portfolios/base.html" %}
{% from "components/alert.html" import Alert %}
{% from "components/icon.html" import Icon %}
{% from "components/modal.html" import Modal %}
{% from "components/text_input.html" import TextInput %}
{% block workspace_content %}
{% block portfolio_content %}
{% set modalName = "newApplicationConfirmation" %}
{% include "fragments/flash.html" %}
<new-application inline-template v-bind:initial-data='{{ form.data|tojson }}' modal-name='{{ modalName }}'>
<form method="POST" action="{{ url_for('workspaces.create_application', workspace_id=workspace.id) }}" v-on:submit="handleSubmit">
<form method="POST" action="{{ url_for('portfolios.create_application', portfolio_id=portfolio.id) }}" v-on:submit="handleSubmit">
{% call Modal(name=modalName, dismissable=False) %}
<h1>Create application !{ name }</h1>

View File

@@ -0,0 +1,15 @@
{% extends "base.html" %}
{% block content %}
<div class='portfolio-panel-container'>
<div class='col'>
{% include 'navigation/portfolio_navigation.html' %}
</div>
<div class='col col--grow'>
{% block portfolio_content %}{% endblock %}
</div>
</div>
{% endblock %}

View File

@@ -1,13 +1,13 @@
{% extends "workspaces/base.html" %}
{% extends "portfolios/base.html" %}
{% from "components/icon.html" import Icon %}
{% from "components/text_input.html" import TextInput %}
{% block workspace_content %}
{% block portfolio_content %}
{% include "fragments/flash.html" %}
<form method="POST" action="{{ url_for('workspaces.edit_workspace', workspace_id=workspace.id) }}" autocomplete="false">
<form method="POST" action="{{ url_for('portfolios.edit_portfolio', portfolio_id=portfolio.id) }}" autocomplete="false">
{{ form.csrf_token }}
<div class="panel">
@@ -17,14 +17,14 @@
</div>
<div class="panel__content">
{{ TextInput(form.name, validation="workspaceName") }}
{{ TextInput(form.name, validation="portfolioName") }}
</div>
</div>
<div class='action-group'>
<button type="submit" class="usa-button usa-button-big usa-button-primary" tabindex="0">Save</button>
<a href='{{ url_for("workspaces.workspace_applications", workspace_id=workspace.id) }}' class='action-group__action icon-link'>
<a href='{{ url_for("portfolios.portfolio_applications", portfolio_id=portfolio.id) }}' class='action-group__action icon-link'>
{{ Icon('x') }}
<span>Cancel</span>
</a>

View File

@@ -11,16 +11,16 @@
</tr>
</thead>
<tbody>
{% for workspace in workspaces %}
{% for portfolio in portfolios %}
<tr>
<td>
<a class='icon-link icon-link--large' href="/workspaces/{{ workspace.id }}/applications">{{ workspace.name }}</a><br>
<a class='icon-link icon-link--large' href="/portfolios/{{ portfolio.id }}/applications">{{ portfolio.name }}</a><br>
</td>
<td>
#{{ workspace.legacy_task_order.number }}
#{{ portfolio.legacy_task_order.number }}
</td>
<td>
<span class="label">{{ workspace.user_count }}</span><span class='h6'>Users</span>
<span class="label">{{ portfolio.user_count }}</span><span class='h6'>Users</span>
</td>
</tr>
{% endfor %}

View File

@@ -10,7 +10,7 @@
{% include "fragments/flash.html" %}
<form method="POST" action="{{ url_for('workspaces.update_member', workspace_id=workspace.id, member_id=member.user_id) }}" autocomplete="false">
<form method="POST" action="{{ url_for('portfolios.update_member', portfolio_id=portfolio.id, member_id=member.user_id) }}" autocomplete="false">
{{ form.csrf_token }}
<div class='panel member-card'>
@@ -18,7 +18,7 @@
<h1 class='member-card__heading'>{{ member.user.full_name }}</h1>
<div class="usa-input member-card__input">
{{ Selector(form.workspace_role) }}
{{ Selector(form.portfolio_role) }}
</div>
</div>
@@ -40,20 +40,20 @@
{% if member.latest_invitation.is_revokable %}
{{ ConfirmationButton(
"Revoke Invitation",
url_for("workspaces.revoke_invitation", workspace_id=workspace.id, token=member.latest_invitation.token),
url_for("portfolios.revoke_invitation", portfolio_id=portfolio.id, token=member.latest_invitation.token),
) }}
{% endif %}
{% if member.can_resend_invitation %}
{{ ConfirmationButton (
"Resend Invitation",
url_for("workspaces.resend_invitation", workspace_id=workspace.id, token=member.latest_invitation.token),
url_for("portfolios.resend_invitation", portfolio_id=portfolio.id, token=member.latest_invitation.token),
confirm_msg="Are you sure? This will send an email to invite the user to join this portfolio."
)}}
{% endif %}
{% if can_revoke_access %}
{{ ConfirmationButton (
"Remove Portfolio Access",
url_for("workspaces.revoke_access", workspace_id=workspace.id, member_id=member.id),
url_for("portfolios.revoke_access", portfolio_id=portfolio.id, member_id=member.id),
confirm_msg="Are you sure? This will remove this user from the portfolio.",
)}}
{% endif %}
@@ -177,7 +177,7 @@
<button class='action-group__action usa-button usa-button-big'>
{% if is_new_member %}Create{% else %}Save{% endif %}
</button>
<a href='{{ url_for("workspaces.workspace_members", workspace_id=workspace.id) }}' class='action-group__action icon-link'>
<a href='{{ url_for("portfolios.portfolio_members", portfolio_id=portfolio.id) }}' class='action-group__action icon-link'>
{{ Icon('x') }}
<span>Cancel</span>
</a>

View File

@@ -1,11 +1,11 @@
{% extends "workspaces/base.html" %}
{% extends "portfolios/base.html" %}
{% from "components/empty_state.html" import EmptyState %}
{% from "components/icon.html" import Icon %}
{% block workspace_content %}
{% block portfolio_content %}
{% if not workspace.members %}
{% if not portfolio.members %}
{% set user_can_invite = user_can(permissions.ASSIGN_AND_UNASSIGN_ATAT_ROLE) %}

View File

@@ -7,7 +7,7 @@
{% block content %}
<form method="POST" action="{{ url_for('workspaces.create_member', workspace_id=workspace.id) }}" autocomplete="false">
<form method="POST" action="{{ url_for('portfolios.create_member', portfolio_id=portfolio.id) }}" autocomplete="false">
{{ form.csrf_token }}
<div class="panel">
@@ -22,14 +22,14 @@
{{ TextInput(form.last_name) }}
{{ TextInput(form.email,placeholder='jane@mail.mil', validation='email') }}
{{ TextInput(form.dod_id,placeholder='10-digit number on the back of the CAC', validation='dodId') }}
{{ Selector(form.workspace_role) }}
{{ Selector(form.portfolio_role) }}
</div>
</div>
<div class='action-group'>
<button class="usa-button usa-button-big usa-button-primary" tabindex="0">Add User</button>
<a href='{{ url_for("workspaces.workspace_members", workspace_id=workspace.id) }}' class='action-group__action icon-link'>
<a href='{{ url_for("portfolios.portfolio_members", portfolio_id=portfolio.id) }}' class='action-group__action icon-link'>
{{ Icon('x') }}
<span>Cancel</span>
</a>

View File

@@ -1,12 +1,12 @@
{% extends "workspaces/base.html" %}
{% extends "portfolios/base.html" %}
{% from "components/alert.html" import Alert %}
{% from "components/icon.html" import Icon %}
{% from "components/empty_state.html" import EmptyState %}
{% block workspace_content %}
{% block portfolio_content %}
{{ Alert("Budget Report for Portfolio " + workspace.name,
{{ Alert("Budget Report for Portfolio " + portfolio.name,
message="<p>Track your monthly and cumulative expenditures for your portfolio, applications, and environments below.</p>\
<p>Please note that the projected spend is based on the <em>average expense over the last three completed months</em> and therefore does not account for future changes that might be made in scale or configuration of your cloud services.</p>",
actions=[
@@ -20,8 +20,8 @@
<div class='row'>
<h2 class='spend-summary__heading col'>Portfolio Total Spend</h2>
<dl class='spend-summary__budget'>
{% set budget = workspace_totals['budget'] %}
{% set spent = workspace_totals['spent'] %}
{% set budget = portfolio_totals['budget'] %}
{% set spent = portfolio_totals['spent'] %}
{% set remaining = budget - spent %}
<div>
<dt>Budget </dt>
@@ -88,7 +88,7 @@
</div>
</dl>
<a href='{{ url_for("workspaces.workspace", workspace_id=workspace.id) }}' class='icon-link'>
<a href='{{ url_for("portfolios.portfolio", portfolio_id=portfolio.id) }}' class='icon-link'>
Manage Task Order
</a>
</div>
@@ -107,13 +107,13 @@
</div>
{% set workspace_totals = monthly_totals['workspace'] %}
{% set portfolio_totals = monthly_totals['portfolio'] %}
{% set current_month_index = current_month.strftime('%m/%Y') %}
{% set prev_month_index = prev_month.strftime('%m/%Y') %}
{% set two_months_ago_index = two_months_ago.strftime('%m/%Y') %}
{% set reports_url = url_for("workspaces.workspace_reports", workspace_id=workspace.id) %}
{% set reports_url = url_for("portfolios.portfolio_reports", portfolio_id=portfolio.id) %}
{% if not workspace.applications %}
{% if not portfolio.applications %}
{% set can_create_applications = user_can(permissions.ADD_APPLICATION_IN_WORKSPACE) %}
{% set message = 'This portfolio has no cloud environments set up, so there is no spending data to report. Create an application with some cloud environments to get started.'
@@ -124,7 +124,7 @@
{{ EmptyState(
'Nothing to report',
action_label='Add a New Application' if can_create_applications else None,
action_href=url_for('workspaces.new_application', workspace_id=workspace.id) if can_create_applications else None,
action_href=url_for('portfolios.new_application', portfolio_id=portfolio.id) if can_create_applications else None,
icon='chart',
sub_message=message
) }}
@@ -338,8 +338,8 @@
{% if month.month == current_month.month and month.year == current_month.year %}
selected='selected'
{% endif %}
value='{{ url_for("workspaces.workspace_reports",
workspace_id=workspace.id,
value='{{ url_for("portfolios.portfolio_reports",
portfolio_id=portfolio.id,
month=month.month,
year=month.year) }}'
>
@@ -354,7 +354,7 @@
<spend-table
v-bind:applications='{{ monthly_totals['applications'] | tojson }}'
v-bind:workspace='{{ workspace_totals | tojson }}'
v-bind:portfolio='{{ portfolio_totals | tojson }}'
v-bind:environments='{{ monthly_totals['environments'] | tojson }}'
current-month-index='{{ current_month_index }}'
prev-month-index='{{ prev_month_index }}'
@@ -369,14 +369,14 @@
<th class='current-month'>% of total spend this month</th>
</thead>
<tbody class='spend-table__workspace'>
<tbody class='spend-table__portfolio'>
<tr>
<th scope='row'>Total</th>
<td class='table-cell--align-right previous-month'>{{ workspace_totals.get(two_months_ago_index, 0) | dollars }}</td>
<td class='table-cell--align-right previous-month'>{{ workspace_totals.get(prev_month_index, 0) | dollars }}</td>
<td class='table-cell--align-right current-month'>{{ workspace_totals.get(current_month_index, 0) | dollars }}</td>
<td class='table-cell--align-right previous-month'>{{ portfolio_totals.get(two_months_ago_index, 0) | dollars }}</td>
<td class='table-cell--align-right previous-month'>{{ portfolio_totals.get(prev_month_index, 0) | dollars }}</td>
<td class='table-cell--align-right current-month'>{{ portfolio_totals.get(current_month_index, 0) | dollars }}</td>
<td class='table-cell--expand current-month meter-cell'>
<meter value='{{ workspace_totals.get(current_month_index, 0) }}' min='0' max='{{ workspace_totals.get(current_month_index, 0) }}'>
<meter value='{{ portfolio_totals.get(current_month_index, 0) }}' min='0' max='{{ portfolio_totals.get(current_month_index, 0) }}'>
<div class='meter__fallback' style='width: 100%'></div>
</meter>
</td>
@@ -406,10 +406,10 @@
<td class='table-cell--expand current-month meter-cell'>
<span class='spend-table__meter-value'>
<span v-html='round( 100 * ((application[currentMonthIndex] || 0) / (workspace[currentMonthIndex] || 1) )) + "%"'></span>
<span v-html='round( 100 * ((application[currentMonthIndex] || 0) / (portfolio[currentMonthIndex] || 1) )) + "%"'></span>
</span>
<meter v-bind:value='application[currentMonthIndex] || 0' min='0' v-bind:max='workspace[currentMonthIndex] || 1'>
<div class='meter__fallback' v-bind:style='"width:" + round( 100 * ((application[currentMonthIndex] || 0) / (workspace[currentMonthIndex] || 1) )) + "%;"'></div>
<meter v-bind:value='application[currentMonthIndex] || 0' min='0' v-bind:max='portfolio[currentMonthIndex] || 1'>
<div class='meter__fallback' v-bind:style='"width:" + round( 100 * ((application[currentMonthIndex] || 0) / (portfolio[currentMonthIndex] || 1) )) + "%;"'></div>
</meter>
</td>
</tr>

View File

@@ -1,24 +1,24 @@
{% from "components/empty_state.html" import EmptyState %}
{% extends "workspaces/base.html" %}
{% extends "portfolios/base.html" %}
{% block workspace_content %}
{% block portfolio_content %}
{% if not workspace.task_orders %}
{% if not portfolio.task_orders %}
{{ EmptyState(
'This portfolio doesnt have any task orders yet.',
action_label='Add a New Task Order',
action_href=url_for('task_orders.new', screen=1, workspace_id=workspace.id),
action_href=url_for('task_orders.new', screen=1, portfolio_id=portfolio.id),
icon='cloud',
) }}
{% else %}
<ul>
{% for task_order in workspace.task_orders %}
{% for task_order in portfolio.task_orders %}
<li class='block-list__item'>
<a href='{{ url_for("workspaces.view_task_order", workspace_id=workspace.id, task_order_id=task_order.id)}}'>
<a href='{{ url_for("portfolios.view_task_order", portfolio_id=portfolio.id, task_order_id=task_order.id)}}'>
<span>{{ task_order.start_date }} - {{ task_order.end_date }}</span>
</a>
</li>

View File

@@ -0,0 +1,7 @@
{% extends "portfolios/base.html" %}
{% block portfolio_content %}
You're looking at TO {{ task_order.id }}
{% endblock %}

View File

@@ -50,9 +50,9 @@
{% if not requests %}
{{ EmptyState(
("requests.index.no_workspaces_label" | translate),
sub_message=("requests.index.no_workspaces_sub_message" | translate),
action_label=("requests.index.no_workspaces_action_label" | translate),
("requests.index.no_portfolios_label" | translate),
sub_message=("requests.index.no_portfolios_sub_message" | translate),
action_label=("requests.index.no_portfolios_action_label" | translate),
action_href=url_for('requests.requests_form_new', screen=1),
icon='document'
) }}
@@ -146,7 +146,7 @@
{% endif %}
<td>!{ dollars(r.annual_usage) }</td>
<td>
<a v-if="r.is_approved" class="icon-link icon-link--large" :href="r.workspace_link">
<a v-if="r.is_approved" class="icon-link icon-link--large" :href="r.portfolio_link">
!{ r.status }
</a>
<span v-else>

View File

@@ -135,7 +135,7 @@
)
}}
{{ DateInput(f.start_date, placeholder='MM / DD / YYYY', validation='date') }}
{{ TextInput(f.name, placeholder='Request Name', validation='workspaceName') }}
{{ TextInput(f.name, placeholder='Request Name', validation='portfolioName') }}
</div>
</details-of-use>

View File

@@ -1,9 +0,0 @@
{% extends "workspaces/base.html" %}
{% from "components/pagination.html" import Pagination %}
{% block workspace_content %}
<div v-cloak>
{% include "fragments/audit_events_log.html" %}
{{ Pagination(audit_events, 'workspaces.workspace_activity', workspace_id=workspace_id) }}
</div>
{% endblock %}

View File

@@ -1,15 +0,0 @@
{% extends "base.html" %}
{% block content %}
<div class='workspace-panel-container'>
<div class='col'>
{% include 'navigation/workspace_navigation.html' %}
</div>
<div class='col col--grow'>
{% block workspace_content %}{% endblock %}
</div>
</div>
{% endblock %}