Prettier format all js files

This commit is contained in:
George Drummond 2019-01-24 09:38:43 -05:00
parent 20604e6ca9
commit 619bc9fe59
No known key found for this signature in database
GPG Key ID: 296DD6077123BF17
32 changed files with 553 additions and 443 deletions

View File

@ -15,8 +15,8 @@ describe('ConfirmationPopover', () => {
cancel_btn_text: 'Cancel', cancel_btn_text: 'Cancel',
confirm_btn_text: 'Confirm', confirm_btn_text: 'Confirm',
confirm_msg: 'Are you sure you want to do that?', confirm_msg: 'Are you sure you want to do that?',
csrf_token: '42' csrf_token: '42',
} },
}) })
it('matches snapshot', () => { it('matches snapshot', () => {
@ -29,4 +29,3 @@ describe('ConfirmationPopover', () => {
expect(input.attributes('value')).toBe('42') expect(input.attributes('value')).toBe('42')
}) })
}) })

View File

@ -2,9 +2,10 @@ import { shallowMount } from '@vue/test-utils'
import LocalDatetime from '../local_datetime' import LocalDatetime from '../local_datetime'
describe('LocalDatetime', () => { describe('LocalDatetime', () => {
const wrapper = shallowMount(LocalDatetime, { propsData: { timestamp: '1977-05-25 00:00:00' } }) const wrapper = shallowMount(LocalDatetime, {
propsData: { timestamp: '1977-05-25 00:00:00' },
})
it('renders a time element', () => { it('renders a time element', () => {
expect(wrapper.html()).toContain('<time') expect(wrapper.html()).toContain('<time')
@ -16,14 +17,12 @@ describe('LocalDatetime', () => {
}) })
it('allows specifying a custom format', () => { it('allows specifying a custom format', () => {
const wrapperWithCustomFormat = shallowMount( const wrapperWithCustomFormat = shallowMount(LocalDatetime, {
LocalDatetime, {
propsData: { propsData: {
timestamp: '1977-05-25 00:00:00', timestamp: '1977-05-25 00:00:00',
format: 'MMM Do YY' format: 'MMM Do YY',
} },
} })
)
expect(wrapperWithCustomFormat).toMatchSnapshot() expect(wrapperWithCustomFormat).toMatchSnapshot()
}) })
}) })

View File

@ -3,17 +3,20 @@ import { shallowMount } from '@vue/test-utils'
import MembersList from '../members_list' import MembersList from '../members_list'
describe('MembersList', () => { describe('MembersList', () => {
const members = [{ const members = [
{
name: 'Luke Skywalker', name: 'Luke Skywalker',
num_env: 2, num_env: 2,
status: 'active', status: 'active',
role: 'developer' role: 'developer',
}, { },
{
name: 'Chewie', name: 'Chewie',
num_env: 3, num_env: 3,
status: 'pending', status: 'pending',
role: 'admin' role: 'admin',
}] },
]
const role_choices = [ const role_choices = [
{ display_name: 'Developer', name: 'developer' }, { display_name: 'Developer', name: 'developer' },
{ display_name: 'Admin', name: 'admin' }, { display_name: 'Admin', name: 'admin' },
@ -23,10 +26,13 @@ describe('MembersList', () => {
{ display_name: 'Pending', name: 'pending' }, { display_name: 'Pending', name: 'pending' },
] ]
const createWrapper = () => shallowMount(MembersList, { const createWrapper = () =>
shallowMount(MembersList, {
propsData: { propsData: {
members, role_choices, status_choices members,
} role_choices,
status_choices,
},
}) })
it('should sort by name by default', () => { it('should sort by name by default', () => {

View File

@ -3,17 +3,20 @@ import { shallowMount } from '@vue/test-utils'
import RequestsList from '../requests_list' import RequestsList from '../requests_list'
describe('RequestsList', () => { describe('RequestsList', () => {
describe('isExtended', () => { describe('isExtended', () => {
it('should disallow sorting if not extended', () => { it('should disallow sorting if not extended', () => {
const wrapper = shallowMount(RequestsList, { propsData: { isExtended: false } }) const wrapper = shallowMount(RequestsList, {
propsData: { isExtended: false },
})
expect(wrapper.vm.sort.columnName).toEqual('') expect(wrapper.vm.sort.columnName).toEqual('')
wrapper.vm.updateSortValue('full_name') wrapper.vm.updateSortValue('full_name')
expect(wrapper.vm.sort.columnName).toEqual('') expect(wrapper.vm.sort.columnName).toEqual('')
}) })
it('should allow sorting when in extended mode', () => { it('should allow sorting when in extended mode', () => {
const wrapper = shallowMount(RequestsList, { propsData: { isExtended: true } }) const wrapper = shallowMount(RequestsList, {
propsData: { isExtended: true },
})
expect(wrapper.vm.sort.columnName).toEqual('last_submission_timestamp') expect(wrapper.vm.sort.columnName).toEqual('last_submission_timestamp')
wrapper.vm.updateSortValue('full_name') wrapper.vm.updateSortValue('full_name')
expect(wrapper.vm.sort.columnName).toEqual('full_name') expect(wrapper.vm.sort.columnName).toEqual('full_name')
@ -21,25 +24,29 @@ describe('RequestsList', () => {
}) })
describe('sorting', () => { describe('sorting', () => {
const requests = [{ const requests = [
{
name: 'X Wing', name: 'X Wing',
last_edited_timestamp: 'Mon, 2 Jan 2017 12:34:56 GMT', last_edited_timestamp: 'Mon, 2 Jan 2017 12:34:56 GMT',
last_submission_timestamp: 'Mon, 2 Jan 2017 12:34:56 GMT', last_submission_timestamp: 'Mon, 2 Jan 2017 12:34:56 GMT',
full_name: 'Luke Skywalker', full_name: 'Luke Skywalker',
annual_usage: '80000', annual_usage: '80000',
status: 'Approved', status: 'Approved',
dod_component: 'Rebels' dod_component: 'Rebels',
}, { },
{
name: 'TIE Fighter', name: 'TIE Fighter',
last_edited_timestamp: 'Mon, 12 Nov 2018 12:34:56 GMT', last_edited_timestamp: 'Mon, 12 Nov 2018 12:34:56 GMT',
last_submission_timestamp: 'Mon, 12 Nov 2018 12:34:56 GMT', last_submission_timestamp: 'Mon, 12 Nov 2018 12:34:56 GMT',
full_name: 'Darth Vader', full_name: 'Darth Vader',
annual_usage: '999999', annual_usage: '999999',
status: 'Approved', status: 'Approved',
dod_component: 'Empire' dod_component: 'Empire',
}] },
]
const mountWrapper = () => shallowMount(RequestsList, { propsData: { requests, isExtended: true } }) const mountWrapper = () =>
shallowMount(RequestsList, { propsData: { requests, isExtended: true } })
it('should default to sorting by submission recency', () => { it('should default to sorting by submission recency', () => {
const wrapper = mountWrapper() const wrapper = mountWrapper()
@ -60,16 +67,20 @@ describe('RequestsList', () => {
const unsubmittedRequest = { const unsubmittedRequest = {
name: 'Death Star', name: 'Death Star',
status: 'Started', status: 'Started',
last_submission_timestamp: null last_submission_timestamp: null,
} }
const wrapper = shallowMount(RequestsList, { const wrapper = shallowMount(RequestsList, {
propsData: { propsData: {
requests: [unsubmittedRequest, ...requests], requests: [unsubmittedRequest, ...requests],
isExtended: true isExtended: true,
} },
}) })
const displayedRequests = wrapper.vm.filteredRequests const displayedRequests = wrapper.vm.filteredRequests
expect(displayedRequests).toEqual([requests[1], requests[0], unsubmittedRequest]) expect(displayedRequests).toEqual([
requests[1],
requests[0],
unsubmittedRequest,
])
}) })
}) })
}) })

View File

@ -1,4 +1,10 @@
import { format, isWithinRange, addMonths, isSameMonth, getMonth } from 'date-fns' import {
format,
isWithinRange,
addMonths,
isSameMonth,
getMonth,
} from 'date-fns'
import { abbreviateDollars, formatDollars } from '../../lib/dollars' import { abbreviateDollars, formatDollars } from '../../lib/dollars'
const TOP_OFFSET = 20 const TOP_OFFSET = 20
@ -11,27 +17,28 @@ export default {
currentMonth: String, currentMonth: String,
expirationDate: String, expirationDate: String,
months: Object, months: Object,
budget: String budget: String,
}, },
data: function () { data: function() {
const heightScale = this.budget / (CHART_HEIGHT - TOP_OFFSET - BOTTOM_OFFSET) const heightScale =
this.budget / (CHART_HEIGHT - TOP_OFFSET - BOTTOM_OFFSET)
return { return {
numMonths: 10, numMonths: 10,
focusedMonthPosition: 4, focusedMonthPosition: 4,
height: CHART_HEIGHT, height: CHART_HEIGHT,
heightScale, heightScale,
budgetHeight: CHART_HEIGHT - BOTTOM_OFFSET - (this.budget / heightScale), budgetHeight: CHART_HEIGHT - BOTTOM_OFFSET - this.budget / heightScale,
baseHeight: CHART_HEIGHT - BOTTOM_OFFSET, baseHeight: CHART_HEIGHT - BOTTOM_OFFSET,
width: 0, width: 0,
displayedMonths: [], displayedMonths: [],
spendPath: '', spendPath: '',
projectedPath: '', projectedPath: '',
displayBudget: formatDollars(parseFloat(this.budget)) displayBudget: formatDollars(parseFloat(this.budget)),
} }
}, },
mounted: function () { mounted: function() {
this._setDisplayedMonths() this._setDisplayedMonths()
this._setMetrics() this._setMetrics()
addEventListener('load', this._setMetrics) addEventListener('load', this._setMetrics)
@ -39,7 +46,7 @@ export default {
}, },
methods: { methods: {
_setMetrics: function () { _setMetrics: function() {
this.width = this.$refs.panel.clientWidth this.width = this.$refs.panel.clientWidth
this.spendPath = '' this.spendPath = ''
this.projectedPath = '' this.projectedPath = ''
@ -48,16 +55,20 @@ export default {
let lastSpendPoint = '' let lastSpendPoint = ''
for (let i = 0; i < this.numMonths; i++) { for (let i = 0; i < this.numMonths; i++) {
const { metrics, budget, rollingAverage, cumulativeTotal } = this.displayedMonths[i] const {
const blockWidth = (this.width / this.numMonths) metrics,
budget,
rollingAverage,
cumulativeTotal,
} = this.displayedMonths[i]
const blockWidth = this.width / this.numMonths
const blockX = blockWidth * i const blockX = blockWidth * i
const spend = budget && budget.spend const spend = budget && budget.spend ? budget.spend : rollingAverage
? budget.spend
: rollingAverage
const barHeight = spend / this.heightScale const barHeight = spend / this.heightScale
lastSpend = spend lastSpend = spend
const cumulativeY = this.height - (cumulativeTotal / this.heightScale) - BOTTOM_OFFSET const cumulativeY =
const cumulativeX = blockX + blockWidth/2 this.height - cumulativeTotal / this.heightScale - BOTTOM_OFFSET
const cumulativeX = blockX + blockWidth / 2
const cumulativePoint = `${cumulativeX} ${cumulativeY}` const cumulativePoint = `${cumulativeX} ${cumulativeY}`
this.displayedMonths[i].metrics = Object.assign(metrics, { this.displayedMonths[i].metrics = Object.assign(metrics, {
@ -65,26 +76,26 @@ export default {
blockX, blockX,
barHeight, barHeight,
barWidth: 30, barWidth: 30,
barX: blockX + (blockWidth/2 - 15), barX: blockX + (blockWidth / 2 - 15),
barY: this.height - barHeight - BOTTOM_OFFSET, barY: this.height - barHeight - BOTTOM_OFFSET,
cumulativeR: 2.5, cumulativeR: 2.5,
cumulativeY, cumulativeY,
cumulativeX cumulativeX,
}) })
if (budget && budget.spend) { if (budget && budget.spend) {
this.spendPath += this.spendPath === '' ? 'M' : ' L' this.spendPath += this.spendPath === '' ? 'M' : ' L'
this.spendPath += cumulativePoint this.spendPath += cumulativePoint
lastSpendPoint = cumulativePoint lastSpendPoint = cumulativePoint
} else if (lastSpendPoint !== '') { } else if (lastSpendPoint !== '') {
this.projectedPath += this.projectedPath === '' ? `M${lastSpendPoint} L` : ' L' this.projectedPath +=
this.projectedPath === '' ? `M${lastSpendPoint} L` : ' L'
this.projectedPath += cumulativePoint this.projectedPath += cumulativePoint
} }
} }
}, },
_setDisplayedMonths: function () { _setDisplayedMonths: function() {
const [month, year] = this.currentMonth.split('/') const [month, year] = this.currentMonth.split('/')
const [expYear, expMonth, expDate] = this.expirationDate.split('-') // assumes format 'YYYY-MM-DD' const [expYear, expMonth, expDate] = this.expirationDate.split('-') // assumes format 'YYYY-MM-DD'
const monthsRange = [] const monthsRange = []
@ -101,7 +112,7 @@ export default {
const end = addMonths(start, this.numMonths + 1) const end = addMonths(start, this.numMonths + 1)
// expiration date // expiration date
const expires = new Date(expYear, expMonth-1, expDate) const expires = new Date(expYear, expMonth - 1, expDate)
// is the expiration date within the displayed date range? // is the expiration date within the displayed date range?
const expirationWithinRange = isWithinRange(expires, start, end) const expirationWithinRange = isWithinRange(expires, start, end)
@ -122,9 +133,15 @@ export default {
const budget = this.months[index] || null const budget = this.months[index] || null
const spendAmount = budget ? budget.spend : rollingAverage const spendAmount = budget ? budget.spend : rollingAverage
const spendMinusOne = this.months[indexMinusOne] ? this.months[indexMinusOne].spend : rollingAverage const spendMinusOne = this.months[indexMinusOne]
const spendMinusTwo = this.months[indexMinusTwo] ? this.months[indexMinusTwo].spend : rollingAverage ? this.months[indexMinusOne].spend
const spendMinusThree = this.months[indexMinusThree] ? this.months[indexMinusThree].spend : rollingAverage : rollingAverage
const spendMinusTwo = this.months[indexMinusTwo]
? this.months[indexMinusTwo].spend
: rollingAverage
const spendMinusThree = this.months[indexMinusThree]
? this.months[indexMinusThree].spend
: rollingAverage
const isExpirationMonth = isSameMonth(date, expires) const isExpirationMonth = isSameMonth(date, expires)
@ -134,12 +151,8 @@ export default {
cumulativeTotal += spendAmount cumulativeTotal += spendAmount
} }
rollingAverage = ( rollingAverage =
spendAmount (spendAmount + spendMinusOne + spendMinusTwo + spendMinusThree) / 4
+ spendMinusOne
+ spendMinusTwo
+ spendMinusThree
) / 4
monthsRange.push({ monthsRange.push({
budget, budget,
@ -153,9 +166,9 @@ export default {
date: { date: {
monthIndex: format(date, 'M'), monthIndex: format(date, 'M'),
month: format(date, 'MMM'), month: format(date, 'MMM'),
year: format(date,'YYYY') year: format(date, 'YYYY'),
}, },
showYear: isExpirationMonth || (i === 0) || getMonth(date) === 0, showYear: isExpirationMonth || i === 0 || getMonth(date) === 0,
isHighlighted: this.currentMonth === index, isHighlighted: this.currentMonth === index,
metrics: { metrics: {
blockWidth: 0, blockWidth: 0,
@ -166,12 +179,11 @@ export default {
barY: 0, barY: 0,
cumulativeY: 0, cumulativeY: 0,
cumulativeX: 0, cumulativeX: 0,
cumulativeR: 0 cumulativeR: 0,
} },
}) })
} }
this.displayedMonths = monthsRange this.displayedMonths = monthsRange
} },
} },
} }

View File

@ -6,11 +6,11 @@ export default {
}, },
methods: { methods: {
onInput: function (e) { onInput: function(e) {
this.$root.$emit('field-change', { this.$root.$emit('field-change', {
value: e.target.checked, value: e.target.checked,
name: this.name name: this.name,
}) })
} },
} },
} }

View File

@ -7,7 +7,7 @@ export default {
cancel_btn_text: String, cancel_btn_text: String,
confirm_btn_text: String, confirm_btn_text: String,
confirm_msg: String, confirm_msg: String,
csrf_token: String csrf_token: String,
}, },
template: ` template: `
@ -28,5 +28,5 @@ export default {
</template> </template>
<button class="tooltip-target" type="button">{{ btn_text }}</button> <button class="tooltip-target" type="button">{{ btn_text }}</button>
</v-popover> </v-popover>
` `,
} }

View File

@ -6,22 +6,22 @@ export default {
components: { components: {
textinput, textinput,
LocalDatetime LocalDatetime,
}, },
props: { props: {
initialState: String initialState: String,
}, },
data: function () { data: function() {
return { return {
approving: this.initialState === 'approving', approving: this.initialState === 'approving',
denying: this.initialState === 'denying' denying: this.initialState === 'denying',
} }
}, },
methods: { methods: {
setReview: function (e) { setReview: function(e) {
if (e.target.value === 'approving') { if (e.target.value === 'approving') {
this.approving = true this.approving = true
this.denying = false this.denying = false
@ -30,5 +30,5 @@ export default {
this.denying = true this.denying = true
} }
}, },
} },
} }

View File

@ -18,47 +18,47 @@ export default {
props: { props: {
initialData: { initialData: {
type: Object, type: Object,
default: () => ({}) default: () => ({}),
} },
}, },
data: function () { data: function() {
const { const {
estimated_monthly_spend = 0, estimated_monthly_spend = 0,
jedi_migration = '', jedi_migration = '',
technical_support_team = '' technical_support_team = '',
} = this.initialData } = this.initialData
return { return {
estimated_monthly_spend, estimated_monthly_spend,
jedi_migration, jedi_migration,
technical_support_team technical_support_team,
} }
}, },
computed: { computed: {
annualSpend: function () { annualSpend: function() {
const monthlySpend = this.estimated_monthly_spend || 0 const monthlySpend = this.estimated_monthly_spend || 0
return monthlySpend * 12 return monthlySpend * 12
}, },
annualSpendStr: function () { annualSpendStr: function() {
return this.formatDollars(this.annualSpend) return this.formatDollars(this.annualSpend)
}, },
jediMigrationOptionSelected: function () { jediMigrationOptionSelected: function() {
return this.jedi_migration !== '' return this.jedi_migration !== ''
}, },
isJediMigration: function () { isJediMigration: function() {
return this.jedi_migration === 'yes' return this.jedi_migration === 'yes'
}, },
hasTechnicalSupportTeam: function () { hasTechnicalSupportTeam: function() {
return this.technical_support_team === 'yes' return this.technical_support_team === 'yes'
} },
}, },
methods: { methods: {
formatDollars: function (intValue) { formatDollars: function(intValue) {
const mask = createNumberMask({ prefix: '$', allowDecimal: true }) const mask = createNumberMask({ prefix: '$', allowDecimal: true })
return conformToMask(intValue.toString(), mask).conformedValue return conformToMask(intValue.toString(), mask).conformedValue
} },
} },
} }

View File

@ -15,12 +15,12 @@ export default {
props: { props: {
name: String, name: String,
id: String id: String,
}, },
methods: { methods: {
doRevoke: function () { doRevoke: function() {
this.$root.$emit('revoke-' + this.id) this.$root.$emit('revoke-' + this.id)
} },
} },
} }

View File

@ -4,7 +4,6 @@ import Selector from '../selector'
import Modal from '../../mixins/modal' import Modal from '../../mixins/modal'
import toggler from '../toggler' import toggler from '../toggler'
export default { export default {
name: 'edit-environment-role', name: 'edit-environment-role',
@ -14,16 +13,16 @@ export default {
toggler, toggler,
Modal, Modal,
Selector, Selector,
textinput textinput,
}, },
props: { props: {
choices: Array, choices: Array,
initialData: String, initialData: String,
applicationId: String applicationId: String,
}, },
data: function () { data: function() {
return { return {
new_role: this.initialData, new_role: this.initialData,
} }
@ -34,19 +33,19 @@ export default {
}, },
methods: { methods: {
change: function (e) { change: function(e) {
this.new_role = e.target.value this.new_role = e.target.value
}, },
cancel: function () { cancel: function() {
this.new_role = this.initialData this.new_role = this.initialData
}, },
revoke: function () { revoke: function() {
this.new_role = "" this.new_role = ''
} },
}, },
computed: { computed: {
displayName: function () { displayName: function() {
const newRole = this.newRole const newRole = this.newRole
for (var arr in this.choices) { for (var arr in this.choices) {
if (this.choices[arr][0] == newRole) { if (this.choices[arr][0] == newRole) {
@ -54,12 +53,11 @@ export default {
} }
} }
}, },
label_class: function () { label_class: function() {
return this.newRole === "" ? return this.newRole === '' ? 'label' : 'label label--success'
"label" : "label label--success"
}, },
newRole: function () { newRole: function() {
return this.new_role return this.new_role
} },
}, },
} }

View File

@ -17,32 +17,32 @@ export default {
props: { props: {
initialData: { initialData: {
type: Object, type: Object,
default: () => ({}) default: () => ({}),
} },
}, },
data: function () { data: function() {
const { const { funding_type = '' } = this.initialData
funding_type = ""
} = this.initialData
return { return {
funding_type, funding_type,
shouldForceShowTaskOrder: false shouldForceShowTaskOrder: false,
} }
}, },
computed: { computed: {
showTaskOrderUpload: function() { showTaskOrderUpload: function() {
return !this.initialData.legacy_task_order.pdf || this.shouldForceShowTaskOrder return (
} !this.initialData.legacy_task_order.pdf || this.shouldForceShowTaskOrder
)
},
}, },
methods: { methods: {
forceShowTaskOrderUpload: function(e) { forceShowTaskOrderUpload: function(e) {
console.log("forceShowTaskOrder", e) console.log('forceShowTaskOrder', e)
e.preventDefault() e.preventDefault()
this.shouldForceShowTaskOrder = true this.shouldForceShowTaskOrder = true
} },
} },
} }

View File

@ -12,21 +12,21 @@ export default {
components: { components: {
textinput, textinput,
optionsinput optionsinput,
}, },
props: { props: {
initialData: { initialData: {
type: Object, type: Object,
default: () => ({}) default: () => ({}),
}, },
uploadErrors: { uploadErrors: {
type: Array, type: Array,
default: () => ([]) default: () => [],
} },
}, },
data: function () { data: function() {
const { const {
clin_01 = 0, clin_01 = 0,
clin_02 = 0, clin_02 = 0,
@ -40,26 +40,27 @@ export default {
clin_02, clin_02,
clin_03, clin_03,
clin_04, clin_04,
showUpload: !csp_estimate || this.uploadErrors.length > 0 showUpload: !csp_estimate || this.uploadErrors.length > 0,
} }
}, },
computed: { computed: {
totalBudget: function () { totalBudget: function() {
return [this.clin_01, this.clin_02, this.clin_03, this.clin_04].reduce( return [this.clin_01, this.clin_02, this.clin_03, this.clin_04].reduce(
function(acc, curr) { function(acc, curr) {
curr = !curr ? 0 : parseInt(curr) curr = !curr ? 0 : parseInt(curr)
return acc + curr; return acc + curr
}, 0 },
0
) )
}, },
totalBudgetStr: function () { totalBudgetStr: function() {
return this.formatDollars(this.totalBudget); return this.formatDollars(this.totalBudget)
}, },
}, },
methods: { methods: {
formatDollars: function (intValue) { formatDollars: function(intValue) {
const mask = createNumberMask({ prefix: '$', allowDecimal: true }) const mask = createNumberMask({ prefix: '$', allowDecimal: true })
return conformToMask(intValue.toString(), mask).conformedValue return conformToMask(intValue.toString(), mask).conformedValue
}, },
@ -68,7 +69,7 @@ export default {
}, },
updateBudget: function() { updateBudget: function() {
document.querySelector('#to-target').innerText = this.totalBudgetStr document.querySelector('#to-target').innerText = this.totalBudgetStr
} },
}, },
watch: { watch: {
@ -80,5 +81,5 @@ export default {
mounted: function() { mounted: function() {
this.updateBudget() this.updateBudget()
} },
} }

View File

@ -1,7 +1,7 @@
import FormMixin from '../../mixins/form' import FormMixin from '../../mixins/form'
import textinput from '../text_input' import textinput from '../text_input'
const createEnvironment = (name) => ({ name }) const createEnvironment = name => ({ name })
export default { export default {
name: 'new-application', name: 'new-application',
@ -9,97 +9,107 @@ export default {
mixins: [FormMixin], mixins: [FormMixin],
components: { components: {
textinput textinput,
}, },
props: { props: {
initialData: { initialData: {
type: Object, type: Object,
default: () => ({}) default: () => ({}),
}, },
modalName: String modalName: String,
}, },
data: function () { data: function() {
const { const { environment_names, name } = this.initialData
environment_names,
name,
} = this.initialData
const environments = ( const environments = (environment_names.length > 0
environment_names.length > 0
? environment_names ? environment_names
: ["Development", "Testing", "Staging", "Production"] : ['Development', 'Testing', 'Staging', 'Production']
).map(createEnvironment) ).map(createEnvironment)
return { return {
validations: [ validations: [
{func: this.hasEnvironments, message: "Provide at least one environment name."}, {
{func: this.envNamesAreUnique, message: "Environment names must be unique."}, func: this.hasEnvironments,
{func: this.environmentsHaveNames, message: "Environment names cannot be empty."}, message: 'Provide at least one environment name.',
},
{
func: this.envNamesAreUnique,
message: 'Environment names must be unique.',
},
{
func: this.environmentsHaveNames,
message: 'Environment names cannot be empty.',
},
], ],
errors: [], errors: [],
environments, environments,
name, name,
readyToSubmit: false readyToSubmit: false,
} }
}, },
mounted: function () { mounted: function() {
this.$root.$on('onEnvironmentAdded', this.addEnvironment) this.$root.$on('onEnvironmentAdded', this.addEnvironment)
}, },
methods: { methods: {
addEnvironment: function (event) { addEnvironment: function(event) {
this.environments.push(createEnvironment("")) this.environments.push(createEnvironment(''))
}, },
removeEnvironment: function (index) { removeEnvironment: function(index) {
if (this.environments.length > 1) { if (this.environments.length > 1) {
this.environments.splice(index, 1) this.environments.splice(index, 1)
} }
}, },
validate: function() { validate: function() {
this.errors = this.validations.map((validation) => { this.errors = this.validations
.map(validation => {
if (!validation.func()) { if (!validation.func()) {
return validation.message return validation.message
} }
}).filter(Boolean) })
.filter(Boolean)
}, },
hasEnvironments: function () { hasEnvironments: function() {
return this.environments.length > 0 && this.environments.some((e) => e.name !== "") return (
this.environments.length > 0 &&
this.environments.some(e => e.name !== '')
)
}, },
environmentsHaveNames: function () { environmentsHaveNames: function() {
if (this.environments.length > 1) { if (this.environments.length > 1) {
// only want to display this error if we have multiple envs and one or // only want to display this error if we have multiple envs and one or
// more do not have names // more do not have names
return this.environments.every((e) => e.name !== "") return this.environments.every(e => e.name !== '')
} else { } else {
return true return true
} }
}, },
envNamesAreUnique: function () { envNamesAreUnique: function() {
const names = this.environments.map((e) => e.name) const names = this.environments.map(e => e.name)
return names.every((n, index) => names.indexOf(n) === index) return names.every((n, index) => names.indexOf(n) === index)
}, },
handleSubmit: function (event) { handleSubmit: function(event) {
if (!this.readyToSubmit) { if (!this.readyToSubmit) {
event.preventDefault() event.preventDefault()
this.validateAndOpenModal() this.validateAndOpenModal()
} }
}, },
handleCancelSubmit: function () { handleCancelSubmit: function() {
this.readyToSubmit = false this.readyToSubmit = false
this.closeModal(this.modalName) this.closeModal(this.modalName)
}, },
validateAndOpenModal: function () { validateAndOpenModal: function() {
let isValid = this.$children.reduce((previous, newVal) => { let isValid = this.$children.reduce((previous, newVal) => {
// display textInput error if it is not valid // display textInput error if it is not valid
if (!newVal.showValid) { if (!newVal.showValid) {
@ -116,6 +126,6 @@ export default {
this.readyToSubmit = true this.readyToSubmit = true
this.openModal(this.modalName) this.openModal(this.modalName)
} }
} },
} },
} }

View File

@ -15,11 +15,11 @@ export default {
props: { props: {
initialData: { initialData: {
type: Object, type: Object,
default: () => ({}) default: () => ({}),
} },
}, },
data: function () { data: function() {
const { const {
am_cor = false, am_cor = false,
ko_invite = false, ko_invite = false,
@ -33,5 +33,5 @@ export default {
cor_invite, cor_invite,
so_invite, so_invite,
} }
} },
} }

View File

@ -15,17 +15,15 @@ export default {
props: { props: {
initialData: { initialData: {
type: Object, type: Object,
default: () => ({}) default: () => ({}),
} },
}, },
data: function () { data: function() {
const { const { am_poc = false } = this.initialData
am_poc = false
} = this.initialData
return { return {
am_poc am_poc,
}
} }
},
} }

View File

@ -7,15 +7,15 @@ export default {
timestamp: String, timestamp: String,
format: { format: {
type: String, type: String,
default: 'MMM D YYYY H:mm' default: 'MMM D YYYY H:mm',
} },
}, },
computed: { computed: {
displayTime: function () { displayTime: function() {
return format(this.timestamp, this.format) return format(this.timestamp, this.format)
} },
}, },
template: '<time v-bind:datetime="timestamp">{{ displayTime }}</time>' template: '<time v-bind:datetime="timestamp">{{ displayTime }}</time>',
} }

View File

@ -1,36 +1,46 @@
import { compose, sortBy, reverse, indexBy, partial, prop, pipe, toLower } from 'ramda' import {
compose,
sortBy,
reverse,
indexBy,
partial,
prop,
pipe,
toLower,
} from 'ramda'
const search = (query, members) => { const search = (query, members) => {
if (query === '' || query === 'all') { if (query === '' || query === 'all') {
return members return members
} else { } else {
const normalizedQuery = query.toLowerCase() const normalizedQuery = query.toLowerCase()
return members.filter( return members.filter(member =>
(member) => member.name.toLowerCase().includes(normalizedQuery) member.name.toLowerCase().includes(normalizedQuery)
) )
} }
} }
const filterByStatus = (status, statusesByDisplayName, members) => { const filterByStatus = (status, statusesByDisplayName, members) => {
const getStatusFromDisplayName = (_status) => statusesByDisplayName[_status].name const getStatusFromDisplayName = _status =>
statusesByDisplayName[_status].name
if (status === '' || status === 'all') { if (status === '' || status === 'all') {
return members return members
} else { } else {
return members.filter( return members.filter(
(member) => getStatusFromDisplayName(member.status) === status member => getStatusFromDisplayName(member.status) === status
) )
} }
} }
const filterByRole = (role, rolesByDisplayname, members) => { const filterByRole = (role, rolesByDisplayname, members) => {
const getRoleNameFromDisplayName = (_role) => rolesByDisplayname[_role].name const getRoleNameFromDisplayName = _role => rolesByDisplayname[_role].name
if (role === '' || role === 'all') { if (role === '' || role === 'all') {
return members return members
} else { } else {
return members.filter( return members.filter(
(member) => getRoleNameFromDisplayName(member.role) === role member => getRoleNameFromDisplayName(member.role) === role
) )
} }
} }
@ -42,9 +52,7 @@ const sort = (sortInfo, members) => {
const sortColumn = sortInfo.columns[sortInfo.columnName] const sortColumn = sortInfo.columns[sortInfo.columnName]
const sortedMembers = sortColumn.sortFunc(sortColumn.attr, members) const sortedMembers = sortColumn.sortFunc(sortColumn.attr, members)
return sortInfo.isAscending ? return sortInfo.isAscending ? sortedMembers : reverse(sortedMembers)
sortedMembers :
reverse(sortedMembers)
} }
} }
@ -57,9 +65,12 @@ export default {
status_choices: Array, status_choices: Array,
}, },
data: function () { data: function() {
const alphabeticalSort = (attr, members) => { const alphabeticalSort = (attr, members) => {
const lowercaseProp = compose(toLower, prop(attr)) const lowercaseProp = compose(
toLower,
prop(attr)
)
return sortBy(lowercaseProp, members) return sortBy(lowercaseProp, members)
} }
@ -70,18 +81,18 @@ export default {
displayName: 'Name', displayName: 'Name',
attr: 'name', attr: 'name',
sortFunc: alphabeticalSort, sortFunc: alphabeticalSort,
width: "50%" width: '50%',
}, },
{ {
displayName: 'Environments', displayName: 'Environments',
attr: 'num_env', attr: 'num_env',
sortFunc: numericSort, sortFunc: numericSort,
class: "table-cell--align-right" class: 'table-cell--align-right',
}, },
{ {
displayName: 'Status', displayName: 'Status',
attr: 'status', attr: 'status',
sortFunc: alphabeticalSort sortFunc: alphabeticalSort,
}, },
{ {
displayName: 'Portfolio Role', displayName: 'Portfolio Role',
@ -101,20 +112,20 @@ export default {
sortInfo: { sortInfo: {
columnName: defaultSortColumn, columnName: defaultSortColumn,
isAscending: true, isAscending: true,
columns: indexBy(prop('displayName'), columns) columns: indexBy(prop('displayName'), columns),
}, },
} }
}, },
computed: { computed: {
searchedList: function () { searchedList: function() {
return pipe( return pipe(
partial(search, [this.searchValue]), partial(search, [this.searchValue]),
partial(filterByStatus, [this.status, this.statusesByDisplayName]), partial(filterByStatus, [this.status, this.statusesByDisplayName]),
partial(filterByRole, [this.role, this.rolesByDisplayName]), partial(filterByRole, [this.role, this.rolesByDisplayName]),
partial(sort, [this.sortInfo]) partial(sort, [this.sortInfo])
)(this.members) )(this.members)
} },
}, },
methods: { methods: {
@ -128,8 +139,8 @@ export default {
}, },
getColumns: function() { getColumns: function() {
return Object.values(this.sortInfo.columns) return Object.values(this.sortInfo.columns)
} },
}, },
template: '<div></div>' template: '<div></div>',
} }

View File

@ -13,33 +13,36 @@ export default {
name: String, name: String,
initialErrors: { initialErrors: {
type: Array, type: Array,
default: () => [] default: () => [],
}, },
initialValue: { initialValue: {
type: Array, type: Array,
default: () => [] default: () => [],
}, },
initialOtherValue: String, initialOtherValue: String,
}, },
data: function() {
data: function () {
const showError = (this.initialErrors && this.initialErrors.length) || false const showError = (this.initialErrors && this.initialErrors.length) || false
return { return {
showError: showError, showError: showError,
showValid: !showError && this.initialValue.length > 0, showValid: !showError && this.initialValue.length > 0,
validationError: this.initialErrors.join(' '), validationError: this.initialErrors.join(' '),
otherChecked: this.initialValue.includes("other") ? true : this.otherChecked, otherChecked: this.initialValue.includes('other')
otherText: this.initialValue.includes("other") ? this.initialOtherValue : '', ? true
selections: this.initialValue : this.otherChecked,
otherText: this.initialValue.includes('other')
? this.initialOtherValue
: '',
selections: this.initialValue,
} }
}, },
methods: { methods: {
onInput: function (e) { onInput: function(e) {
this.$root.$emit('field-change', { this.$root.$emit('field-change', {
value: e.target.value, value: e.target.value,
name: this.name name: this.name,
}) })
this.showError = false this.showError = false
this.showValid = true this.showValid = true
@ -47,5 +50,5 @@ export default {
otherToggle: function() { otherToggle: function() {
this.otherChecked = !this.otherChecked this.otherChecked = !this.otherChecked
}, },
} },
} }

View File

@ -5,30 +5,28 @@ export default {
name: String, name: String,
initialErrors: { initialErrors: {
type: Array, type: Array,
default: () => [] default: () => [],
}, },
initialValue: String, initialValue: String,
}, },
data: function() {
data: function () {
const showError = (this.initialErrors && this.initialErrors.length) || false const showError = (this.initialErrors && this.initialErrors.length) || false
return { return {
showError: showError, showError: showError,
showValid: !showError && !!this.initialValue, showValid: !showError && !!this.initialValue,
validationError: this.initialErrors.join(' ') validationError: this.initialErrors.join(' '),
} }
}, },
methods: { methods: {
onInput: function (e) { onInput: function(e) {
this.$root.$emit('field-change', { this.$root.$emit('field-change', {
value: e.target.value, value: e.target.value,
name: this.name name: this.name,
}) })
this.showError = false this.showError = false
this.showValid = true this.showValid = true
} },
} },
} }

View File

@ -1,7 +1,16 @@
import LocalDatetime from '../components/local_datetime' import LocalDatetime from '../components/local_datetime'
import { formatDollars } from '../lib/dollars' import { formatDollars } from '../lib/dollars'
import { parse } from 'date-fns' import { parse } from 'date-fns'
import { compose, partial, indexBy, prop, propOr, sortBy, reverse, pipe } from 'ramda' import {
compose,
partial,
indexBy,
prop,
propOr,
sortBy,
reverse,
pipe,
} from 'ramda'
export default { export default {
name: 'requests-list', name: 'requests-list',
@ -26,13 +35,17 @@ export default {
dodComponents: { dodComponents: {
type: Array, type: Array,
default: () => [], default: () => [],
} },
}, },
data: function () { data: function() {
const defaultSort = (sort, requests) => sortBy(prop(sort.columnName), requests) const defaultSort = (sort, requests) =>
sortBy(prop(sort.columnName), requests)
const dateSort = (sort, requests) => { const dateSort = (sort, requests) => {
const parseDate = compose(partial(parse), propOr(sort.columnName, '')) const parseDate = compose(
partial(parse),
propOr(sort.columnName, '')
)
return sortBy(parseDate, requests) return sortBy(parseDate, requests)
} }
@ -84,43 +97,40 @@ export default {
dodComponentValue: '', dodComponentValue: '',
sort: { sort: {
columnName: defaultSortColumn, columnName: defaultSortColumn,
isAscending: false isAscending: false,
}, },
columns: indexBy(prop('attr'), columnList), columns: indexBy(prop('attr'), columnList),
} }
}, },
computed: { computed: {
filteredRequests: function () { filteredRequests: function() {
return pipe( return pipe(
partial(this.applySearch, [this.searchValue]), partial(this.applySearch, [this.searchValue]),
partial(this.applyFilters, [this.statusValue, this.dodComponentValue]), partial(this.applyFilters, [this.statusValue, this.dodComponentValue]),
partial(this.applySort, [this.sort]), partial(this.applySort, [this.sort])
)(this.requests) )(this.requests)
} },
}, },
methods: { methods: {
getColumns: function() { getColumns: function() {
return Object.values(this.columns) return Object.values(this.columns).filter(
.filter((column) => !column.extendedOnly || this.isExtended) column => !column.extendedOnly || this.isExtended
)
}, },
applySearch: (query, requests) => { applySearch: (query, requests) => {
return requests.filter( return requests.filter(request =>
(request) => query !== '' ? query !== ''
request.name.toLowerCase().includes(query.toLowerCase()) : ? request.name.toLowerCase().includes(query.toLowerCase())
true : true
) )
}, },
applyFilters: (status, dodComponent, requests) => { applyFilters: (status, dodComponent, requests) => {
return requests.filter( return requests
(request) => status !== '' ? .filter(request => (status !== '' ? request.status === status : true))
request.status === status : .filter(request =>
true dodComponent !== '' ? request.dod_component === dodComponent : true
).filter(
(request) => dodComponent !== '' ?
request.dod_component === dodComponent :
true
) )
}, },
applySort: function(sort, requests) { applySort: function(sort, requests) {
@ -129,23 +139,23 @@ export default {
} else { } else {
const { sortFunc } = this.columns[sort.columnName] const { sortFunc } = this.columns[sort.columnName]
const sorted = sortFunc(sort, requests) const sorted = sortFunc(sort, requests)
return sort.isAscending ? return sort.isAscending ? sorted : reverse(sorted)
sorted :
reverse(sorted)
} }
}, },
dollars: (value) => formatDollars(value, false), dollars: value => formatDollars(value, false),
updateSortValue: function(columnName) { updateSortValue: function(columnName) {
if (!this.isExtended) { return } if (!this.isExtended) {
return
}
// toggle ascending / descending if column is clicked twice // toggle ascending / descending if column is clicked twice
if (columnName === this.sort.columnName) { if (columnName === this.sort.columnName) {
this.sort.isAscending = !this.sort.isAscending this.sort.isAscending = !this.sort.isAscending
} }
this.sort.columnName = columnName; this.sort.columnName = columnName
}, },
}, },
template: '<div></div>' template: '<div></div>',
} }

View File

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

View File

@ -10,36 +10,39 @@ export default {
environments: Object, environments: Object,
currentMonthIndex: String, currentMonthIndex: String,
prevMonthIndex: String, prevMonthIndex: String,
twoMonthsAgoIndex: String twoMonthsAgoIndex: String,
}, },
data: function () { data: function() {
return { return {
applicationsState: this.applications applicationsState: this.applications,
} }
}, },
created: function () { created: function() {
Object.keys(this.applications).forEach(application => { Object.keys(this.applications).forEach(application => {
set(this.applicationsState[application], 'isVisible', false) set(this.applicationsState[application], 'isVisible', false)
}) })
}, },
methods: { methods: {
toggle: function (e, applicationName) { toggle: function(e, applicationName) {
this.applicationsState = Object.assign(this.applicationsState, { this.applicationsState = Object.assign(this.applicationsState, {
[applicationName]: Object.assign(this.applicationsState[applicationName],{ [applicationName]: Object.assign(
isVisible: !this.applicationsState[applicationName].isVisible this.applicationsState[applicationName],
}) {
isVisible: !this.applicationsState[applicationName].isVisible,
}
),
}) })
}, },
formatDollars: function (value) { formatDollars: function(value) {
return formatDollars(value, false) return formatDollars(value, false)
}, },
round: function (value) { round: function(value) {
return Math.round(value) return Math.round(value)
} },
} },
} }

View File

@ -11,9 +11,7 @@ const sort = (sortInfo, members) => {
const sortColumn = sortInfo.columns[sortInfo.columnName] const sortColumn = sortInfo.columns[sortInfo.columnName]
const sortedMembers = sortColumn.sortFunc(sortColumn.attr, members) const sortedMembers = sortColumn.sortFunc(sortColumn.attr, members)
return sortInfo.isAscending ? return sortInfo.isAscending ? sortedMembers : reverse(sortedMembers)
sortedMembers :
reverse(sortedMembers)
} }
} }
@ -22,16 +20,19 @@ export default {
props: { props: {
data: Array, data: Array,
expired: Boolean expired: Boolean,
}, },
components: { components: {
localDatetime localDatetime,
}, },
data: function () { data: function() {
const alphabeticalSort = (attr, members) => { const alphabeticalSort = (attr, members) => {
const lowercaseProp = compose(toLower, prop(attr)) const lowercaseProp = compose(
toLower,
prop(attr)
)
return sortBy(lowercaseProp, members) return sortBy(lowercaseProp, members)
} }
@ -45,23 +46,23 @@ export default {
displayName: 'Period of Performance', displayName: 'Period of Performance',
attr: 'start_date', attr: 'start_date',
sortFunc: numericSort, sortFunc: numericSort,
width: "50%" width: '50%',
}, },
{ {
displayName: 'Initial Value', displayName: 'Initial Value',
attr: 'budget', attr: 'budget',
class: "table-cell--align-right", class: 'table-cell--align-right',
sortFunc: numericSort sortFunc: numericSort,
}, },
{ {
displayName: this.expired ? 'Expired Balance' : 'Balance', displayName: this.expired ? 'Expired Balance' : 'Balance',
attr: 'budget', attr: 'budget',
class: "table-cell--align-right", class: 'table-cell--align-right',
sortFunc: numericSort sortFunc: numericSort,
}, },
{ {
displayName: '' displayName: '',
} },
] ]
const defaultSortColumn = 'Period of Performance' const defaultSortColumn = 'Period of Performance'
@ -69,15 +70,15 @@ export default {
sortInfo: { sortInfo: {
columnName: defaultSortColumn, columnName: defaultSortColumn,
isAscending: false, isAscending: false,
columns: indexBy(prop('displayName'), columns) columns: indexBy(prop('displayName'), columns),
} },
} }
}, },
computed: { computed: {
taskOrders: function () { taskOrders: function() {
return sort(this.sortInfo, this.data) return sort(this.sortInfo, this.data)
} },
}, },
methods: { methods: {
@ -94,10 +95,10 @@ export default {
return Object.values(this.sortInfo.columns) return Object.values(this.sortInfo.columns)
}, },
formatDollars: function (value) { formatDollars: function(value) {
return formatDollars(value, false) return formatDollars(value, false)
} },
}, },
template: '<div></div>' template: '<div></div>',
} }

View File

@ -5,54 +5,58 @@ export default {
name: 'textinput', name: 'textinput',
components: { components: {
MaskedInput MaskedInput,
}, },
props: { props: {
name: String, name: String,
validation: { validation: {
type: String, type: String,
default: () => 'anything' default: () => 'anything',
}, },
initialValue: { initialValue: {
type: String, type: String,
default: () => '' default: () => '',
}, },
initialErrors: { initialErrors: {
type: Array, type: Array,
default: () => [] default: () => [],
}, },
paragraph: String, paragraph: String,
noMaxWidth: String noMaxWidth: String,
}, },
data: function () { data: function() {
return { return {
showError: (this.initialErrors && this.initialErrors.length) || false, showError: (this.initialErrors && this.initialErrors.length) || false,
showValid: false, showValid: false,
mask: inputValidations[this.validation].mask, mask: inputValidations[this.validation].mask,
pipe: inputValidations[this.validation].pipe || undefined, pipe: inputValidations[this.validation].pipe || undefined,
keepCharPositions: inputValidations[this.validation].keepCharPositions || false, keepCharPositions:
validationError: this.initialErrors.join(' ') || inputValidations[this.validation].validationError, inputValidations[this.validation].keepCharPositions || false,
validationError:
this.initialErrors.join(' ') ||
inputValidations[this.validation].validationError,
value: this.initialValue, value: this.initialValue,
modified: false modified: false,
} }
}, },
computed:{ computed: {
rawValue: function () { rawValue: function() {
return this._rawValue(this.value) return this._rawValue(this.value)
} },
}, },
mounted: function () { mounted: function() {
if (this.value) { if (this.value) {
this._checkIfValid({ value: this.value, invalidate: true }) this._checkIfValid({ value: this.value, invalidate: true })
if (this.mask && this.validation !== 'email') { if (this.mask && this.validation !== 'email') {
const mask = typeof this.mask.mask !== 'function' const mask =
typeof this.mask.mask !== 'function'
? this.mask ? this.mask
: mask.mask(this.value).filter((val) => val !== '[]') : mask.mask(this.value).filter(val => val !== '[]')
this.value = conformToMask(this.value, mask).conformedValue this.value = conformToMask(this.value, mask).conformedValue
} }
@ -61,7 +65,7 @@ export default {
methods: { methods: {
// When user types a character // When user types a character
onInput: function (e) { onInput: function(e) {
// When we use the native textarea element, we receive an event object // When we use the native textarea element, we receive an event object
// When we use the masked-input component, we receive the value directly // When we use the masked-input component, we receive the value directly
const value = typeof e === 'object' ? e.target.value : e const value = typeof e === 'object' ? e.target.value : e
@ -71,13 +75,13 @@ export default {
}, },
// When field is blurred (un-focused) // When field is blurred (un-focused)
onChange: function (e) { onChange: function(e) {
// Only invalidate the field when it blurs // Only invalidate the field when it blurs
this._checkIfValid({ value: e.target.value, invalidate: true }) this._checkIfValid({ value: e.target.value, invalidate: true })
}, },
// //
_checkIfValid: function ({ value, invalidate = false}) { _checkIfValid: function({ value, invalidate = false }) {
// Validate the value // Validate the value
let valid = this._validate(value) let valid = this._validate(value)
@ -95,24 +99,27 @@ export default {
} else if (invalidate) { } else if (invalidate) {
this.showError = true this.showError = true
} }
this.showValid = this.value != "" && valid this.showValid = this.value != '' && valid
// Emit a change event // Emit a change event
this.$root.$emit('field-change', { this.$root.$emit('field-change', {
value: this._rawValue(value), value: this._rawValue(value),
valid, valid,
name: this.name name: this.name,
}) })
}, },
_rawValue: function (value) { _rawValue: function(value) {
return inputValidations[this.validation].unmask.reduce((currentValue, character) => { return inputValidations[this.validation].unmask.reduce(
(currentValue, character) => {
return currentValue.split(character).join('') return currentValue.split(character).join('')
}, value) },
value
)
}, },
_validate: function (value) { _validate: function(value) {
return inputValidations[this.validation].match.test(this._rawValue(value)) return inputValidations[this.validation].match.test(this._rawValue(value))
} },
} },
} }

View File

@ -4,29 +4,29 @@ export default {
props: { props: {
defaultVisible: { defaultVisible: {
type: Boolean, type: Boolean,
default: () => false default: () => false,
} },
}, },
data: function () { data: function() {
return { return {
isVisible: this.defaultVisible isVisible: this.defaultVisible,
} }
}, },
render: function (createElement) { render: function(createElement) {
return createElement( this.$vnode.data.tag, [ return createElement(this.$vnode.data.tag, [
this.$scopedSlots.default({ this.$scopedSlots.default({
isVisible: this.isVisible, isVisible: this.isVisible,
toggle: this.toggle toggle: this.toggle,
}) }),
]) ])
}, },
methods: { methods: {
toggle: function (e) { toggle: function(e) {
e.preventDefault() e.preventDefault()
this.isVisible = !this.isVisible this.isVisible = !this.isVisible
} },
} },
} }

View File

@ -2,7 +2,6 @@ import 'svg-innerhtml'
import 'babel-polyfill' import 'babel-polyfill'
import ally from 'ally.js' import ally from 'ally.js'
import classes from '../styles/atat.scss' import classes from '../styles/atat.scss'
import Vue from 'vue/dist/vue' import Vue from 'vue/dist/vue'
import VTooltip from 'v-tooltip' import VTooltip from 'v-tooltip'
@ -30,7 +29,7 @@ import MembersList from './components/members_list'
import LocalDatetime from './components/local_datetime' import LocalDatetime from './components/local_datetime'
import RequestsList from './components/requests_list' import RequestsList from './components/requests_list'
import ConfirmationPopover from './components/confirmation_popover' import ConfirmationPopover from './components/confirmation_popover'
import {isNotInVerticalViewport} from './lib/viewport' import { isNotInVerticalViewport } from './lib/viewport'
Vue.config.productionTip = false Vue.config.productionTip = false
@ -70,24 +69,27 @@ const app = new Vue({
if (isOpen) { if (isOpen) {
document.body.className += ' modal-open' document.body.className += ' modal-open'
} else { } else {
document.body.className = document.body.className.replace(' modal-open', '') document.body.className = document.body.className.replace(
' modal-open',
''
)
} }
}) })
const modalOpen = document.querySelector("#modalOpen") const modalOpen = document.querySelector('#modalOpen')
if (modalOpen) { if (modalOpen) {
const modal = modalOpen.getAttribute("data-modal") const modal = modalOpen.getAttribute('data-modal')
this.openModal(modal) this.openModal(modal)
} }
ally.query.focusable().forEach( function(el) { ally.query.focusable().forEach(function(el) {
el.addEventListener('focus', function(){ el.addEventListener('focus', function() {
if (isNotInVerticalViewport(el)) { if (isNotInVerticalViewport(el)) {
el.scrollIntoView({block: 'center'}) el.scrollIntoView({ block: 'center' })
} }
}) })
}) })
}, },
delimiters: ['!{', '}'] delimiters: ['!{', '}'],
}) })

View File

@ -8,12 +8,19 @@ export const formatDollars = (value, cents = true) => {
} }
export const abbreviateDollars = (value, decimals = 1) => { export const abbreviateDollars = (value, decimals = 1) => {
if (value === null) { return null } // terminate early if (value === null) {
if (value === 0) { return '0' } // terminate early return null
var b = (value).toPrecision(2).split("e"), // get power } // terminate early
if (value === 0) {
return '0'
} // terminate early
var b = value.toPrecision(2).split('e'), // get power
k = b.length === 1 ? 0 : Math.floor(Math.min(b[1].slice(1), 14) / 3), // floor at decimals, ceiling at trillions k = b.length === 1 ? 0 : Math.floor(Math.min(b[1].slice(1), 14) / 3), // floor at decimals, ceiling at trillions
c = k < 1 ? value.toFixed(0 + decimals) : (value / Math.pow(10, k * 3) ).toFixed(decimals), // divide by power c =
k < 1
? value.toFixed(0 + decimals)
: (value / Math.pow(10, k * 3)).toFixed(decimals), // divide by power
d = c < 0 ? c : Math.abs(c), // enforce -0 is 0 d = c < 0 ? c : Math.abs(c), // enforce -0 is 0
e = d + ['', 'k', 'M', 'B', 'T'][k]; // append power e = d + ['', 'k', 'M', 'B', 'T'][k] // append power
return e; return e
} }

View File

@ -7,86 +7,121 @@ export default {
mask: false, mask: false,
match: /\s*/, match: /\s*/,
unmask: [], unmask: [],
validationError: 'Please enter a response' validationError: 'Please enter a response',
}, },
requiredField: { requiredField: {
mask: false, mask: false,
match: /.+/, match: /.+/,
unmask: [], unmask: [],
validationError: 'This field is required' validationError: 'This field is required',
}, },
integer: { integer: {
mask: createNumberMask({ prefix: '', allowDecimal: false }), mask: createNumberMask({ prefix: '', allowDecimal: false }),
match: /^[1-9]\d*$/, match: /^[1-9]\d*$/,
unmask: [','], unmask: [','],
validationError: 'Please enter a number' validationError: 'Please enter a number',
}, },
dollars: { dollars: {
mask: createNumberMask({ prefix: '$', allowDecimal: true }), mask: createNumberMask({ prefix: '$', allowDecimal: true }),
match: /^-?\d+\.?\d*$/, match: /^-?\d+\.?\d*$/,
unmask: ['$',','], unmask: ['$', ','],
validationError: 'Please enter a dollar amount' validationError: 'Please enter a dollar amount',
}, },
gigabytes: { gigabytes: {
mask: createNumberMask({ prefix: '', suffix:' GB', allowDecimal: false }), mask: createNumberMask({ prefix: '', suffix: ' GB', allowDecimal: false }),
match: /^[1-9]\d*$/, match: /^[1-9]\d*$/,
unmask: [',',' GB'], unmask: [',', ' GB'],
validationError: 'Please enter an amount of data in gigabytes' validationError: 'Please enter an amount of data in gigabytes',
}, },
email: { email: {
mask: emailMask, mask: emailMask,
match: /(?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*|"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\[(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?|[a-z0-9-]*[a-z0-9]:(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])+)\])/i, match: /(?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*|"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\[(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?|[a-z0-9-]*[a-z0-9]:(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])+)\])/i,
unmask: [], unmask: [],
validationError: 'Please enter a valid e-mail address' validationError: 'Please enter a valid e-mail address',
}, },
date: { date: {
mask: [/\d/,/\d/,'/',/\d/,/\d/,'/',/\d/,/\d/,/\d/,/\d/], mask: [/\d/, /\d/, '/', /\d/, /\d/, '/', /\d/, /\d/, /\d/, /\d/],
match: /(0[1-9]|1[012])[- \/.](0[1-9]|[12][0-9]|3[01])[- \/.](19|20)\d\d/, match: /(0[1-9]|1[012])[- \/.](0[1-9]|[12][0-9]|3[01])[- \/.](19|20)\d\d/,
unmask: [], unmask: [],
pipe: createAutoCorrectedDatePipe('mm/dd/yyyy HH:MM'), pipe: createAutoCorrectedDatePipe('mm/dd/yyyy HH:MM'),
keepCharPositions: true, keepCharPositions: true,
validationError: 'Please enter a valid date in the form MM/DD/YYYY' validationError: 'Please enter a valid date in the form MM/DD/YYYY',
}, },
usPhone: { usPhone: {
mask: ['(', /[1-9]/, /\d/, /\d/, ')', ' ', /\d/, /\d/, /\d/, '-', /\d/, /\d/, /\d/, /\d/], mask: [
'(',
/[1-9]/,
/\d/,
/\d/,
')',
' ',
/\d/,
/\d/,
/\d/,
'-',
/\d/,
/\d/,
/\d/,
/\d/,
],
match: /^\d{10}$/, match: /^\d{10}$/,
unmask: ['(',')','-',' '], unmask: ['(', ')', '-', ' '],
validationError: 'Please enter a 10-digit phone number' validationError: 'Please enter a 10-digit phone number',
}, },
phoneExt: { phoneExt: {
mask: createNumberMask({ prefix: '', allowDecimal: false, integerLimit: 10, allowLeadingZeroes: true, includeThousandsSeparator: false }), mask: createNumberMask({
prefix: '',
allowDecimal: false,
integerLimit: 10,
allowLeadingZeroes: true,
includeThousandsSeparator: false,
}),
match: /^\d{0,10}$/, match: /^\d{0,10}$/,
unmask: [], unmask: [],
validationError: 'Optional: Please enter up to 10 digits' validationError: 'Optional: Please enter up to 10 digits',
}, },
dodId: { dodId: {
mask: createNumberMask({ prefix: '', allowDecimal: false, allowLeadingZeroes: true, includeThousandsSeparator: false }), mask: createNumberMask({
prefix: '',
allowDecimal: false,
allowLeadingZeroes: true,
includeThousandsSeparator: false,
}),
match: /^\d{10}$/, match: /^\d{10}$/,
unmask: [], unmask: [],
validationError: 'Please enter a 10-digit DoD ID number' validationError: 'Please enter a 10-digit DoD ID number',
}, },
peNumber: { peNumber: {
mask: false, mask: false,
match: /(0\d)(0\d)(\d{3})([a-z,A-Z]{1,3})/, match: /(0\d)(0\d)(\d{3})([a-z,A-Z]{1,3})/,
unmask: ['_'], unmask: ['_'],
validationError: 'Please enter a valid PE number. Note that it should be 7 digits followed by 1-3 letters, and should have a zero as the first and third digits.' validationError:
'Please enter a valid PE number. Note that it should be 7 digits followed by 1-3 letters, and should have a zero as the first and third digits.',
}, },
treasuryCode: { treasuryCode: {
mask: createNumberMask({ prefix: '', allowDecimal: false, allowLeadingZeroes: true, includeThousandsSeparator: false }), mask: createNumberMask({
prefix: '',
allowDecimal: false,
allowLeadingZeroes: true,
includeThousandsSeparator: false,
}),
match: /^0*([1-9]{4}|[1-9]{6})$/, match: /^0*([1-9]{4}|[1-9]{6})$/,
unmask: [], unmask: [],
validationError: 'Please enter a valid Program Treasury Code. Note that it should be a four digit or six digit number, optionally prefixed by one or more zeros.' validationError:
'Please enter a valid Program Treasury Code. Note that it should be a four digit or six digit number, optionally prefixed by one or more zeros.',
}, },
baCode: { baCode: {
mask: false, mask: false,
match: /[0-9]{2}\w?$/, match: /[0-9]{2}\w?$/,
unmask: [], unmask: [],
validationError: 'Please enter a valid BA Code. Note that it should be two digits, followed by an optional letter.' validationError:
'Please enter a valid BA Code. Note that it should be two digits, followed by an optional letter.',
}, },
portfolioName: { portfolioName: {
mask: false, mask: false,
match: /^.{4,100}$/, match: /^.{4,100}$/,
unmask: [], unmask: [],
validationError: 'Portfolio and request names must be at least 4 and not more than 100 characters' validationError:
'Portfolio and request names must be at least 4 and not more than 100 characters',
}, },
} }

View File

@ -1,11 +1,11 @@
export const isNotInVerticalViewport = (el) => { export const isNotInVerticalViewport = el => {
const bounds = el.getBoundingClientRect() const bounds = el.getBoundingClientRect()
if (bounds.top < 0) { if (bounds.top < 0) {
return true return true
} }
if (bounds.bottom > ((window.innerHeight - 50))) { if (bounds.bottom > window.innerHeight - 50) {
// 50 is a magic number to offset for the sticky footer // 50 is a magic number to offset for the sticky footer
// see variables.scss for $footer-height // see variables.scss for $footer-height
return true return true

View File

@ -1,14 +1,14 @@
export default { export default {
mounted: function () { mounted: function() {
this.$root.$on('field-change', this.handleFieldChange) this.$root.$on('field-change', this.handleFieldChange)
}, },
methods: { methods: {
handleFieldChange: function (event) { handleFieldChange: function(event) {
const { value, name } = event const { value, name } = event
if (typeof this[name] !== undefined) { if (typeof this[name] !== undefined) {
this[name] = value this[name] = value
} }
}, },
} },
} }

View File

@ -8,25 +8,25 @@ export default {
if (this.allyHandler) this.allyHandler.disengage() if (this.allyHandler) this.allyHandler.disengage()
}, },
openModal: function (name) { openModal: function(name) {
this.activeModal = name this.activeModal = name
this.$emit('modalOpen', true) this.$emit('modalOpen', true)
const idSelector = `#${this.modalId}` const idSelector = `#${this.modalId}`
this.allyHandler = ally.maintain.disabled({ this.allyHandler = ally.maintain.disabled({
filter: idSelector filter: idSelector,
}); })
} },
}, },
data: function() { data: function() {
return { return {
activeModal: null, activeModal: null,
allyHandler: null allyHandler: null,
} }
}, },
computed: { computed: {
modalId: function () { modalId: function() {
return !!this.activeModal ? `modal--${ this.activeModal }` : null return !!this.activeModal ? `modal--${this.activeModal}` : null
} },
} },
} }