Merge pull request #617 from dod-ccpo/reskin-portfolio-reports

Reskin portfolio reports
This commit is contained in:
patricksmithdds 2019-02-11 12:59:22 -05:00 committed by GitHub
commit a7733925ca
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 202 additions and 138 deletions

View File

@ -62,9 +62,11 @@ def portfolio_reports(portfolio_id):
prev_month = current_month - timedelta(days=28)
two_months_ago = prev_month - timedelta(days=28)
expiration_date = (
portfolio.legacy_task_order and portfolio.legacy_task_order.expiration_date
task_order = next(
(task_order for task_order in portfolio.task_orders if task_order.is_active),
None,
)
expiration_date = task_order and task_order.end_date
if expiration_date:
remaining_difference = expiration_date - today
remaining_days = remaining_difference.days
@ -76,8 +78,7 @@ def portfolio_reports(portfolio_id):
cumulative_budget=Reports.cumulative_budget(portfolio),
portfolio_totals=Reports.portfolio_totals(portfolio),
monthly_totals=Reports.monthly_totals(portfolio),
jedi_request=portfolio.request,
legacy_task_order=portfolio.legacy_task_order,
task_order=task_order,
current_month=current_month,
prev_month=prev_month,
two_months_ago=two_months_ago,

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path d="M464 64H48C21.49 64 0 85.49 0 112v288c0 26.51 21.49 48 48 48h416c26.51 0 48-21.49 48-48V112c0-26.51-21.49-48-48-48zm0 48v40.805c-22.422 18.259-58.168 46.651-134.587 106.49-16.841 13.247-50.201 45.072-73.413 44.701-23.208.375-56.579-31.459-73.413-44.701C106.18 199.465 70.425 171.067 48 152.805V112h416zM48 400V214.398c22.914 18.251 55.409 43.862 104.938 82.646 21.857 17.205 60.134 55.186 103.062 54.955 42.717.231 80.509-37.199 103.053-54.947 49.528-38.783 82.032-64.401 104.947-82.653V400H48z"/></svg>

After

Width:  |  Height:  |  Size: 574 B

View File

@ -95,11 +95,7 @@
margin: 6 * $gap $gap 0 $gap;
}
.portfolio-applications {
.portfolio-applications__header {
margin-bottom: 4 * $gap;
.portfolio-applications__header--title {
@mixin subheading {
color: $color-gray-dark;
padding: $gap 0;
text-transform: uppercase;
@ -108,6 +104,14 @@
font-weight: bold;
}
.portfolio-applications {
.portfolio-applications__header {
margin-bottom: 4 * $gap;
.portfolio-applications__header--title {
@include subheading;
}
.portfolio-applications__header--actions {
color: $color-blue;
font-size: $small-font-size;
@ -287,3 +291,19 @@
}
}
}
.portfolio-reports {
.portfolio-reports__header {
margin-bottom: 4 * $gap;
.portfolio-reports__header--title {
@include subheading;
}
}
.panel {
box-shadow: 0 6px 18px 0 rgba(144,164,183,0.3);
border-top: none;
border-bottom: none;
}
}

View File

@ -7,6 +7,11 @@
.funding-summary-row__col {
hr {
margin: 2 * $gap 0;
border-bottom: 1px solid $color-gray-lightest;
}
@include media($medium-screen) {
@include grid-pad;
flex-grow: 1;
@ -36,6 +41,11 @@
max-width: 100%;
}
.subheading {
@include h4;
margin: 0 $gap 2 * $gap 0;
-ms-flex-negative: 1;
}
// Spending Summary
// ===============================
@ -53,40 +63,28 @@
}
}
.spend-summary__heading {
@include h3;
margin: 0 $gap 0 0;
-ms-flex-negative: 1;
}
.spend-summary__budget {
margin: 0 0 0 $gap;
@include ie-only {
margin: $gap 0 0 0;
}
}
> div {
text-align: right;
dl {
text-align: left;
margin: 0 0 ($gap / 2) 0;
@include ie-only {
text-align: left;
}
dd, dt {
display: inline;
}
dt {
color: $color-gray;
text-transform: uppercase;
color: $color-gray-light;
margin-right: $gap;
font-weight: normal;
}
dd {
font-weight: bold;
}
font-size: $small-font-size;
}
}
@ -97,32 +95,33 @@
}
.spend-summary__spent {
margin: $gap 0 0 0;
margin: 2 * $gap 0;
display: flex;
flex-direction: row-reverse;
flex-direction: column;
justify-content: flex-end;
dd, dt {
@include h5;
}
dt {
font-weight: normal;
margin-left: $gap;
letter-spacing: 0.47px;
}
}
}
// Task Order Summary
// ===============================
&.to-summary {
.to-summary__row {
.icon-link {
font-weight: $font-normal
}
.subheading {
margin-bottom: 0;
}
.to-summary__heading {
@include h3;
margin: 0;
@include h4;
margin: 0 $gap 0 0;
}
.to-summary__to-number {
@ -134,7 +133,6 @@
margin-right: $gap;
}
}
}
@include media($xlarge-screen) {
display: flex;
@ -163,23 +161,27 @@
.to-summary__expiration {
dl {
margin: ($gap * 2) 0 0 0;
> div {
margin: 0 0 ($gap / 2) 0;
text-align: right;
dd, dt {
display: block;
display: inline;
}
dt {
color: $color-gray;
margin-right: $gap;
font-weight: normal;
font-size: $small-font-size;
text-transform: uppercase;
font-weight: $font-bold;
color: $color-gray-light;
}
dd {
font-weight: bold;
dd.ending-soon {
color: $color-red-dark;
font-size: $h2-font-size;
white-space: nowrap;
.icon {
@include icon-size(28);
@include icon-color($color-red-dark);
}
}
}
@ -203,9 +205,12 @@
.spend-table {
box-shadow: 0 6px 18px 0 rgba(144,164,183,0.3);
.spend-table__header {
@include panel-base;
@include panel-theme-default;
border-top: none;
border-bottom: 0;
display: flex;
flex-direction: row;
@ -215,8 +220,8 @@
padding: $gap * 2;
.spend-table__title {
@include h3;
margin: 0;
@include h4;
font-size: $lead-font-size;
flex: 2;
}
@ -227,6 +232,12 @@
}
table {
thead th {
text-transform: uppercase;
border-bottom: 1px solid $color-gray-lightest;
border-top: none;
}
th, td {
white-space: nowrap;
@ -234,10 +245,6 @@
margin: 0;
}
&.current-month {
background-color: $color-aqua-lightest;
}
&.previous-month {
color: $color-gray;
}
@ -286,28 +293,53 @@
.spend-table__portfolio {
th, td {
font-weight: bold;
border-bottom: 1px solid $color-gray-lightest;
}
}
.spend-table__application {
.spend-table__application__toggler {
@include icon-link-color($color-black-light, $color-gray-lightest);
@include icon-link-color($color-blue, $color-gray-lightest);
margin-left: -$gap;
color: $color-blue;
.icon {
@include icon-size(12);
margin-right: $gap;
}
.open-indicator {
position: absolute;
bottom: 0;
left: 5 * $gap;
width: 0;
height: 0;
border-left: 10px solid transparent;
border-right: 10px solid transparent;
border-bottom: 10px solid $color-blue-light;
}
}
th, td {
border-bottom: none;
}
th[scope=rowgroup] {
position: relative;
}
.spend-table__application__env {
margin-left: $gap;
margin-left: 2 * $gap;
&:last-child {
td, th {
padding-bottom: $gap * 5;
box-shadow: inset 0 (-$gap * 2.5) 0 $color-gray-lightest;
}
th, td {
.icon-link {
font-weight: $font-normal;
font-size: $base-font-size;
}
border-bottom: 1px dashed $color-white;
background-color: $color-blue-light;
}
}
}

View File

@ -12,7 +12,7 @@
<div class='portfolio-header row'>
<div class='col col--grow'>
<div class='portfolio-header__name'>
{{ portfolio.name }}
{{ secondary_breadcrumb or portfolio.name }}
</div>
<div class='portfolio-header__budget row'>
<span>Available budget</span>

View File

@ -1,6 +1,5 @@
{% extends "portfolios/base.html" %}
{% from "components/alert.html" import Alert %}
{% from "components/icon.html" import Icon %}
{% from "components/empty_state.html" import EmptyState %}
@ -8,42 +7,38 @@
{% block portfolio_content %}
{{ 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=[
{"label": "Learn More", "href": url_for('atst.helpdocs'), "icon": "info"}
] ) }}
<div class='portfolio-reports'>
<div v-cloak class='funding-summary-row'>
<div class='funding-summary-row__col'>
<div class='panel spend-summary'>
<h4 class='spend-summary__heading subheading'>Portfolio Total Spend</h4>
<div class='row'>
<h2 class='spend-summary__heading col'>Portfolio Total Spend</h2>
<dl class='spend-summary__budget'>
<dl class='spend-summary__budget col col--grow row'>
{% set budget = portfolio_totals['budget'] %}
{% set spent = portfolio_totals['spent'] %}
{% set remaining = budget - spent %}
<div>
<dl class='col col--grow'>
<dt>Budget</dt>
<dd>{{ budget | dollars }}</dd>
</div>
</dl>
<div>
<dl class='col col--grow'>
<dt>Remaining</dt>
<dd>{{ remaining | dollars }}</dd>
</div>
</dl>
</dl>
</div>
<hr></hr>
<div>
<meter value='{{ spent }}' min='0' max='{{ budget }}' title='{{ spent | dollars }} Total spend to date'>
<div class='meter__fallback' style='width:{{ (spent / budget) * 100 if budget else 0 }}%;'></div>
</meter>
<dl class='spend-summary__spent'>
<dt>Total spend to date</dt>
<dt>Total spending to date</dt>
<dd>{{ spent | dollars }}</dd>
</dl>
</div>
@ -55,18 +50,19 @@
<div class='to-summary__row'>
<div class='to-summary__to'>
<h2 class='to-summary__heading'>Task Order</h2>
<h2 class='to-summary__heading subheading'>Current Task Order</h2>
<dl class='to-summary__to-number'>
<dt class='usa-sr-only'>Task Order Number</dt>
<dd>{{ legacy_task_order.number }}</dd>
<dd>{{ task_order.number }}</dd>
</dl>
</div>
<div class='to-summary__expiration'>
<dl>
<hr></hr>
<div class='to-summary__expiration row'>
<div class='col col--grow'>
<h4 class='subheading'>Expiration Date</h4>
<div>
<dt>Expires</dt>
<dd>
{% if expiration_date %}
<local-datetime
timestamp='{{ expiration_date }}'
@ -75,32 +71,47 @@
{% else %}
-
{% endif %}
</dd>
</div>
<div>
<dt>Remaining</dt>
<dd>
<a href='{{ url_for("portfolios.portfolio_funding", portfolio_id=portfolio.id) }}' class='icon-link'>
{{ Icon('cog') }}
Manage Task Order
</a>
</div>
<div class='col col--grow'>
<dl>
<dt>Remaining Days</dt>
<dd class='{{ 'ending-soon' if remaining_days is not none and remaining_days < 190 }}'>
{% if remaining_days is not none %}
{{ remaining_days }} days
{{ Icon('arrow-down') }}
<span>{{ remaining_days }}</span>
{% else %}
-
{% endif %}
</dd>
</div>
</dl>
</div>
</div>
</div>
<a href='{{ url_for("portfolios.portfolio", portfolio_id=portfolio.id) }}' class='icon-link'>
Manage Task Order
</a>
</div>
</div>
<hr></hr>
<dl class='to-summary__co'>
<dt>Contracting Officer</dt>
<dd>
{{ jedi_request.contracting_officer_full_name }}
<a class='icon-link' href='mailto:{{ jedi_request.contracting_officer_email }}'>{{ jedi_request.contracting_officer_email }}</a>
<dt class='subheading'>Contracting Officer</dt>
<dd class='row'>
<div class='col col--grow'>
{% if task_order.ko_first_name and task_order.ko_last_name %}
{{ task_order.ko_first_name }} {{ task_order.ko_last_name }}
{% endif %}
</div>
<div class='col'>
{% if task_order.ko_email %}
<a class='icon-link' href='mailto:{{ task_order.ko_email }}'>
{{ Icon('envelope') }}
{{ task_order.ko_email }}
</a>
{% endif %}
</div>
</dd>
</dl>
@ -142,7 +153,7 @@
<div class='budget-chart panel' ref='panel'>
<header class='budget-chart__header panel__heading panel__heading--tight'>
<h2 class='h3'>Cumulative Budget</h2>
<h4>Cumulative Budget</h4>
<div class='budget-chart__legend'>
<dl class='budget-chart__legend__spend'>
@ -331,7 +342,7 @@
<div class='spend-table responsive-table-wrapper'>
<div class='spend-table__header'>
<h2 class='spend-table__title'>Total spend per month </h2>
<h2 class='spend-table__title'>Total spent per month</h2>
<select name='month' id='month' onchange='location = this.value' class='spend-table__month-select'>
{% for m in cumulative_budget["months"] %}
@ -368,12 +379,12 @@
<th scope='col' class='table-cell--align-right previous-month'>{{ two_months_ago.strftime('%B %Y') }}</th>
<th scope='col' class='table-cell--align-right previous-month'>{{ prev_month.strftime('%B %Y') }}</th>
<th scope='col' class='table-cell--align-right current-month'>{{ current_month.strftime('%B %Y') }}</th>
<th class='current-month'>% of total spend this month</th>
<th class='current-month'></th>
</thead>
<tbody class='spend-table__portfolio'>
<tr>
<th scope='row'>Total</th>
<th scope='row'>Portfolio Total</th>
<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>
@ -389,7 +400,7 @@
<tr>
<th scope='rowgroup'>
<button v-on:click='toggle($event, name)' class='icon-link icon-link--large spend-table__application__toggler'>
<template v-if='application.isVisible'>{{ Icon('caret_down') }}</template>
<template v-if='application.isVisible'>{{ Icon('caret_down') }}<div class='open-indicator'></div></template>
<template v-else>{{ Icon('caret_right') }}</template>
<span v-html='name'></span>
</button>
@ -418,10 +429,9 @@
<tr v-for='(environment, envName) in environments[name]' v-show='application.isVisible' class='spend-table__application__env'>
<th scope='rowgroup'>
<a href='#' class='icon-link spend-table__application__env'>
{{ Icon('link') }}
<div class='icon-link spend-table__application__env'>
<span v-html='envName'></span>
</a>
</div>
</th>
<td class='table-cell--align-right previous-month'>
@ -442,7 +452,7 @@
</table>
</spend-table>
</div>
{% endif %}
</div>
{% endblock %}