Merge pull request #1130 from dod-ccpo/app-settings-styling_part-4

App settings styling - team table
This commit is contained in:
leigh-mil 2019-10-23 10:45:45 -04:00 committed by GitHub
commit 76ab44ca69
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
19 changed files with 92 additions and 467 deletions

View File

@ -2,7 +2,6 @@ import FormMixin from '../../mixins/form'
import textinput from '../text_input'
import optionsinput from '../options_input'
import checkboxinput from '../checkbox_input'
import Selector from '../selector'
import Modal from '../../mixins/modal'
import toggler from '../toggler'
@ -14,7 +13,6 @@ export default {
components: {
toggler,
Modal,
Selector,
textinput,
optionsinput,
checkboxinput,

View File

@ -1,117 +0,0 @@
import { VPopover } from 'v-tooltip'
const SelectorInput = {
name: 'SelectorInput',
props: {
name: String,
value: String,
label: String,
description: String,
selected: Boolean,
handleChange: Function,
handleEnter: Function,
handleEsc: Function,
},
computed: {
id: function() {
return `${this.name}_${this.value}`
},
},
methods: {
onChange: function(e) {
this.handleChange(this.value)
},
onEnter: function(e) {
this.handleEnter()
},
onEsc: function(e) {
this.handleEsc()
},
},
}
export default {
name: 'selector',
components: {
VPopover,
SelectorInput,
},
props: {
choices: Array,
defaultLabel: String,
initialErrors: Array,
initialChoice: {
type: String,
default: null,
},
},
data: function() {
return {
value: this.initialChoice || null,
currentChoice: this.initialChoice || null,
showError: (this.initialErrors && this.initialErrors.length) || false,
usingKeyboard: false,
}
},
computed: {
label: function() {
if (this.value) {
const selectedChoice = this.choices.find(choice => {
return this.value === choice[0]
})[1]
return selectedChoice.name
} else {
return this.defaultLabel
}
},
},
methods: {
change: function(value) {
this.value = value
this.showError = false
},
onShow: function() {
setTimeout(() => {
// timeout is a hack to make focus work in Chrome
const selected = this.$refs.choices.find(choice => choice.selected)
if (selected) {
selected.$refs.input[0].focus()
} else {
this.$refs.choices[0].$refs.input[0].focus()
}
}, 100)
},
enter: function() {
this.$refs.popover.hide()
},
esc: function() {
this.value = this.currentChoice
this.usingKeyboard = false
this.$refs.popover.hide()
},
handleEnterOption: function(e) {
this.change(e.target.value)
this.currentChoice = e.target.value
this.usingKeyboard = false
this.$refs.popover.hide()
},
handleButtonArrowDown: function(e) {
this.usingKeyboard = true
this.$refs.popover.show()
},
},
}

View File

@ -19,7 +19,6 @@ import ApplicationEnvironments from './components/forms/new_application/environm
import MultiStepModalForm from './components/forms/multi_step_modal_form'
import uploadinput from './components/upload_input'
import Modal from './mixins/modal'
import selector from './components/selector'
import BudgetChart from './components/charts/budget_chart'
import SpendTable from './components/tables/spend_table'
import LocalDatetime from './components/local_datetime'
@ -52,7 +51,6 @@ const app = new Vue({
poc,
ApplicationNameAndDescription,
ApplicationEnvironments,
selector,
BudgetChart,
SpendTable,
LocalDatetime,

View File

@ -1 +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>
<svg aria-hidden="true" focusable="false" data-prefix="fas" data-icon="envelope" class="svg-inline--fa fa-envelope fa-w-16" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="currentColor" d="M502.3 190.8c3.9-3.1 9.7-.2 9.7 4.7V400c0 26.5-21.5 48-48 48H48c-26.5 0-48-21.5-48-48V195.6c0-5 5.7-7.8 9.7-4.7 22.4 17.4 52.1 39.5 154.1 113.6 21.1 15.4 56.7 47.8 92.2 47.6 35.7.3 72-32.8 92.3-47.6 102-74.1 131.6-96.3 154-113.7zM256 320c23.2.4 56.6-29.2 73.4-41.4 132.7-96.3 142.8-104.7 173.4-128.7 5.8-4.5 9.2-11.5 9.2-18.9v-19c0-26.5-21.5-48-48-48H48C21.5 64 0 85.5 0 112v19c0 7.4 3.4 14.3 9.2 18.9 30.6 23.9 40.7 32.4 173.4 128.7 16.8 12.2 50.2 41.8 73.4 41.4z"></path></svg>

Before

Width:  |  Height:  |  Size: 574 B

After

Width:  |  Height:  |  Size: 700 B

View File

@ -138,11 +138,6 @@
.portfolio-content {
margin: (4 * $gap) $gap 0 $gap;
.panel {
@include shadow-panel;
padding-bottom: $gap * 3;
}
a.add-new-button {
display: inherit;
margin-left: auto;
@ -156,11 +151,6 @@
margin-bottom: 0;
}
table {
min-width: 100%;
margin-top: 0;
}
input.usa-button.usa-button-primary {
width: 9rem;
height: 4rem;
@ -250,6 +240,12 @@
.panel {
@include shadow-panel;
padding-bottom: 2rem;
table {
.form-row {
margin: 0;
}
}
}
.application-list-item {
@ -419,82 +415,6 @@
padding: 2 * $gap;
padding-top: 0;
}
table {
thead {
th:first-child {
padding-left: 3 * $gap;
}
}
th {
background-color: $color-gray-lightest;
padding: $gap 2 * $gap;
border-top: none;
border-bottom: none;
color: $color-gray;
.icon {
margin-left: 1rem;
}
}
td {
border-bottom: 1px solid $color-gray-lightest;
}
td.unused-balance {
color: $color-red;
}
.label--expired {
background-color: $color-gray-light;
}
.to-performance-period {
display: flex;
flex-wrap: wrap;
.to-end-date {
margin-right: 1.2rem;
}
&.to-expiring-soon {
.to-expiration-alert {
font-weight: $font-bold;
font-size: 1.5rem;
word-break: normal;
white-space: normal;
.icon {
margin-left: 0;
}
}
&.funded .to-expiration-alert {
color: $color-blue;
.icon {
@include icon-color($color-blue);
}
}
&.unfunded {
.to-expiration-alert {
color: $color-red;
}
.icon {
@include icon-color($color-red);
}
.to-end-date {
color: $color-red;
}
}
}
}
}
}
.portfolio-reports {

View File

@ -18,6 +18,7 @@
padding: 0 $gap;
border-radius: $gap / 3;
white-space: nowrap;
text-transform: uppercase;
&--info {
background-color: $color-primary;

View File

@ -46,7 +46,6 @@
}
@mixin shadow-panel {
padding: ($gap / 2) 0;
box-shadow: $box-shadow;
border-top: none;
border-bottom: none;
@ -59,8 +58,7 @@
@include shadow-panel;
&__content {
margin: ($gap * 2) 0;
padding: 0 ($gap * 2);
padding: $gap * 2;
}
&__body {
@ -110,8 +108,4 @@
&__footer {
padding: 3 * $gap;
}
&__actions {
@include panel-actions;
}
}

View File

@ -6,7 +6,6 @@
table.atat-table {
@include panel-margin;
min-width: 100%;
@include ie-only {
@ -42,42 +41,25 @@ table.atat-table {
}
}
tbody,
thead {
tr th {
.sorting-direction {
position: inherit;
margin-right: -16px;
width: 16px;
.icon {
height: 14px;
width: 16px;
margin: 0;
}
}
}
}
tbody {
tr {
th,
td {
@include block-list-item;
background-color: $color-white;
margin: 0;
padding: $gap * 2;
border: 1px solid $color-gray-lighter;
display: table-cell;
white-space: nowrap;
border-bottom-style: solid;
border-top: none;
vertical-align: top;
&:first-child {
border-left: none;
}
&:last-child {
border-bottom-style: dashed;
}
}
&:last-child {
td,
th {
border-bottom-style: solid;
border-right: none;
}
}
}
@ -87,19 +69,12 @@ table.atat-table {
tr {
th,
td {
@include block-list-header;
display: table-cell;
white-space: nowrap;
color: black;
background-color: $color-gray-lightest;
padding: 1rem 1.5rem;
border-top: none;
}
}
}
@at-root .panel #{&} {
&:last-child {
margin-bottom: 0;
}
}
}
.responsive-table-wrapper {

View File

@ -37,28 +37,4 @@
left: 4px;
}
}
table {
thead {
td {
font-weight: bold;
font-size: 1.4rem;
border-top: 0;
}
}
tbody {
th {
font-weight: bold;
font-size: 1.6rem;
}
td {
font-size: 1.6rem;
border-bottom: 1px solid $color-gray-lightest;
border-top: 0;
padding: (3 * $gap) (2 * $gap);
}
}
}
}

View File

@ -212,7 +212,6 @@ table {
th,
td {
font-weight: bold;
border-bottom: 1px solid $color-gray-lightest;
}
}

View File

@ -1,4 +1,5 @@
{% from "components/icon.html" import Icon %}
{% from "components/label.html" import Label %}
{% from 'components/save_button.html' import SaveButton %}
{% from "components/text_input.html" import TextInput %}
{% from "components/toggle_list.html" import ToggleButton, ToggleSection %}
@ -6,9 +7,7 @@
{% macro EnvironmentManagementTemplate(
application,
environments_obj,
new_env_form,
user_can_create_environment
) %}
new_env_form) %}
<h3>{{ "portfolios.applications.settings.environments" | translate }}</h3>
<section class="panel" id="application-environments">
@ -53,7 +52,7 @@
}}
<br>
{% if env['pending'] -%}
<span class='usa-label label--below'>{{Icon('exchange')}} CHANGES PENDING</span>
{{ Label('exchange', 'Changes Pending', classes='label--below')}}
{% else %}
<a href='{{ url_for("applications.access_environment", environment_id=env.id)}}' target='_blank' rel='noopener noreferrer' class='application-list-item__environment__csp_link'>
<span>{{ "portfolios.applications.csp_link" | translate }} {{ Icon('link', classes="icon--tiny") }}</span>
@ -94,7 +93,7 @@
</div>
</div>
{%- endif %}
{% if user_can_create_environment -%}
{% if user_can(permissions.CREATE_ENVIRONMENT) -%}
{% include "applications/fragments/add_new_environment.html" %}
{%- endif %}
</section>

View File

@ -1,5 +1,6 @@
{% from "components/alert.html" import Alert %}
{% from "components/icon.html" import Icon %}
{% from "components/label.html" import Label %}
{% import "applications/fragments/new_member_modal_content.html" as member_steps %}
{% import "applications/fragments/member_form_fields.html" as member_fields %}
{% from "components/modal.html" import Modal %}
@ -12,9 +13,9 @@
new_member_form,
action) %}
<div class="subheading" id="application-members">
<h3 id="application-members">
{{ 'portfolios.applications.settings.team_members' | translate }}
</div>
</h3>
{% if g.matchesPath("application-members") %}
{% include "fragments/flash.html" %}
@ -23,33 +24,11 @@
<div class="panel">
{% if not application.members %}
<div class='empty-state panel__content'>
<p class='empty-state__message'>{{ ("portfolios.applications.team_settings.blank_slate.title" | translate) }}</p>
{{ Icon('avatar') }}
{% if not user_can(permissions.CREATE_APPLICATION_MEMBER) %}
<p class='empty-state__sub-message'>{{ ("portfolios.applications.team_settings.blank_slate.sub_message" | translate) }}</p>
{% endif %}
{% if user_can(permissions.CREATE_APPLICATION_MEMBER) %}
{% 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(action, application_id=application.id),
steps=[
member_steps.MemberStepOne(new_member_form),
member_steps.MemberStepTwo(new_member_form, application)
],
) }}
{% endif %}
<p class='empty-state__message'>
{{ ("portfolios.applications.members.blank_slate" | translate) }}
</p>
</div>
{% else %}
{% set new_member_modal_name = "add-app-mem" %}
{% for member in members %}
{%- if user_can(permissions.EDIT_APPLICATION_MEMBER) %}
@ -114,10 +93,9 @@
<table class="atat-table">
<thead>
<tr>
<th>Member</th>
<th>Name</th>
<th>Application Permissions</th>
<th>Environment Access</th>
<th></th>
</tr>
</thead>
<tbody>
@ -131,7 +109,7 @@
</a>
<br>
{% if member.role_status == 'pending' %}
<span class='label label--purple'>INVITE PENDING</span>
{{ Label('envelope', 'invite pending', 'success', classes='label--below') }}
{% endif %}
</td>
@ -142,44 +120,47 @@
{% 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' -%}
{% set revoke_invite_modal = "revoke_invite_{}".format(member.role_id) %}
{% set resend_invite_modal = "resend_invite-{}".format(member.role_id) %}
<a v-on:click='openModal("{{ resend_invite_modal }}")'>Resend Invite</a><br>
{% if user_can(permissions.DELETE_APPLICATION_MEMBER) -%}
<a v-on:click='openModal("{{ revoke_invite_modal }}")'>{{ 'invites.revoke' | translate }}</a>
{%- endif %}
{%- endif %}
<div class="form-row">
<div class="form-col form-col--two-thirds">
{% for env in member.environment_roles %}
{{ env.environment_name }}<br>
{% endfor %}
</div>
<div class="form-col form-col--one-third">
{% if member.role_status == 'pending' -%}
{% set revoke_invite_modal = "revoke_invite_{}".format(member.role_id) %}
{% set resend_invite_modal = "resend_invite-{}".format(member.role_id) %}
<a v-on:click='openModal("{{ resend_invite_modal }}")'>Resend Invite</a><br>
{% if user_can_delete_app_member -%}
<a v-on:click='openModal("{{ revoke_invite_modal }}")'>{{ 'invites.revoke' | translate }}</a>
{%- endif %}
{%- endif %}
</div>
</div>
</td>
</tr>
{% endfor %}
</tbody>
</table>
{% if user_can(permissions.CREATE_APPLICATION_MEMBER) %}
<a class="usa-button usa-button-secondary add-new-button" v-on:click="openModal('{{ new_member_modal_name }}')">
{{ "portfolios.applications.add_member" | translate }}
</a>
{% endif %}
</div>
{% if user_can(permissions.CREATE_APPLICATION_MEMBER) %}
{{ MultiStepModalForm(
name=new_member_modal_name,
form=new_member_form,
form_action=url_for(action, application_id=application.id),
steps=[
member_steps.MemberStepOne(new_member_form),
member_steps.MemberStepTwo(new_member_form, application)
],
) }}
{% endif %}
</section>
{% endif %}
{% if user_can(permissions.CREATE_APPLICATION_MEMBER) %}
{% set new_member_modal_name = "add-app-mem" %}
<a class="usa-button usa-button-secondary add-new-button" v-on:click="openModal('{{ new_member_modal_name }}')">
{{ "portfolios.applications.add_member" | translate }}
</a>
{{ MultiStepModalForm(
name=new_member_modal_name,
form=new_member_form,
form_action=url_for(action, application_id=application.id),
steps=[
member_steps.MemberStepOne(new_member_form),
member_steps.MemberStepTwo(new_member_form, application)
],
) }}
{% endif %}
</div>
{% endmacro %}

View File

@ -2,7 +2,7 @@
{% extends "applications/base.html" %}
{% from "fragments/members.html" import MemberManagementTemplate with context %}
{% from "applications/fragments/members.html" import MemberManagementTemplate with context %}
{% set secondary_breadcrumb = 'portfolios.applications.new_application_title' | translate %}
{% block portfolio_header %}
@ -16,16 +16,16 @@
{{ ('portfolios.applications.new.step_3_description' | translate) }}
</p>
<hr class="panel__break">
{{ MemberManagementTemplate(
application,
application,
members,
new_member_form,
"applications.update_new_application_step_3") }}
<span class="action-group-footer">
<a class="usa-button" href="{{ url_for('applications.settings', application_id=application_id) }}">
<a class="usa-button" href="{{ url_for('applications.settings', application_id=application_id) }}">
Return to Application Settings
</a>
<a class="usa-button usa-button-secondary" href="{{ url_for('applications.view_new_application_step_2', application_id=application.id) }}">
@ -35,6 +35,5 @@
Cancel
</a>
</span>
{% endblock %}
{% endblock %}

View File

@ -2,8 +2,8 @@
{% from "components/alert.html" import Alert %}
{% from "components/delete_confirmation.html" import DeleteConfirmation %}
{% from "fragments/environments.html" import EnvironmentManagementTemplate %}
{% from "fragments/members.html" import MemberManagementTemplate with context %}
{% from "applications/fragments/environments.html" import EnvironmentManagementTemplate with context %}
{% from "applications/fragments/members.html" import MemberManagementTemplate with context %}
{% from "components/modal.html" import Modal %}
{% from "components/pagination.html" import Pagination %}
{% from "components/save_button.html" import SaveButton %}
@ -27,8 +27,7 @@
</form>
</base-form>
{% else %}
<!-- TODO: use new spacing styling to add in bottom margin here -->
<div class="">
<div>
<p>
{{ "fragments.edit_application_form.explain" | translate }}
</p>
@ -57,9 +56,7 @@
{{ EnvironmentManagementTemplate(
application,
environments_obj,
new_env_form,
user_can_create_environment=user_can(permissions.CREATE_ENVIRONMENT)
) }}
new_env_form) }}
{% if user_can(permissions.DELETE_APPLICATION) %}
{% set env_count = application.environments | length %}

View File

@ -0,0 +1,8 @@
{% from "components/icon.html" import Icon %}
{% macro Label(icon_name, text, type=None, classes="") -%}
<span class='label {% if type %}label--{{ type }}{% endif %} {{ classes }}'>
{{ Icon(icon_name) }} {{ text }}
</span>
{%- endmacro %}

View File

@ -1,98 +0,0 @@
{% from "components/icon.html" import Icon %}
{# expects a wtforms SelectField instance #}
{% macro Selector(field, default_label='Select an option') -%}
<selector
v-bind:choices='{{ field.choices | tojson }}'
default-label='{{ default_label }}'
{% if field.data %}initial-choice='{{ field.data }}'{% endif %}
{% if field.errors %}v-bind:initial-errors='{{ field.errors }}'{% endif %}
inline-template>
<fieldset data-ally-disabled="true" v-bind:class="['selector usa-input', { 'usa-input--error': initialErrors }]">
<v-popover v-bind:container='false' ref='popover' v-on:show='onShow'>
<legend>
<div class="usa-input__title">{{ field.label | striptags }}</div>
{% if field.description %}
<p class='usa-input__help'>
{{ field.description | safe }}
</p>
{% endif %}
<span v-show='showError'>{{ Icon('alert',classes="icon-validation") }}</span>
</legend>
<button
class='selector__button'
type='button'
v-html='label'
v-on:keydown.down.prevent.stop='handleButtonArrowDown'
v-on:keydown.up.prevent.stop='handleButtonArrowDown'
v-tooltip='{ container:false }'>
</button>
<span v-show='showError'>{{ Icon('alert',classes="icon-validation") }}</span>
<input type='hidden' name='{{ field.name }}' v-bind:value='value'/>
<template v-if='showError'>
<span v-if='initialErrors' v-for='error in initialErrors' class='usa-input__message' v-html='error'></span>
</template>
<template slot='popover'>
<div class='block-list'>
<ul>
<li v-for='(choice, index) in choices' class='block-list__item block-list__item--selectable'>
<template v-if='choice[0] !== ""'>
<selector-input
name="{{ field.name }}"
ref='choices'
v-bind:value='choice[0]'
v-bind:label='choice[1].name'
v-bind:description='choice[1].description'
v-bind:selected='value === choice[0]'
v-bind:handle-change='change'
v-bind:handle-enter='enter'
v-bind:handle-esc='esc'
inline-template>
<div>
<input
ref='input'
tabindex='0'
type='radio'
v-bind:name='name'
v-bind:id='id'
v-bind:value='value'
v-bind:checked='selected'
v-bind:autofocus='selected'
v-on:change='onChange'
v-on:keydown.enter.prevent.stop='onEnter'
v-on:keydown.esc.prevent.stop='onEsc'/>
<label v-bind:for='id'>
<template v-if='description'>
<dl>
<dt v-html='label'></dt>
<dd v-html='description'></dd>
</dl>
</template>
<span v-else v-html='label'>
</label>
</div>
</selector-input>
</template>
</li>
</ul>
</div>
</template>
</v-popover>
</fieldset>
</selector>
{%- endmacro %}

View File

@ -1,5 +1,4 @@
{% 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 %}

View File

@ -30,10 +30,9 @@
<a v-on:click="openModal('{{ modal_id }}')" class='usa-button {{ archive_button_class }}'>
{{ "portfolios.members.archive_button" | translate }}
</a>
{% if not ppoc %}
{{ subform.member_id() }}
{% endif %}
</td>
{% if not ppoc %}
{{ subform.member_id() }}
{% endif %}
</tr>
{% endfor %}

View File

@ -310,7 +310,7 @@ portfolios:
applications:
add_application_text: Add a new application
add_environment: Create an Environment
add_member: Add a New Team Member
add_member: Add Team Member
add_another_environment: Add another environment
app_settings_text: App settings
new:
@ -376,13 +376,9 @@ portfolios:
settings_heading: Application Settings
settings:
name_description: Application name and description
team_members: Team Members
team_members: Application Team
environments: Application Environments
team_settings:
blank_slate:
action_label: Invite a new team member
sub_message: Please contact your JEDI Cloud portfolio administrator to invite new members.
title: There are currently no team members for this application.
environments: Environments
section:
table:
@ -394,6 +390,7 @@ portfolios:
add_to_environment: Add to existing environment
team_text: Team
members:
blank_slate: This Application has no members
form:
env_mgmt:
label: Manage Environments