Merge pull request #860 from dod-ccpo/to-review-page
Basic Task Order Review Page
This commit is contained in:
commit
6e6b0f9256
@ -23,6 +23,13 @@ def view_task_order(task_order_id):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@task_orders_bp.route("/task_orders/<task_order_id>/review")
|
||||||
|
@user_can(Permissions.VIEW_TASK_ORDER_DETAILS, message="review task order details")
|
||||||
|
def review_task_order(task_order_id):
|
||||||
|
task_order = TaskOrders.get(task_order_id)
|
||||||
|
return render_template("portfolios/task_orders/review.html", task_order=task_order)
|
||||||
|
|
||||||
|
|
||||||
def serialize_task_order(task_order):
|
def serialize_task_order(task_order):
|
||||||
return {
|
return {
|
||||||
key: getattr(task_order, key)
|
key: getattr(task_order, key)
|
||||||
|
@ -1,52 +0,0 @@
|
|||||||
import textinput from '../text_input'
|
|
||||||
import DateSelector from '../date_selector'
|
|
||||||
import uploadinput from '../upload_input'
|
|
||||||
import inputValidations from '../../lib/input_validations'
|
|
||||||
import FormMixin from '../../mixins/form'
|
|
||||||
|
|
||||||
const createLOA = number => ({ number })
|
|
||||||
|
|
||||||
export default {
|
|
||||||
name: 'ko-review',
|
|
||||||
|
|
||||||
mixins: [FormMixin],
|
|
||||||
|
|
||||||
components: {
|
|
||||||
textinput,
|
|
||||||
DateSelector,
|
|
||||||
uploadinput,
|
|
||||||
},
|
|
||||||
|
|
||||||
props: {
|
|
||||||
initialData: {
|
|
||||||
type: Object,
|
|
||||||
default: () => ({}),
|
|
||||||
},
|
|
||||||
modalName: String,
|
|
||||||
},
|
|
||||||
|
|
||||||
data: function() {
|
|
||||||
const loa_list = this.initialData['loas']
|
|
||||||
const loas = (loa_list.length > 0 ? loa_list : ['']).map(createLOA)
|
|
||||||
|
|
||||||
return {
|
|
||||||
loas,
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
mounted: function() {
|
|
||||||
this.$root.$on('onLOAAdded', this.addLOA)
|
|
||||||
},
|
|
||||||
|
|
||||||
methods: {
|
|
||||||
addLOA: function(event) {
|
|
||||||
this.loas.push(createLOA(''))
|
|
||||||
},
|
|
||||||
|
|
||||||
removeLOA: function(index) {
|
|
||||||
if (this.loas.length > 1) {
|
|
||||||
this.loas.splice(index, 1)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
15
js/components/semi_collapsible_text.js
Normal file
15
js/components/semi_collapsible_text.js
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
export default {
|
||||||
|
name: 'semi-collapsible-text',
|
||||||
|
|
||||||
|
data: function() {
|
||||||
|
return {
|
||||||
|
open: false,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
toggle: function() {
|
||||||
|
this.open = !this.open
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
@ -35,11 +35,11 @@ import ConfirmationPopover from './components/confirmation_popover'
|
|||||||
import { isNotInVerticalViewport } from './lib/viewport'
|
import { isNotInVerticalViewport } from './lib/viewport'
|
||||||
import DateSelector from './components/date_selector'
|
import DateSelector from './components/date_selector'
|
||||||
import SidenavToggler from './components/sidenav_toggler'
|
import SidenavToggler from './components/sidenav_toggler'
|
||||||
import KoReview from './components/forms/ko_review'
|
|
||||||
import BaseForm from './components/forms/base_form'
|
import BaseForm from './components/forms/base_form'
|
||||||
import DeleteConfirmation from './components/delete_confirmation'
|
import DeleteConfirmation from './components/delete_confirmation'
|
||||||
import NewEnvironment from './components/forms/new_environment'
|
import NewEnvironment from './components/forms/new_environment'
|
||||||
import EnvironmentRole from './components/environment_role'
|
import EnvironmentRole from './components/environment_role'
|
||||||
|
import SemiCollapsibleText from './components/semi_collapsible_text'
|
||||||
|
|
||||||
Vue.config.productionTip = false
|
Vue.config.productionTip = false
|
||||||
|
|
||||||
@ -76,12 +76,12 @@ const app = new Vue({
|
|||||||
DateSelector,
|
DateSelector,
|
||||||
EditOfficerForm,
|
EditOfficerForm,
|
||||||
SidenavToggler,
|
SidenavToggler,
|
||||||
KoReview,
|
|
||||||
BaseForm,
|
BaseForm,
|
||||||
DeleteConfirmation,
|
DeleteConfirmation,
|
||||||
nestedcheckboxinput,
|
nestedcheckboxinput,
|
||||||
NewEnvironment,
|
NewEnvironment,
|
||||||
EnvironmentRole,
|
EnvironmentRole,
|
||||||
|
SemiCollapsibleText,
|
||||||
},
|
},
|
||||||
|
|
||||||
mounted: function() {
|
mounted: function() {
|
||||||
|
@ -47,6 +47,15 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.semi-collapsed {
|
||||||
|
overflow: hidden;
|
||||||
|
height: $gap * 5.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.more {
|
||||||
|
margin-top: -2.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
.green {
|
.green {
|
||||||
color: $color-green;
|
color: $color-green;
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
* @source https://github.com/uswds/uswds/blob/develop/src/stylesheets/elements/_table.scss
|
* @source https://github.com/uswds/uswds/blob/develop/src/stylesheets/elements/_table.scss
|
||||||
*/
|
*/
|
||||||
|
|
||||||
table {
|
table.atat-table {
|
||||||
@include panel-margin;
|
@include panel-margin;
|
||||||
|
|
||||||
min-width: 100%;
|
min-width: 100%;
|
||||||
|
@ -67,6 +67,43 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.task-order-summary {
|
.task-order-summary {
|
||||||
|
margin: $gap * 4;
|
||||||
|
|
||||||
|
hr {
|
||||||
|
border: 0;
|
||||||
|
border-bottom: 1px solid $color-gray-light;
|
||||||
|
margin-top: $gap * 4;
|
||||||
|
margin-bottom: $gap * 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
table {
|
||||||
|
margin-top: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.col {
|
||||||
|
flex-grow: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.h1,
|
||||||
|
.h3 {
|
||||||
|
margin-bottom: $gap * 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.h4 {
|
||||||
|
margin-top: $gap * 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.to-sidebar {
|
||||||
|
padding: $gap * 4;
|
||||||
|
padding-top: $gap * 2;
|
||||||
|
flex-grow: unset;
|
||||||
|
margin-left: $gap * 6;
|
||||||
|
margin-top: $gap * 3;
|
||||||
|
width: 33.77%;
|
||||||
|
max-height: 45rem;
|
||||||
|
background-color: $color-gray-lightest;
|
||||||
|
}
|
||||||
|
|
||||||
.panel {
|
.panel {
|
||||||
@include shadow-panel;
|
@include shadow-panel;
|
||||||
}
|
}
|
||||||
|
16
templates/components/to_sidebar.html
Normal file
16
templates/components/to_sidebar.html
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
{% macro TOSidebar() -%}
|
||||||
|
|
||||||
|
<div class="col to-sidebar">
|
||||||
|
<div class="h4">Total obligated funds</div>
|
||||||
|
<div class="h3">$500,000</div>
|
||||||
|
<div>This is the funding allocated to cloud services. It may be 100% or a portion of the total task order budget.</div>
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
|
||||||
|
<div class="h4">Total contract amount</div>
|
||||||
|
<div class="h3">$800,000</div>
|
||||||
|
<div>This is the value of all funds obligated for this contract, including -- but not limited to -- funds obligated for the cloud.</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{%- endmacro %}
|
@ -32,7 +32,7 @@
|
|||||||
{% if not portfolio.members %}
|
{% if not portfolio.members %}
|
||||||
<p>{{ "portfolios.admin.no_members" | translate }}</p>
|
<p>{{ "portfolios.admin.no_members" | translate }}</p>
|
||||||
{% else %}
|
{% else %}
|
||||||
<table>
|
<table class="atat-table">
|
||||||
|
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
|
@ -14,7 +14,7 @@
|
|||||||
{% endcall %}
|
{% endcall %}
|
||||||
|
|
||||||
<div class="col col--grow">
|
<div class="col col--grow">
|
||||||
<table class="funding-summary__table">
|
<table class="funding-summary__table atat-table">
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr>
|
<tr>
|
||||||
<td><h4>{{ "task_orders.new.review.to_value"| translate }}</h4></td>
|
<td><h4>{{ "task_orders.new.review.to_value"| translate }}</h4></td>
|
||||||
|
@ -32,7 +32,7 @@
|
|||||||
class='member-list'
|
class='member-list'
|
||||||
v-bind:members='{{ members | tojson}}'>
|
v-bind:members='{{ members | tojson}}'>
|
||||||
<div class='responsive-table-wrapper panel'>
|
<div class='responsive-table-wrapper panel'>
|
||||||
<table v-cloak v-if='searchedList && searchedList.length'>
|
<table v-cloak v-if='searchedList && searchedList.length' class="atat-table">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th v-for="col in getColumns()" @click="updateSort(col.displayName)" :width="col.width" :class="col.class" scope="col">
|
<th v-for="col in getColumns()" @click="updateSort(col.displayName)" :width="col.width" :class="col.class" scope="col">
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div v-cloak class='col'>
|
<div v-cloak class='col'>
|
||||||
<table>
|
<table class="atat-table">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>Portfolio Name</th>
|
<th>Portfolio Name</th>
|
||||||
|
@ -379,7 +379,7 @@
|
|||||||
prev-month-index='{{ prev_month_index }}'
|
prev-month-index='{{ prev_month_index }}'
|
||||||
two-months-ago-index='{{ two_months_ago_index }}'
|
two-months-ago-index='{{ two_months_ago_index }}'
|
||||||
inline-template>
|
inline-template>
|
||||||
<table>
|
<table class="atat-table">
|
||||||
<thead>
|
<thead>
|
||||||
<th scope='col'><span class='usa-sr-only'>Spending scope</span></th>
|
<th scope='col'><span class='usa-sr-only'>Spending scope</span></th>
|
||||||
<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'>{{ two_months_ago.strftime('%B %Y') }}</th>
|
||||||
|
@ -23,7 +23,7 @@
|
|||||||
v-cloak
|
v-cloak
|
||||||
>
|
>
|
||||||
<div class='responsive-table-wrapper'>
|
<div class='responsive-table-wrapper'>
|
||||||
<table v-cloak>
|
<table v-cloak class="atat-table">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th v-for="col in getColumns()" @click="updateSort(col.displayName)" :width="col.width" :class="col.class" scope="col">
|
<th v-for="col in getColumns()" @click="updateSort(col.displayName)" :width="col.width" :class="col.class" scope="col">
|
||||||
|
@ -1,113 +1,91 @@
|
|||||||
{% extends "base.html" %}
|
{% extends 'portfolios/base.html' %}
|
||||||
|
|
||||||
{% set secondary_breadcrumb = "navigation.portfolio_navigation.breadcrumbs.funding" | translate %}
|
|
||||||
|
|
||||||
{% from "components/edit_link.html" import EditLink %}
|
|
||||||
{% from "components/required_label.html" import RequiredLabel %}
|
|
||||||
{% from "components/icon.html" import Icon %}
|
{% from "components/icon.html" import Icon %}
|
||||||
{% from "components/date_picker.html" import DatePicker %}
|
{% from "components/to_sidebar.html" import TOSidebar %}
|
||||||
{% from "components/text_input.html" import TextInput %}
|
|
||||||
{% from "components/alert.html" import Alert %}
|
|
||||||
{% from "components/review_field.html" import ReviewField %}
|
|
||||||
{% from "components/upload_input.html" import UploadInput %}
|
|
||||||
{% from 'components/save_button.html' import SaveButton %}
|
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<ko-review inline-template v-bind:initial-data='{{ form.data|tojson }}'>
|
|
||||||
<div class="col task-order-form">
|
|
||||||
|
|
||||||
{% include "fragments/flash.html" %}
|
<div class="task-order-summary">
|
||||||
|
<div class="h2">Portfolio Name</div>
|
||||||
{% block form_action %}
|
|
||||||
<form method='POST' action="{{ url_for('task_orders.submit_ko_review', task_order_id=task_order.id, form=form) }}" autocomplete="off" enctype="multipart/form-data">
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{{ form.csrf_token }}
|
|
||||||
|
|
||||||
{% block form %}
|
|
||||||
|
|
||||||
<div class="top-message panel">
|
|
||||||
<h1 class="subheading title">
|
|
||||||
{{ "task_orders.ko_review.title" | translate }}
|
|
||||||
</h1>
|
|
||||||
{% include "fragments/ko_review_message.html" %}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="panel">
|
|
||||||
<div class="panel__content">
|
|
||||||
|
|
||||||
<div class="h2">
|
|
||||||
{{ "task_orders.new.review.app_info"| translate }}
|
|
||||||
</div>
|
|
||||||
{% include "fragments/task_order_review/app_info.html" %}
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
<div class="h2">
|
|
||||||
{{ "task_orders.new.review.reporting"| translate }}
|
|
||||||
{{ EditLink(url_for("task_orders.new", screen=1, task_order_id=task_order.id, _anchor="reporting", ko_edit=True)) }}
|
|
||||||
</div>
|
|
||||||
{% include "fragments/task_order_review/reporting.html" %}
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
<div class="h2">
|
|
||||||
{{ "task_orders.new.review.funding"| translate }}
|
|
||||||
{{ EditLink(url_for("task_orders.new", screen=2, task_order_id=task_order.id, ko_edit=True)) }}
|
|
||||||
</div>
|
|
||||||
{% include "fragments/task_order_review/funding.html" %}
|
|
||||||
|
|
||||||
<div class="form__sub-fields">
|
|
||||||
{{ DatePicker(form.start_date) }}
|
|
||||||
{{ DatePicker(form.end_date) }}
|
|
||||||
</div>
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
<div class="h2">
|
|
||||||
{{ "task_orders.new.review.oversight"| translate }}
|
|
||||||
{{ EditLink(url_for("task_orders.new", screen=3, task_order_id=task_order.id, ko_edit=True)) }}
|
|
||||||
</div>
|
|
||||||
{% include "fragments/task_order_review/oversight.html" %}
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
<div class="h2">{{ "task_orders.ko_review.task_order_information"| translate }}</div>
|
|
||||||
|
|
||||||
<div class="form__sub-fields">
|
|
||||||
{{ UploadInput(form.pdf, show_label=True) }}
|
|
||||||
{{ TextInput(form.number, placeholder='1234567890') }}
|
|
||||||
|
|
||||||
<div class="task-order__loa-list">
|
|
||||||
<ul>
|
|
||||||
<li v-for="(loa, i) in loas" class="task-order__loa-list-item">
|
|
||||||
<div class="usa-input usa-input--validation--anything">
|
|
||||||
<label :for="'loas-' + i">
|
|
||||||
<div class="usa-input__title" v-html="'Line of Accounting (LOA) #' + (i + 1)"></div>
|
|
||||||
</label>
|
|
||||||
<input type="text" v-model='loa.number' :id="'loas-' + i" placeholder="1234567890"/>
|
|
||||||
<input type="hidden" :name="'loas-' + i" v-model='loa.number'/>
|
|
||||||
</div>
|
|
||||||
<button v-on:click="removeLOA(i)" v-if="loas.length > 1" type="button" class='loa-list-item__remover'>
|
|
||||||
{{ Icon('trash') }}
|
|
||||||
<span>Remove</span>
|
|
||||||
</button>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
<div class="task-order__loa-add-item">
|
|
||||||
<button v-on:click="addLOA" class="icon-link" tabindex="0" type="button">{{ Icon('plus') }} Add another LOA</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{{ TextInput(form.custom_clauses, paragraph=True) }}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
<semi-collapsible-text inline-template>
|
||||||
|
<div>
|
||||||
|
<div v-bind:class="{ 'semi-collapsed' : !open }">
|
||||||
|
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
|
||||||
</div>
|
</div>
|
||||||
|
<a v-on:click='toggle' v-show="!open" class="right more">More{{ Icon('caret_down') }}</a>
|
||||||
|
<a v-on:click='toggle' v-show="open" class="right more">Less{{ Icon('caret_up') }}</a>
|
||||||
</div>
|
</div>
|
||||||
{% endblock %}
|
</semi-collapsible-text>
|
||||||
|
|
||||||
<div class='action-group'>
|
<hr>
|
||||||
{{ SaveButton(text="Continue", element="input") }}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</form>
|
|
||||||
|
<div class="h1">Review your task order</div>
|
||||||
|
<div>Check to make sure the information you entered is correct. After submission, you will confirm this task order was signed by a contracting officer. Thereafter, you will be informed as soon as CCPO completes their review.</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col">
|
||||||
|
<div class="h4">Task order number - 10 digit found in your system of record</div>
|
||||||
|
<div>{{task_order.number}}</div>
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
|
||||||
|
<div class="h3">Funding summary</div>
|
||||||
|
<div>CLIN 1: Unclassified Cloud Services 001</div>
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Amount</th>
|
||||||
|
<th>Obligated</th>
|
||||||
|
<th>PoP Start</th>
|
||||||
|
<th>PoP End</th>
|
||||||
|
<th>LOA</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td>$500,000</td>
|
||||||
|
<td>Yes</td>
|
||||||
|
<td>9/07/19</td>
|
||||||
|
<td>9/07/20</td>
|
||||||
|
<td>34820394</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<div>CLIN 2: Unclassified Cloud Services 002</div>
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Amount</th>
|
||||||
|
<th>Obligated</th>
|
||||||
|
<th>PoP Start</th>
|
||||||
|
<th>PoP End</th>
|
||||||
|
<th>LOA</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td>$300,000</td>
|
||||||
|
<td>No</td>
|
||||||
|
<td>9/08/20</td>
|
||||||
|
<td>9/08/21</td>
|
||||||
|
<td>q9384751934</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
|
||||||
|
<div class="h3">Supporting document</div>
|
||||||
|
<div class="h4">{{ Icon('ok',classes="icon-validation") }}document</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{ TOSidebar() }}
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</ko-review>
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user