Merge pull request #611 from dod-ccpo/reskin-portfolio-nav

Reskin portfolio navigation
This commit is contained in:
patricksmithdds 2019-02-07 11:04:39 -05:00 committed by GitHub
commit f19191c6d2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 188 additions and 93 deletions

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 544 512"><path d="M527.79 288H290.5l158.03 158.03c6.04 6.04 15.98 6.53 22.19.68 38.7-36.46 65.32-85.61 73.13-140.86 1.34-9.46-6.51-17.85-16.06-17.85zm-15.83-64.8C503.72 103.74 408.26 8.28 288.8.04 279.68-.59 272 7.1 272 16.24V240h223.77c9.14 0 16.82-7.68 16.19-16.8zM224 288V50.71c0-9.55-8.39-17.4-17.84-16.06C86.99 51.49-4.1 155.6.14 280.37 4.5 408.51 114.83 513.59 243.03 511.98c50.4-.63 96.97-16.87 135.26-44.03 7.9-5.6 8.42-17.23 1.57-24.08L224 288z"/></svg>

After

Width:  |  Height:  |  Size: 515 B

1
static/icons/cog.svg Normal file
View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path d="M487.4 315.7l-42.6-24.6c4.3-23.2 4.3-47 0-70.2l42.6-24.6c4.9-2.8 7.1-8.6 5.5-14-11.1-35.6-30-67.8-54.7-94.6-3.8-4.1-10-5.1-14.8-2.3L380.8 110c-17.9-15.4-38.5-27.3-60.8-35.1V25.8c0-5.6-3.9-10.5-9.4-11.7-36.7-8.2-74.3-7.8-109.2 0-5.5 1.2-9.4 6.1-9.4 11.7V75c-22.2 7.9-42.8 19.8-60.8 35.1L88.7 85.5c-4.9-2.8-11-1.9-14.8 2.3-24.7 26.7-43.6 58.9-54.7 94.6-1.7 5.4.6 11.2 5.5 14L67.3 221c-4.3 23.2-4.3 47 0 70.2l-42.6 24.6c-4.9 2.8-7.1 8.6-5.5 14 11.1 35.6 30 67.8 54.7 94.6 3.8 4.1 10 5.1 14.8 2.3l42.6-24.6c17.9 15.4 38.5 27.3 60.8 35.1v49.2c0 5.6 3.9 10.5 9.4 11.7 36.7 8.2 74.3 7.8 109.2 0 5.5-1.2 9.4-6.1 9.4-11.7v-49.2c22.2-7.9 42.8-19.8 60.8-35.1l42.6 24.6c4.9 2.8 11 1.9 14.8-2.3 24.7-26.7 43.6-58.9 54.7-94.6 1.5-5.5-.7-11.3-5.6-14.1zM256 336c-44.1 0-80-35.9-80-80s35.9-80 80-80 80 35.9 80 80-35.9 80-80 80z"/></svg>

After

Width:  |  Height:  |  Size: 890 B

1
static/icons/home.svg Normal file
View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 576 512"><path d="M280.37 148.26L96 300.11V464a16 16 0 0 0 16 16l112.06-.29a16 16 0 0 0 15.92-16V368a16 16 0 0 1 16-16h64a16 16 0 0 1 16 16v95.64a16 16 0 0 0 16 16.05L464 480a16 16 0 0 0 16-16V300L295.67 148.26a12.19 12.19 0 0 0-15.3 0zM571.6 251.47L488 182.56V44.05a12 12 0 0 0-12-12h-56a12 12 0 0 0-12 12v72.61L318.47 43a48 48 0 0 0-61 0L4.34 251.47a12 12 0 0 0-1.6 16.9l25.5 31A12 12 0 0 0 45.15 301l235.22-193.74a12.19 12.19 0 0 1 15.3 0L530.9 301a12 12 0 0 0 16.9-1.6l25.5-31a12 12 0 0 0-1.7-16.93z"/></svg>

After

Width:  |  Height:  |  Size: 565 B

View File

@ -1,5 +1,5 @@
#app-root { #app-root {
background-color: $color-gray-lightest; background-color: $color-white;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
justify-content: flex-start; justify-content: flex-start;

View File

@ -2,34 +2,93 @@
@include media($large-screen) { @include media($large-screen) {
@include grid-row; @include grid-row;
} }
.line {
box-sizing: border-box;
height: 2px;
width: 100%;
border: 1px solid $color-gray-lightest;
}
} }
.portfolio-navigation { .portfolio-breadcrumbs {
@include panel-margin; margin-bottom: $gap * 2;
margin-bottom: $gap * 4; color: $color-gray-medium;
font-size: $h5-font-size;
ul { .icon-link {
display: flex; color: $color-gray-medium;
flex-direction: column; font-weight: normal;
li { }
flex-grow: 1;
.icon--tiny {
padding: $gap 0;
}
.icon {
@include icon-color($color-gray-medium);
}
.portfolio-breadcrumbs__crumb {
.icon {
@include icon-color($color-blue);
}
.icon-link {
color: $color-blue;
pointer-events: none;
}
}
}
.portfolio-header {
margin: 2 * $gap 0;
.portfolio-header__name {
@include h1;
}
.portfolio-header__budget {
font-size: $small-font-size;
align-items: center;
button {
margin: 0;
padding: 0;
}
.portfolio-header__budget--dollars {
font-size: $h2-font-size;
font-weight: bold;
} }
} }
@include media($medium-screen) { .links {
margin-bottom: $gap * 5; font-size: $small-font-size;
}
@include media($large-screen) { .icon-link {
width: 20rem; &.active {
margin-right: $gap * 2; color: $color-gray;
.icon {
@include icon-color($color-gray);
}
}
ul { .icon-link--icon {
display: block; text-align: center;
}
.icon {
@include icon-size(20);
}
} }
} }
} }
.portfolio-content {
margin-top: 6 * $gap;
}
.portfolio-funding { .portfolio-funding {
.portfolio-funding__header { .portfolio-funding__header {
padding: 0; padding: 0;

View File

@ -62,7 +62,7 @@ $color-black-light: #212121;
$color-gray-dark: #323a45; $color-gray-dark: #323a45;
$color-gray: #5b616b; $color-gray: #5b616b;
$color-gray-medium: #757575; $color-gray-medium: #9b9b9b;
$color-gray-light: #aeb0b5; $color-gray-light: #aeb0b5;
$color-gray-lighter: #d6d7d9; $color-gray-lighter: #d6d7d9;
$color-gray-lightest: #f1f1f1; $color-gray-lightest: #f1f1f1;

View File

@ -1,68 +0,0 @@
{% 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_PORTFOLIO) 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_PORTFOLIO_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.portfolio_funding" | translate),
href=url_for("portfolios.portfolio_funding", portfolio_id=portfolio.id),
active=request.url_rule.rule.startswith('/portfolios/<portfolio_id>/task_order'),
subnav=None
) }}
{% if user_can(permissions.EDIT_PORTFOLIO_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_PORTFOLIO_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

@ -1,6 +1,8 @@
{% extends "portfolios/base.html" %} {% extends "portfolios/base.html" %}
{% from "components/pagination.html" import Pagination %} {% from "components/pagination.html" import Pagination %}
{% set secondary_breadcrumb = "navigation.portfolio_navigation.breadcrumbs.admin" | translate %}
{% block portfolio_content %} {% block portfolio_content %}
<div v-cloak> <div v-cloak>
{% include "fragments/audit_events_log.html" %} {% include "fragments/audit_events_log.html" %}

View File

@ -3,7 +3,6 @@
{% extends "portfolios/base.html" %} {% extends "portfolios/base.html" %}
{% block portfolio_content %} {% block portfolio_content %}
{% if not portfolio.applications %} {% if not portfolio.applications %}

View File

@ -3,12 +3,18 @@
{% block content %} {% block content %}
<div class='portfolio-panel-container'> <div class='portfolio-panel-container'>
<div class='col'>
{% include 'navigation/portfolio_navigation.html' %}
</div>
<div class='col col--grow'> <div class='col col--grow'>
{% block portfolio_content %}{% endblock %} {% block portfolio_breadcrumbs %}
{% include "portfolios/breadcrumbs.html" %}
{% endblock %}
<div class='line'></div>
{% block portfolio_header %}
{% include "portfolios/header.html" %}
{% endblock %}
<div class='line'></div>
<div class='portfolio-content'>
{% block portfolio_content %}{% endblock %}
</div>
</div> </div>
</div> </div>

View File

@ -0,0 +1,19 @@
{% from "components/icon.html" import Icon %}
<div class="row portfolio-breadcrumbs">
<a class="icon-link portfolio-breadcrumbs__home" href="{{ url_for("portfolios.portfolio_applications", portfolio_id=portfolio.id) }}">
{{ Icon("home") }}
<span>
{{ portfolio.name }} Portfolio
</span>
</a>
<div class="portfolio-breadcrumbs__crumb">
{% if secondary_breadcrumb %}
{{ Icon("caret_right", classes="icon--tiny") }}
<div class="icon-link">
{{ secondary_breadcrumb }}
</div>
{% endif %}
</div>
</div
>

View File

@ -3,6 +3,8 @@
{% 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 %}
{% set secondary_breadcrumb = "navigation.portfolio_navigation.breadcrumbs.admin" | translate %}
{% block portfolio_content %} {% block portfolio_content %}
{% include "fragments/flash.html" %} {% include "fragments/flash.html" %}

View File

@ -0,0 +1,51 @@
{% from "components/icon.html" import Icon %}
{% macro Link(icon, text, url, active=False) %}
<a class='icon-link {{ "active icon-link--disabled" if active }}' href='{{ url }}'>
<div class='col'>
<div class='icon-link--icon'>{{ Icon(icon) }}</div>
<div class='icon-link--name'>{{ text }}</div>
</div>
</a>
{% endmacro %}
<div class='portfolio-header row'>
<div class='col col--grow'>
<div class='portfolio-header__name'>
{{ portfolio.name }}
</div>
<div class='portfolio-header__budget row'>
<span>Available budget</span>
<button type="button" tabindex="0" class="icon-tooltip" v-tooltip.right="{content: 'The available budget shown includes the available budget of all active task orders', container: false}">
{{ Icon('info') }}
</button>
<span class='portfolio-header__budget--dollars'>
{{ portfolio.task_orders | sum(attribute='budget') | dollars }}
</span>
</div>
</div>
<div class='row links'>
{% if user_can(permissions.VIEW_USAGE_DOLLARS) %}
{{ Link(
icon='chart-pie',
text='navigation.portfolio_navigation.breadcrumbs.reports' | translate,
url=url_for("portfolios.portfolio_reports", portfolio_id=portfolio.id),
active=request.url_rule.endpoint == "portfolios.portfolio_reports",
) }}
{% endif %}
{{ Link(
icon='dollar-sign',
text='navigation.portfolio_navigation.breadcrumbs.funding' | translate,
url=url_for("portfolios.portfolio_funding", portfolio_id=portfolio.id),
active=request.url_rule.endpoint == "portfolios.portfolio_funding",
) }}
{% if user_can(permissions.EDIT_PORTFOLIO_INFORMATION) %}
{{ Link(
icon='cog',
text='navigation.portfolio_navigation.breadcrumbs.admin' | translate,
url=url_for("portfolios.portfolio", portfolio_id=portfolio.id),
active=request.url_rule.endpoint == "portfolios.portfolio",
) }}
{% endif %}
</div>
</div>

View File

@ -4,6 +4,8 @@
{% from "components/icon.html" import Icon %} {% from "components/icon.html" import Icon %}
{% from "components/empty_state.html" import EmptyState %} {% from "components/empty_state.html" import EmptyState %}
{% set secondary_breadcrumb = "navigation.portfolio_navigation.breadcrumbs.reports" | translate %}
{% block portfolio_content %} {% block portfolio_content %}
{{ Alert("Budget Report for Portfolio " + portfolio.name, {{ Alert("Budget Report for Portfolio " + portfolio.name,

View File

@ -3,6 +3,8 @@
{% extends "portfolios/base.html" %} {% extends "portfolios/base.html" %}
{% set secondary_breadcrumb = "navigation.portfolio_navigation.breadcrumbs.funding" | translate %}
{% block portfolio_content %} {% block portfolio_content %}
{% macro ViewLink(task_order) %} {% macro ViewLink(task_order) %}

View File

@ -1,5 +1,7 @@
{% extends "portfolios/base.html" %} {% extends "portfolios/base.html" %}
{% set secondary_breadcrumb = "navigation.portfolio_navigation.breadcrumbs.funding" | translate %}
{% from "components/checkbox_input.html" import CheckboxInput %} {% from "components/checkbox_input.html" import CheckboxInput %}
{% 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 %}

View File

@ -1,5 +1,7 @@
{% extends "base.html" %} {% extends "base.html" %}
{% set secondary_breadcrumb = "navigation.portfolio_navigation.breadcrumbs.funding" | translate %}
{% from "components/edit_link.html" import EditLink %} {% from "components/edit_link.html" import EditLink %}
{% from "components/required_label.html" import RequiredLabel %} {% from "components/required_label.html" import RequiredLabel %}
{% from "components/icon.html" import Icon %} {% from "components/icon.html" import Icon %}

View File

@ -1,5 +1,7 @@
{% extends "portfolios/base.html" %} {% extends "portfolios/base.html" %}
{% set secondary_breadcrumb = "navigation.portfolio_navigation.breadcrumbs.funding" | translate %}
{% from "components/icon.html" import Icon %} {% from "components/icon.html" import Icon %}
{% block portfolio_content %} {% block portfolio_content %}

View File

@ -1,3 +1,4 @@
import pytest
from flask import url_for from flask import url_for
from tests.factories import ( from tests.factories import (
@ -20,7 +21,7 @@ def test_user_with_permission_has_budget_report_link(client, user_session):
user_session(portfolio.owner) user_session(portfolio.owner)
response = client.get("/portfolios/{}/applications".format(portfolio.id)) response = client.get("/portfolios/{}/applications".format(portfolio.id))
assert ( assert (
'href="/portfolios/{}/reports"'.format(portfolio.id).encode() in response.data "href='/portfolios/{}/reports'".format(portfolio.id).encode() in response.data
) )
@ -38,6 +39,7 @@ def test_user_without_permission_has_no_budget_report_link(client, user_session)
) )
@pytest.mark.skip(reason="Temporarily no add activity log link")
def test_user_with_permission_has_activity_log_link(client, user_session): def test_user_with_permission_has_activity_log_link(client, user_session):
portfolio = PortfolioFactory.create() portfolio = PortfolioFactory.create()
ccpo = UserFactory.from_atat_role("ccpo") ccpo = UserFactory.from_atat_role("ccpo")
@ -69,6 +71,7 @@ def test_user_with_permission_has_activity_log_link(client, user_session):
) )
@pytest.mark.skip(reason="Temporarily no add activity log link")
def test_user_without_permission_has_no_activity_log_link(client, user_session): def test_user_without_permission_has_no_activity_log_link(client, user_session):
portfolio = PortfolioFactory.create() portfolio = PortfolioFactory.create()
developer = UserFactory.create() developer = UserFactory.create()
@ -87,6 +90,7 @@ def test_user_without_permission_has_no_activity_log_link(client, user_session):
) )
@pytest.mark.skip(reason="Temporarily no add application link")
def test_user_with_permission_has_add_application_link(client, user_session): def test_user_with_permission_has_add_application_link(client, user_session):
portfolio = PortfolioFactory.create() portfolio = PortfolioFactory.create()
user_session(portfolio.owner) user_session(portfolio.owner)
@ -97,6 +101,7 @@ def test_user_with_permission_has_add_application_link(client, user_session):
) )
@pytest.mark.skip(reason="Temporarily no add application link")
def test_user_without_permission_has_no_add_application_link(client, user_session): def test_user_without_permission_has_no_add_application_link(client, user_session):
user = UserFactory.create() user = UserFactory.create()
portfolio = PortfolioFactory.create() portfolio = PortfolioFactory.create()

View File

@ -1,3 +1,4 @@
import pytest
from flask import url_for from flask import url_for
from tests.factories import ( from tests.factories import (
@ -36,6 +37,7 @@ def create_portfolio_and_invite_user(
return portfolio return portfolio
@pytest.mark.skip(reason="Temporarily no add member link")
def test_user_with_permission_has_add_member_link(client, user_session): def test_user_with_permission_has_add_member_link(client, user_session):
portfolio = PortfolioFactory.create() portfolio = PortfolioFactory.create()
user_session(portfolio.owner) user_session(portfolio.owner)
@ -46,6 +48,7 @@ def test_user_with_permission_has_add_member_link(client, user_session):
) )
@pytest.mark.skip(reason="Temporarily no add member link")
def test_user_without_permission_has_no_add_member_link(client, user_session): def test_user_without_permission_has_no_add_member_link(client, user_session):
user = UserFactory.create() user = UserFactory.create()
portfolio = PortfolioFactory.create() portfolio = PortfolioFactory.create()

View File

@ -305,6 +305,10 @@ navigation:
applications: Applications applications: Applications
portfolio_funding: Funding portfolio_funding: Funding
portfolio_settings: Portfolio Settings portfolio_settings: Portfolio Settings
breadcrumbs:
admin: Admin
funding: Funding
reports: Reports
requests: requests:
_new: _new:
new_request: New Request new_request: New Request