From 3ece7b4c89a8a39d9f8db9a96555a471ae53184f Mon Sep 17 00:00:00 2001 From: leigh-mil Date: Mon, 1 Apr 2019 20:37:21 -0400 Subject: [PATCH 01/13] Add vue component for save button and integrate into FormMixin --- js/components/save_button.js | 18 ++++++++++++++++++ js/index.js | 2 ++ js/mixins/form.js | 20 ++++++++++++++++++++ 3 files changed, 40 insertions(+) create mode 100644 js/components/save_button.js diff --git a/js/components/save_button.js b/js/components/save_button.js new file mode 100644 index 00000000..60eabe66 --- /dev/null +++ b/js/components/save_button.js @@ -0,0 +1,18 @@ +export default { + name: 'savebutton', + + props: { + text: String, + disabled: Boolean, + classes: String, + }, + + data: function() { + return { + displayClasses: `usa-button usa-button-primary ${this.classes}`, + } + }, + + template: + '', +} diff --git a/js/index.js b/js/index.js index a5e58f45..3fc1e9bf 100644 --- a/js/index.js +++ b/js/index.js @@ -33,6 +33,7 @@ import { isNotInVerticalViewport } from './lib/viewport' import DateSelector from './components/date_selector' import SidenavToggler from './components/sidenav_toggler' import KoReview from './components/forms/ko_review' +import savebutton from './components/save_button' Vue.config.productionTip = false @@ -68,6 +69,7 @@ const app = new Vue({ EditOfficerForm, SidenavToggler, KoReview, + savebutton, }, mounted: function() { diff --git a/js/mixins/form.js b/js/mixins/form.js index e0fb546f..2bdf9fea 100644 --- a/js/mixins/form.js +++ b/js/mixins/form.js @@ -1,3 +1,5 @@ +import savebutton from '../components/save_button' + export default { mounted: function() { this.$root.$on('field-change', this.handleFieldChange) @@ -8,7 +10,25 @@ export default { const { value, name } = event if (typeof this[name] !== undefined) { this[name] = value + this.disabled = false } }, }, + + data: function() { + return { + disabled: this.disableSave, + } + }, + + props: { + disableSave: { + type: Boolean, + default: true, + }, + }, + + components: { + savebutton, + }, } From 7fca19ebeecb36dede565831200c01e4d35dc6af Mon Sep 17 00:00:00 2001 From: leigh-mil Date: Tue, 2 Apr 2019 14:59:47 -0400 Subject: [PATCH 02/13] Create base-form vue component --- js/components/forms/base_form.js | 24 ++++++++++++++++++++++++ js/index.js | 2 ++ 2 files changed, 26 insertions(+) create mode 100644 js/components/forms/base_form.js diff --git a/js/components/forms/base_form.js b/js/components/forms/base_form.js new file mode 100644 index 00000000..80e6106c --- /dev/null +++ b/js/components/forms/base_form.js @@ -0,0 +1,24 @@ +import FormMixin from '../../mixins/form' +import textinput from '../text_input' +import optionsinput from '../options_input' +import DateSelector from '../date_selector' +import MultiStepModalForm from './multi_step_modal_form' +import multicheckboxinput from '../multi_checkbox_input' +import funding from './funding' +import checkboxinput from '../checkbox_input' +import levelofwarrant from '../levelofwarrant' + +export default { + name: 'base-form', + components: { + textinput, + optionsinput, + DateSelector, + MultiStepModalForm, + multicheckboxinput, + funding, + checkboxinput, + levelofwarrant, + }, + mixins: [FormMixin], +} diff --git a/js/index.js b/js/index.js index 3fc1e9bf..e3684424 100644 --- a/js/index.js +++ b/js/index.js @@ -34,6 +34,7 @@ import DateSelector from './components/date_selector' import SidenavToggler from './components/sidenav_toggler' import KoReview from './components/forms/ko_review' import savebutton from './components/save_button' +import BaseForm from './components/forms/base_form' Vue.config.productionTip = false @@ -70,6 +71,7 @@ const app = new Vue({ SidenavToggler, KoReview, savebutton, + BaseForm, }, mounted: function() { From ade3f38b5e0addad606c952e4f9b54a629534dc3 Mon Sep 17 00:00:00 2001 From: leigh-mil Date: Tue, 2 Apr 2019 15:04:17 -0400 Subject: [PATCH 03/13] Update edit user form to use base-form and update date-selector to emit changes --- js/components/date_selector.js | 21 ++++++--- templates/fragments/edit_user_form.html | 60 +++++++++++++------------ 2 files changed, 48 insertions(+), 33 deletions(-) diff --git a/js/components/date_selector.js b/js/components/date_selector.js index e5e48128..be6a8c89 100644 --- a/js/components/date_selector.js +++ b/js/components/date_selector.js @@ -62,18 +62,23 @@ export default { isMonthValid: function() { var _month = parseInt(this.month) - - return _month >= 0 && _month <= 12 + var valid = _month >= 0 && _month <= 12 + this._emitChange('month', this.month, valid) + return valid }, isDayValid: function() { var _day = parseInt(this.day) - - return _day >= 0 && _day <= this.daysMaxCalculation + var valid = _day >= 0 && _day <= this.daysMaxCalculation + this._emitChange('day', this.day, valid) + return valid }, isYearValid: function() { - return parseInt(this.year) >= 1 + // Emit a change event + var valid = parseInt(this.year) >= 1 + this._emitChange('year', this.year, valid) + return valid }, isWithinDateRange: function() { @@ -128,6 +133,12 @@ export default { }, }, + methods: { + _emitChange: function(name, value, valid) { + this.$root.$emit('field-change', { value, valid, name }) + }, + }, + render: function(createElement) { return createElement('p', 'Please implement inline-template') }, diff --git a/templates/fragments/edit_user_form.html b/templates/fragments/edit_user_form.html index fe821b65..436d5218 100644 --- a/templates/fragments/edit_user_form.html +++ b/templates/fragments/edit_user_form.html @@ -4,37 +4,41 @@ {% from "components/phone_input.html" import PhoneInput %} {% from "components/date_picker.html" import DatePicker %} -
- {{ form.csrf_token }} -
-
-
-
- {{ TextInput(form.first_name, validation='requiredField') }} + + + {{ form.csrf_token }} +
+
+
+
+ {{ TextInput(form.first_name, validation='requiredField') }} +
+ +
+ {{ TextInput(form.last_name, validation='requiredField') }} +
-
- {{ TextInput(form.last_name, validation='requiredField') }} + {{ TextInput(form.email, validation='email') }} + {{ PhoneInput(form.phone_number, form.phone_ext) }} + + {{ OptionsInput(form.service_branch) }} + {{ OptionsInput(form.citizenship) }} + {{ OptionsInput(form.designation) }} + + +
+ {{ DatePicker(form.date_latest_training, mindate=mindate, maxdate=maxdate) }}
- - {{ TextInput(form.email, validation='email') }} - {{ PhoneInput(form.phone_number, form.phone_ext) }} - - {{ OptionsInput(form.service_branch) }} - {{ OptionsInput(form.citizenship) }} - {{ OptionsInput(form.designation) }} - - -
- {{ DatePicker(form.date_latest_training, mindate=mindate, maxdate=maxdate) }} -
-
-
- -
- +
+ + +
+ +
From 637efc5ab593b33cf6b0daa1d9f6b75f3ea46f05 Mon Sep 17 00:00:00 2001 From: leigh-mil Date: Tue, 2 Apr 2019 15:05:42 -0400 Subject: [PATCH 04/13] Update validation on new application form to skip the save button --- js/components/forms/new_application.js | 13 ++++++++----- templates/portfolios/applications/new.html | 5 ++++- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/js/components/forms/new_application.js b/js/components/forms/new_application.js index b9275c3b..edc780e0 100644 --- a/js/components/forms/new_application.js +++ b/js/components/forms/new_application.js @@ -112,13 +112,16 @@ export default { validateAndOpenModal: function() { let isValid = this.$children.reduce((previous, newVal) => { // display textInput error if it is not valid - if (!newVal.showValid) { - newVal.showError = true + if (newVal.$options.name == 'savebutton') { + return true + } else { + if (!newVal.showValid) { + newVal.showError = true + } + + return newVal.showValid && previous } - - return newVal.showValid && previous }, true) - this.validate() isValid = this.errors.length == 0 && isValid diff --git a/templates/portfolios/applications/new.html b/templates/portfolios/applications/new.html index 343bb10a..9c2fc021 100644 --- a/templates/portfolios/applications/new.html +++ b/templates/portfolios/applications/new.html @@ -76,7 +76,10 @@
- + +
From 8b10732ac9b1f5619e584797db00b2a0fc7ac9d6 Mon Sep 17 00:00:00 2001 From: leigh-mil Date: Tue, 2 Apr 2019 15:06:36 -0400 Subject: [PATCH 05/13] Use base form and save button on all forms --- js/components/forms/base_form.js | 2 - styles/sections/_task_order.scss | 4 +- templates/portfolios/admin.html | 40 ++++----- .../portfolios/task_orders/invitations.html | 2 +- templates/portfolios/task_orders/review.html | 2 +- .../portfolios/task_orders/so_review.html | 50 ++++++----- .../signing/signature_requested.html | 84 +++++++++---------- 7 files changed, 89 insertions(+), 95 deletions(-) diff --git a/js/components/forms/base_form.js b/js/components/forms/base_form.js index 80e6106c..dc32687a 100644 --- a/js/components/forms/base_form.js +++ b/js/components/forms/base_form.js @@ -4,7 +4,6 @@ import optionsinput from '../options_input' import DateSelector from '../date_selector' import MultiStepModalForm from './multi_step_modal_form' import multicheckboxinput from '../multi_checkbox_input' -import funding from './funding' import checkboxinput from '../checkbox_input' import levelofwarrant from '../levelofwarrant' @@ -16,7 +15,6 @@ export default { DateSelector, MultiStepModalForm, multicheckboxinput, - funding, checkboxinput, levelofwarrant, }, diff --git a/styles/sections/_task_order.scss b/styles/sections/_task_order.scss index 05cea515..cfd321b6 100644 --- a/styles/sections/_task_order.scss +++ b/styles/sections/_task_order.scss @@ -493,12 +493,10 @@ align-items: center; justify-content: flex-end; - .usa-button { + button.usa-button { margin-left: 4 * $gap; margin-top: 0; margin-bottom: 0; - padding-top: 0; - padding-bottom: 0; } } } diff --git a/templates/portfolios/admin.html b/templates/portfolios/admin.html index ad7a0872..1ae6bcf5 100644 --- a/templates/portfolios/admin.html +++ b/templates/portfolios/admin.html @@ -15,28 +15,30 @@
{% if user_can(permissions.VIEW_PORTFOLIO_NAME) %} -
- {{ portfolio_form.csrf_token }} -
-
- {{ TextInput(portfolio_form.name, validation="portfolioName") }} -
- -
- + + + {{ portfolio_form.csrf_token }} +
+
+ {{ TextInput(portfolio_form.name, validation="portfolioName") }}
-
-
-
-
{{ "forms.task_order.defense_component_label" | translate }}
- {% if portfolio.defense_component %} -
{{ portfolio.defense_component }}
- {% else %} -
{{ "fragments.portfolio_admin.none" | translate }}
- {% endif %} + +
+
- +
+
+
{{ "forms.task_order.defense_component_label" | translate }}
+ {% if portfolio.defense_component %} +
{{ portfolio.defense_component }}
+ {% else %} +
{{ "fragments.portfolio_admin.none" | translate }}
+ {% endif %} +
+
+ + {% endif %}
diff --git a/templates/portfolios/task_orders/invitations.html b/templates/portfolios/task_orders/invitations.html index 92955268..1dd1e8a6 100644 --- a/templates/portfolios/task_orders/invitations.html +++ b/templates/portfolios/task_orders/invitations.html @@ -59,7 +59,7 @@ {{ Icon("x") }} Cancel - +
diff --git a/templates/portfolios/task_orders/review.html b/templates/portfolios/task_orders/review.html index 913b9b4a..a3763fa2 100644 --- a/templates/portfolios/task_orders/review.html +++ b/templates/portfolios/task_orders/review.html @@ -103,7 +103,7 @@ {% endblock %}
- +
diff --git a/templates/portfolios/task_orders/so_review.html b/templates/portfolios/task_orders/so_review.html index 357cabce..6b713217 100644 --- a/templates/portfolios/task_orders/so_review.html +++ b/templates/portfolios/task_orders/so_review.html @@ -6,38 +6,36 @@ {% block content %} {% include "fragments/flash.html" %} + +
+
-
-
- -
-

-
{{ "task_orders.so_review.title" | translate }}
-

-
+
+

+
{{ "task_orders.so_review.title" | translate }}
+

+
-
-
- {{ form.csrf_token }} -

{{ "task_orders.so_review.certification" | translate }}

- {{ TextInput(form.certifying_official) }} - {{ TextInput(form.certifying_official_title) }} - {{ TextInput(form.certifying_official_phone, placeholder='(123) 456-7890', validation='usPhone') }} - {{ TextInput(form.certifying_official_address, paragraph=True) }} +
+ + {{ form.csrf_token }} +

{{ "task_orders.so_review.certification" | translate }}

+ {{ TextInput(form.certifying_official) }} + {{ TextInput(form.certifying_official_title) }} + {{ TextInput(form.certifying_official_phone, placeholder='(123) 456-7890', validation='usPhone') }} + {{ TextInput(form.certifying_official_address, paragraph=True) }} -
+
- {{ MultiCheckboxInput(form.required_distribution) }} + {{ MultiCheckboxInput(form.required_distribution) }} -
- -
- +
+ +
+ +
-
- + {% endblock %} diff --git a/templates/task_orders/signing/signature_requested.html b/templates/task_orders/signing/signature_requested.html index 1d3b5f35..86670b30 100644 --- a/templates/task_orders/signing/signature_requested.html +++ b/templates/task_orders/signing/signature_requested.html @@ -5,52 +5,50 @@ {% from "components/icon.html" import Icon %} {% block content %} -
- {{ form.csrf_token }} -
-
-
-
-

-
{{ "task_orders.sign.task_order_builder_title" | translate }}
- {{ "task_orders.sign.title" | translate }} -

-
- -
-
-
- - {{ TextInput(form.level_of_warrant, validation='dollars', placeholder='$0.00', disabled=True) }} - - - - {{ TextInput(form.level_of_warrant, validation='dollars', placeholder='$0.00') }} - - - - {{ CheckboxInput(form.unlimited_level_of_warrant) }} -
+ + + {{ form.csrf_token }} +
+
+
+
+

+
{{ "task_orders.sign.task_order_builder_title" | translate }}
+ {{ "task_orders.sign.title" | translate }} +

- {{ CheckboxInput(form.signature) }} +
+
+
+ + {{ TextInput(form.level_of_warrant, validation='dollars', placeholder='$0.00', disabled=True) }} + + + + {{ TextInput(form.level_of_warrant, validation='dollars', placeholder='$0.00') }} + + + + {{ CheckboxInput(form.unlimited_level_of_warrant) }} +
+
+ + {{ CheckboxInput(form.signature) }} +
+
+
-
- - - - {{ Icon('caret_left') }} - - {{ "common.back" | translate }} - -
-
- + + {% endblock %} - From 02cc18a93f421bc86dade3deeaf8e4f63b5b1df4 Mon Sep 17 00:00:00 2001 From: leigh-mil Date: Tue, 2 Apr 2019 15:38:46 -0400 Subject: [PATCH 06/13] Add emiter to all input fields --- js/components/checkbox_input.js | 1 + js/components/date_selector.js | 6 +++++- js/components/multi_checkbox_input.js | 1 + js/components/options_input.js | 1 + js/components/text_input.js | 1 + js/mixins/form.js | 4 +++- 6 files changed, 12 insertions(+), 2 deletions(-) diff --git a/js/components/checkbox_input.js b/js/components/checkbox_input.js index bfea50ad..d4dc3397 100644 --- a/js/components/checkbox_input.js +++ b/js/components/checkbox_input.js @@ -10,6 +10,7 @@ export default { this.$root.$emit('field-change', { value: e.target.checked, name: this.name, + parent_uid: this.$parent._uid, }) }, }, diff --git a/js/components/date_selector.js b/js/components/date_selector.js index be6a8c89..d3d6ff56 100644 --- a/js/components/date_selector.js +++ b/js/components/date_selector.js @@ -135,7 +135,11 @@ export default { methods: { _emitChange: function(name, value, valid) { - this.$root.$emit('field-change', { value, valid, name }) + this.$root.$emit('field-change', { + value, + name, + parent_uid: this.$parent && this.$parent._uid, + }) }, }, diff --git a/js/components/multi_checkbox_input.js b/js/components/multi_checkbox_input.js index cf008326..2bf03e07 100644 --- a/js/components/multi_checkbox_input.js +++ b/js/components/multi_checkbox_input.js @@ -43,6 +43,7 @@ export default { this.$root.$emit('field-change', { value: e.target.value, name: this.name, + parent_uid: this.$parent._uid, }) this.showError = false this.showValid = true diff --git a/js/components/options_input.js b/js/components/options_input.js index 0a291b02..6f60d529 100644 --- a/js/components/options_input.js +++ b/js/components/options_input.js @@ -24,6 +24,7 @@ export default { this.$root.$emit('field-change', { value: e.target.value, name: this.name, + parent_uid: this.$parent._uid, }) this.showError = false this.showValid = true diff --git a/js/components/text_input.js b/js/components/text_input.js index cb838025..93609841 100644 --- a/js/components/text_input.js +++ b/js/components/text_input.js @@ -128,6 +128,7 @@ export default { value: this._rawValue(value), valid, name: this.name, + parent_uid: this.$parent._uid, }) }, diff --git a/js/mixins/form.js b/js/mixins/form.js index 2bdf9fea..0839a1b9 100644 --- a/js/mixins/form.js +++ b/js/mixins/form.js @@ -10,7 +10,9 @@ export default { const { value, name } = event if (typeof this[name] !== undefined) { this[name] = value - this.disabled = false + if (event['parent_uid'] === this._uid) { + this.disabled = false + } } }, }, From 1aaf4421ab0ac41b4a0a412922345fcf52496f72 Mon Sep 17 00:00:00 2001 From: leigh-mil Date: Tue, 2 Apr 2019 16:01:08 -0400 Subject: [PATCH 07/13] Remove unnecessary savebutton vue component and create SaveButton Macro --- js/components/forms/new_application.js | 12 ++++-------- js/components/save_button.js | 18 ------------------ js/index.js | 2 -- js/mixins/form.js | 6 ------ templates/components/save_button.html | 6 ++++++ .../fragments/admin/portfolio_members.html | 1 + templates/fragments/edit_user_form.html | 7 ++----- templates/portfolios/admin.html | 3 ++- templates/portfolios/applications/new.html | 6 ++---- .../portfolios/task_orders/invitations.html | 3 ++- templates/portfolios/task_orders/review.html | 4 ++-- .../portfolios/task_orders/so_review.html | 3 ++- .../signing/signature_requested.html | 3 ++- 13 files changed, 25 insertions(+), 49 deletions(-) delete mode 100644 js/components/save_button.js create mode 100644 templates/components/save_button.html diff --git a/js/components/forms/new_application.js b/js/components/forms/new_application.js index edc780e0..df7bc4e9 100644 --- a/js/components/forms/new_application.js +++ b/js/components/forms/new_application.js @@ -112,15 +112,11 @@ export default { validateAndOpenModal: function() { let isValid = this.$children.reduce((previous, newVal) => { // display textInput error if it is not valid - if (newVal.$options.name == 'savebutton') { - return true - } else { - if (!newVal.showValid) { - newVal.showError = true - } - - return newVal.showValid && previous + if (!newVal.showValid) { + newVal.showError = true } + + return newVal.showValid && previous }, true) this.validate() isValid = this.errors.length == 0 && isValid diff --git a/js/components/save_button.js b/js/components/save_button.js deleted file mode 100644 index 60eabe66..00000000 --- a/js/components/save_button.js +++ /dev/null @@ -1,18 +0,0 @@ -export default { - name: 'savebutton', - - props: { - text: String, - disabled: Boolean, - classes: String, - }, - - data: function() { - return { - displayClasses: `usa-button usa-button-primary ${this.classes}`, - } - }, - - template: - '', -} diff --git a/js/index.js b/js/index.js index e3684424..5bced706 100644 --- a/js/index.js +++ b/js/index.js @@ -33,7 +33,6 @@ import { isNotInVerticalViewport } from './lib/viewport' import DateSelector from './components/date_selector' import SidenavToggler from './components/sidenav_toggler' import KoReview from './components/forms/ko_review' -import savebutton from './components/save_button' import BaseForm from './components/forms/base_form' Vue.config.productionTip = false @@ -70,7 +69,6 @@ const app = new Vue({ EditOfficerForm, SidenavToggler, KoReview, - savebutton, BaseForm, }, diff --git a/js/mixins/form.js b/js/mixins/form.js index 0839a1b9..3fddc7f2 100644 --- a/js/mixins/form.js +++ b/js/mixins/form.js @@ -1,5 +1,3 @@ -import savebutton from '../components/save_button' - export default { mounted: function() { this.$root.$on('field-change', this.handleFieldChange) @@ -29,8 +27,4 @@ export default { default: true, }, }, - - components: { - savebutton, - }, } diff --git a/templates/components/save_button.html b/templates/components/save_button.html new file mode 100644 index 00000000..2802df1b --- /dev/null +++ b/templates/components/save_button.html @@ -0,0 +1,6 @@ +{% macro SaveButton(text, additional_classes="") -%} + {% set class = "usa-button usa-button-primary" + additional_classes %} + +{%- endmacro %} diff --git a/templates/fragments/admin/portfolio_members.html b/templates/fragments/admin/portfolio_members.html index f548f857..51c8ae33 100644 --- a/templates/fragments/admin/portfolio_members.html +++ b/templates/fragments/admin/portfolio_members.html @@ -1,5 +1,6 @@ {% from "components/icon.html" import Icon %} {% from "components/options_input.html" import OptionsInput %} +{% from 'components/save_button.html' import SaveButton %} {% from "components/modal.html" import Modal %} {% from "components/alert.html" import Alert %} diff --git a/templates/fragments/edit_user_form.html b/templates/fragments/edit_user_form.html index 436d5218..b04b1077 100644 --- a/templates/fragments/edit_user_form.html +++ b/templates/fragments/edit_user_form.html @@ -3,6 +3,7 @@ {% from "components/date_input.html" import DateInput %} {% from "components/phone_input.html" import PhoneInput %} {% from "components/date_picker.html" import DatePicker %} +{% from 'components/save_button.html' import SaveButton %}
@@ -34,11 +35,7 @@
- - + {{ SaveButton(text=("fragments.edit_user_form.save_details_button" | translate), additional_classes="usa-button-big" )}}
diff --git a/templates/portfolios/admin.html b/templates/portfolios/admin.html index 1ae6bcf5..18d2ec86 100644 --- a/templates/portfolios/admin.html +++ b/templates/portfolios/admin.html @@ -4,6 +4,7 @@ {% from "components/icon.html" import Icon %} {% from "components/text_input.html" import TextInput %} {% from "components/multi_step_modal_form.html" import MultiStepModalForm %} +{% from 'components/save_button.html' import SaveButton %} {% set secondary_breadcrumb = "navigation.portfolio_navigation.portfolio_admin" | translate %} @@ -24,7 +25,7 @@
- + {{ SaveButton(text='Save', additional_classes='usa-button-big') }}
diff --git a/templates/portfolios/applications/new.html b/templates/portfolios/applications/new.html index 9c2fc021..bc5b9a7a 100644 --- a/templates/portfolios/applications/new.html +++ b/templates/portfolios/applications/new.html @@ -4,6 +4,7 @@ {% from "components/icon.html" import Icon %} {% from "components/modal.html" import Modal %} {% from "components/text_input.html" import TextInput %} +{% from 'components/save_button.html' import SaveButton %} {% set secondary_breadcrumb = 'portfolios.applications.new_application_title' | translate %} @@ -76,10 +77,7 @@
- - + {{ SaveButton(text=('portfolios.applications.create_button_text' | translate)) }}
diff --git a/templates/portfolios/task_orders/invitations.html b/templates/portfolios/task_orders/invitations.html index 1dd1e8a6..a45a83fa 100644 --- a/templates/portfolios/task_orders/invitations.html +++ b/templates/portfolios/task_orders/invitations.html @@ -6,6 +6,7 @@ {% from "components/icon.html" import Icon %} {% from "components/text_input.html" import TextInput %} {% from "components/confirmation_button.html" import ConfirmationButton %} +{% from 'components/save_button.html' import SaveButton %} {% macro Link(text, icon_name, onClick=None, url='#', classes='') %} @@ -59,7 +60,7 @@ {{ Icon("x") }} Cancel - + {{ SaveButton(text='Save Changes') }}
diff --git a/templates/portfolios/task_orders/review.html b/templates/portfolios/task_orders/review.html index a3763fa2..8e86a66a 100644 --- a/templates/portfolios/task_orders/review.html +++ b/templates/portfolios/task_orders/review.html @@ -10,7 +10,7 @@ {% 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 %} @@ -103,7 +103,7 @@ {% endblock %}
- + {{ SaveButton(text="Continue") }}
diff --git a/templates/portfolios/task_orders/so_review.html b/templates/portfolios/task_orders/so_review.html index 6b713217..d62f1aa2 100644 --- a/templates/portfolios/task_orders/so_review.html +++ b/templates/portfolios/task_orders/so_review.html @@ -2,6 +2,7 @@ {% from "components/text_input.html" import TextInput %} {% from "components/multi_checkbox_input.html" import MultiCheckboxInput %} +{% from 'components/save_button.html' import SaveButton %} {% block content %} @@ -31,7 +32,7 @@ {{ MultiCheckboxInput(form.required_distribution) }}
- + {{ SaveButton(text='Continue') }}
diff --git a/templates/task_orders/signing/signature_requested.html b/templates/task_orders/signing/signature_requested.html index 86670b30..1047de40 100644 --- a/templates/task_orders/signing/signature_requested.html +++ b/templates/task_orders/signing/signature_requested.html @@ -3,6 +3,7 @@ {% from "components/text_input.html" import TextInput %} {% from "components/checkbox_input.html" import CheckboxInput %} {% from "components/icon.html" import Icon %} +{% from 'components/save_button.html' import SaveButton %} {% block content %} @@ -38,7 +39,7 @@
- + {{ SaveButton(text=('common.sign' | translate)) }} From 3f2beb44b2ea85ad4b37700cfbde8f8458b0d489 Mon Sep 17 00:00:00 2001 From: leigh-mil Date: Thu, 4 Apr 2019 10:31:02 -0400 Subject: [PATCH 08/13] Refactor emit field change into a utility function --- js/components/checkbox_input.js | 8 +++----- js/components/date_selector.js | 7 ++----- js/components/multi_checkbox_input.js | 7 ++----- js/components/options_input.js | 8 +++----- js/components/text_input.js | 4 ++-- js/lib/emitters.js | 6 ++++++ 6 files changed, 18 insertions(+), 22 deletions(-) create mode 100644 js/lib/emitters.js diff --git a/js/components/checkbox_input.js b/js/components/checkbox_input.js index d4dc3397..604dd355 100644 --- a/js/components/checkbox_input.js +++ b/js/components/checkbox_input.js @@ -1,3 +1,5 @@ +import { emitFieldChange } from '../lib/emitters' + export default { name: 'checkboxinput', @@ -7,11 +9,7 @@ export default { methods: { onInput: function(e) { - this.$root.$emit('field-change', { - value: e.target.checked, - name: this.name, - parent_uid: this.$parent._uid, - }) + emitFieldChange(this, { value: e.target.checked, name: this.name }) }, }, } diff --git a/js/components/date_selector.js b/js/components/date_selector.js index d3d6ff56..df1142b1 100644 --- a/js/components/date_selector.js +++ b/js/components/date_selector.js @@ -1,5 +1,6 @@ import Vue from 'vue' import { getDaysInMonth } from 'date-fns' +import { emitFieldChange } from '../lib/emitters' var paddedNumber = function(number) { if ((number + '').length === 1) { @@ -135,11 +136,7 @@ export default { methods: { _emitChange: function(name, value, valid) { - this.$root.$emit('field-change', { - value, - name, - parent_uid: this.$parent && this.$parent._uid, - }) + emitFieldChange(this, { value, name }) }, }, diff --git a/js/components/multi_checkbox_input.js b/js/components/multi_checkbox_input.js index 2bf03e07..44a8c184 100644 --- a/js/components/multi_checkbox_input.js +++ b/js/components/multi_checkbox_input.js @@ -1,5 +1,6 @@ import optionsinput from '../components/options_input' import textinput from '../components/text_input' +import { emitFieldChange } from '../lib/emitters' export default { name: 'multicheckboxinput', @@ -40,11 +41,7 @@ export default { methods: { onInput: function(e) { - this.$root.$emit('field-change', { - value: e.target.value, - name: this.name, - parent_uid: this.$parent._uid, - }) + emitFieldChange(this, { value: e.target.value, name: this.name }) this.showError = false this.showValid = true }, diff --git a/js/components/options_input.js b/js/components/options_input.js index 6f60d529..085212e5 100644 --- a/js/components/options_input.js +++ b/js/components/options_input.js @@ -1,3 +1,5 @@ +import { emitFieldChange } from '../lib/emitters' + export default { name: 'optionsinput', @@ -21,11 +23,7 @@ export default { methods: { onInput: function(e) { - this.$root.$emit('field-change', { - value: e.target.value, - name: this.name, - parent_uid: this.$parent._uid, - }) + emitFieldChange(this, { value: e.target.value, name: this.name }) this.showError = false this.showValid = true }, diff --git a/js/components/text_input.js b/js/components/text_input.js index 93609841..51972d82 100644 --- a/js/components/text_input.js +++ b/js/components/text_input.js @@ -1,6 +1,7 @@ import MaskedInput, { conformToMask } from 'vue-text-mask' import inputValidations from '../lib/input_validations' import { formatDollars } from '../lib/dollars' +import { emitFieldChange } from '../lib/emitters' export default { name: 'textinput', @@ -124,11 +125,10 @@ export default { this.showValid = this.value != '' && valid // Emit a change event - this.$root.$emit('field-change', { + emitFieldChange(this, { value: this._rawValue(value), valid, name: this.name, - parent_uid: this.$parent._uid, }) }, diff --git a/js/lib/emitters.js b/js/lib/emitters.js new file mode 100644 index 00000000..8bed5096 --- /dev/null +++ b/js/lib/emitters.js @@ -0,0 +1,6 @@ +export const emitFieldChange = (el, data) => { + el.$root.$emit('field-change', { + ...data, + parent_uid: el.$parent && el.$parent._uid, + }) +} From 850153a517d73825418b1f499231c101451495e1 Mon Sep 17 00:00:00 2001 From: leigh-mil Date: Thu, 4 Apr 2019 11:45:46 -0400 Subject: [PATCH 09/13] Change variable names to be clearer --- js/mixins/form.js | 8 ++++---- templates/components/save_button.html | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/js/mixins/form.js b/js/mixins/form.js index 3fddc7f2..5436f821 100644 --- a/js/mixins/form.js +++ b/js/mixins/form.js @@ -9,7 +9,7 @@ export default { if (typeof this[name] !== undefined) { this[name] = value if (event['parent_uid'] === this._uid) { - this.disabled = false + this.changed = true } } }, @@ -17,14 +17,14 @@ export default { data: function() { return { - disabled: this.disableSave, + changed: this.hasChanges, } }, props: { - disableSave: { + hasChanges: { type: Boolean, - default: true, + default: false, }, }, } diff --git a/templates/components/save_button.html b/templates/components/save_button.html index 2802df1b..0735cd8c 100644 --- a/templates/components/save_button.html +++ b/templates/components/save_button.html @@ -1,6 +1,6 @@ {% macro SaveButton(text, additional_classes="") -%} {% set class = "usa-button usa-button-primary" + additional_classes %} - {%- endmacro %} From f3ea704c1bf17f6d099a6da80f2f581c44abe50f Mon Sep 17 00:00:00 2001 From: leigh-mil Date: Thu, 4 Apr 2019 13:29:15 -0400 Subject: [PATCH 10/13] Update SaveButton to be either an input or a button element, and restore inputs that were previously switched to buttons --- templates/components/save_button.html | 10 ++++++---- templates/portfolios/task_orders/invitations.html | 2 +- templates/portfolios/task_orders/review.html | 2 +- templates/portfolios/task_orders/so_review.html | 2 +- templates/task_orders/signing/signature_requested.html | 2 +- 5 files changed, 10 insertions(+), 8 deletions(-) diff --git a/templates/components/save_button.html b/templates/components/save_button.html index 0735cd8c..fbd6f56f 100644 --- a/templates/components/save_button.html +++ b/templates/components/save_button.html @@ -1,6 +1,8 @@ -{% macro SaveButton(text, additional_classes="") -%} +{% macro SaveButton(text, element="button", additional_classes="", other_attrs="") -%} {% set class = "usa-button usa-button-primary" + additional_classes %} - + <{{ element }} type="submit" class="{{ class }}" tabindex="0" v-bind:disabled="!changed" value="{{ text }}" {{ other_attrs }}> + {% if element == 'button'%} + {{ text }} + {% endif %} + {%- endmacro %} diff --git a/templates/portfolios/task_orders/invitations.html b/templates/portfolios/task_orders/invitations.html index a45a83fa..e7b0b75a 100644 --- a/templates/portfolios/task_orders/invitations.html +++ b/templates/portfolios/task_orders/invitations.html @@ -60,7 +60,7 @@ {{ Icon("x") }} Cancel - {{ SaveButton(text='Save Changes') }} + {{ SaveButton(text='Save Changes', element="input") }}
diff --git a/templates/portfolios/task_orders/review.html b/templates/portfolios/task_orders/review.html index 8e86a66a..3256baf2 100644 --- a/templates/portfolios/task_orders/review.html +++ b/templates/portfolios/task_orders/review.html @@ -103,7 +103,7 @@ {% endblock %}
- {{ SaveButton(text="Continue") }} + {{ SaveButton(text="Continue", element="input") }}
diff --git a/templates/portfolios/task_orders/so_review.html b/templates/portfolios/task_orders/so_review.html index d62f1aa2..7659656f 100644 --- a/templates/portfolios/task_orders/so_review.html +++ b/templates/portfolios/task_orders/so_review.html @@ -32,7 +32,7 @@ {{ MultiCheckboxInput(form.required_distribution) }}
- {{ SaveButton(text='Continue') }} + {{ SaveButton(text='Continue', additional_classes="usa-button-big") }}
diff --git a/templates/task_orders/signing/signature_requested.html b/templates/task_orders/signing/signature_requested.html index 1047de40..fa22b52b 100644 --- a/templates/task_orders/signing/signature_requested.html +++ b/templates/task_orders/signing/signature_requested.html @@ -39,7 +39,7 @@
- {{ SaveButton(text=('common.sign' | translate)) }} + {{ SaveButton(text=('common.sign' | translate), additional_classes="usa-button-big") }} From 5aae1691a21f9a6a7ef7d1721034931765ef058d Mon Sep 17 00:00:00 2001 From: leigh-mil Date: Thu, 4 Apr 2019 15:54:51 -0400 Subject: [PATCH 11/13] Add modal functionality to BaseForm, use BaseForm and SaveButton in Portfolio members form --- js/components/forms/base_form.js | 32 +++++++ styles/components/_portfolio_layout.scss | 6 +- .../fragments/admin/portfolio_members.html | 92 +++++++++---------- 3 files changed, 83 insertions(+), 47 deletions(-) diff --git a/js/components/forms/base_form.js b/js/components/forms/base_form.js index dc32687a..074032c2 100644 --- a/js/components/forms/base_form.js +++ b/js/components/forms/base_form.js @@ -1,3 +1,5 @@ +import ally from 'ally.js' + import FormMixin from '../../mixins/form' import textinput from '../text_input' import optionsinput from '../options_input' @@ -19,4 +21,34 @@ export default { levelofwarrant, }, mixins: [FormMixin], + methods: { + closeModal: function(name) { + this.activeModal = null + this.$root.$emit('modalOpen', false) + if (this.$root.allyHandler) this.$root.allyHandler.disengage() + }, + + openModal: function(name) { + this.$root.activeModal = name + this.$root.$emit('modalOpen', true) + const idSelector = `#${this.$root.modalId}` + + this.$root.allyHandler = ally.maintain.disabled({ + filter: idSelector, + }) + }, + }, + data: function() { + return { + activeModal: null, + allyHandler: null, + } + }, + computed: { + modalId: function() { + return !!this.$root.activeModal + ? `modal--${this.$root.activeModal}` + : null + }, + }, } diff --git a/styles/components/_portfolio_layout.scss b/styles/components/_portfolio_layout.scss index 7a33345b..1f24f582 100644 --- a/styles/components/_portfolio_layout.scss +++ b/styles/components/_portfolio_layout.scss @@ -297,7 +297,11 @@ .members-table-footer { float: right; - padding: 3 * $gap; + padding: 3 * $gap 0; + + .action-group.save { + padding-right: 3 * $gap; + } } a.modal-link.icon-link { diff --git a/templates/fragments/admin/portfolio_members.html b/templates/fragments/admin/portfolio_members.html index 51c8ae33..75b90078 100644 --- a/templates/fragments/admin/portfolio_members.html +++ b/templates/fragments/admin/portfolio_members.html @@ -10,51 +10,59 @@ {% if g.matchesPath("portfolio-members") %} {% include "fragments/flash.html" %} {% endif %} -
- {{ member_perms_form.csrf_token }} + + + {{ member_perms_form.csrf_token }} -
- - {% if not portfolio.members %} -

{{ "portfolios.admin.no_members" | translate }}

- {% else %} - + {% if not portfolio.members %} +

{{ "portfolios.admin.no_members" | translate }}

+ {% else %} +
- - - - - - - - - - + + + + + + + + + + - - {% if user_can(permissions.EDIT_PORTFOLIO_USERS) %} - {% include "fragments/admin/members_edit.html" %} - {% elif user_can(permissions.VIEW_PORTFOLIO_USERS) %} - {% include "fragments/admin/members_view.html" %} - {% endif %} - + + {% if user_can(permissions.EDIT_PORTFOLIO_USERS) %} + {% include "fragments/admin/members_edit.html" %} + {% elif user_can(permissions.VIEW_PORTFOLIO_USERS) %} + {% include "fragments/admin/members_view.html" %} + {% endif %} + -
{{ "portfolios.members.permissions.name" | translate }}{{ "portfolios.members.permissions.app_mgmt" | translate }}{{ "portfolios.members.permissions.funding" | translate }}{{ "portfolios.members.permissions.reporting" | translate }}{{ "portfolios.members.permissions.portfolio_mgmt" | translate }}
{{ "portfolios.members.permissions.name" | translate }}{{ "portfolios.members.permissions.app_mgmt" | translate }}{{ "portfolios.members.permissions.funding" | translate }}{{ "portfolios.members.permissions.reporting" | translate }}{{ "portfolios.members.permissions.portfolio_mgmt" | translate }}
+ + + {% endif %} - {% endif %} - - + + {% if user_can(permissions.EDIT_PORTFOLIO_USERS) %} {% for member in portfolio.members %} @@ -85,19 +93,11 @@ -
From 5e77c4f29cd77782f2c32882dbdf2beef359c49d Mon Sep 17 00:00:00 2001 From: leigh-mil Date: Sat, 6 Apr 2019 15:34:01 -0400 Subject: [PATCH 12/13] Refactor SaveButton --- templates/components/save_button.html | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/templates/components/save_button.html b/templates/components/save_button.html index fbd6f56f..4adb6e37 100644 --- a/templates/components/save_button.html +++ b/templates/components/save_button.html @@ -1,8 +1,10 @@ -{% macro SaveButton(text, element="button", additional_classes="", other_attrs="") -%} +{% macro SaveButton(text, element="button", additional_classes="", form=None) -%} {% set class = "usa-button usa-button-primary" + additional_classes %} - <{{ element }} type="submit" class="{{ class }}" tabindex="0" v-bind:disabled="!changed" value="{{ text }}" {{ other_attrs }}> - {% if element == 'button'%} + {% if element == "button" %} + + {% elif element == 'input' %} + + {% endif %} {%- endmacro %} From 85c99182f79a186f2f8cd3c6a3f2ff2c03694e27 Mon Sep 17 00:00:00 2001 From: leigh-mil Date: Sat, 6 Apr 2019 16:52:52 -0400 Subject: [PATCH 13/13] Refactor modals so they work when nested in other components and fix BaseForm so it doesn't repeat ModalMixin logic --- js/components/forms/base_form.js | 34 +++----------------------------- js/index.js | 5 +++-- js/mixins/modal.js | 2 +- 3 files changed, 7 insertions(+), 34 deletions(-) diff --git a/js/components/forms/base_form.js b/js/components/forms/base_form.js index 074032c2..749365ba 100644 --- a/js/components/forms/base_form.js +++ b/js/components/forms/base_form.js @@ -8,6 +8,7 @@ import MultiStepModalForm from './multi_step_modal_form' import multicheckboxinput from '../multi_checkbox_input' import checkboxinput from '../checkbox_input' import levelofwarrant from '../levelofwarrant' +import Modal from '../../mixins/modal' export default { name: 'base-form', @@ -19,36 +20,7 @@ export default { multicheckboxinput, checkboxinput, levelofwarrant, + Modal, }, - mixins: [FormMixin], - methods: { - closeModal: function(name) { - this.activeModal = null - this.$root.$emit('modalOpen', false) - if (this.$root.allyHandler) this.$root.allyHandler.disengage() - }, - - openModal: function(name) { - this.$root.activeModal = name - this.$root.$emit('modalOpen', true) - const idSelector = `#${this.$root.modalId}` - - this.$root.allyHandler = ally.maintain.disabled({ - filter: idSelector, - }) - }, - }, - data: function() { - return { - activeModal: null, - allyHandler: null, - } - }, - computed: { - modalId: function() { - return !!this.$root.activeModal - ? `modal--${this.$root.activeModal}` - : null - }, - }, + mixins: [FormMixin, Modal], } diff --git a/js/index.js b/js/index.js index 5bced706..0a419224 100644 --- a/js/index.js +++ b/js/index.js @@ -73,9 +73,10 @@ const app = new Vue({ }, mounted: function() { - this.$on('modalOpen', isOpen => { - if (isOpen) { + this.$on('modalOpen', data => { + if (data['isOpen']) { document.body.className += ' modal-open' + this.activeModal = data['name'] } else { document.body.className = document.body.className.replace( ' modal-open', diff --git a/js/mixins/modal.js b/js/mixins/modal.js index 13c5f18d..6a922db8 100644 --- a/js/mixins/modal.js +++ b/js/mixins/modal.js @@ -10,7 +10,7 @@ export default { openModal: function(name) { this.activeModal = name - this.$emit('modalOpen', true) + this.$root.$emit('modalOpen', { isOpen: true, name: name }) const idSelector = `#${this.modalId}` this.allyHandler = ally.maintain.disabled({