diff --git a/atst/forms/task_order.py b/atst/forms/task_order.py index 903149fe..b63ce7b0 100644 --- a/atst/forms/task_order.py +++ b/atst/forms/task_order.py @@ -7,6 +7,7 @@ from wtforms.fields import ( TextAreaField, ) from wtforms.fields.html5 import DateField +from wtforms.widgets import ListWidget, CheckboxInput from .forms import CacheableForm from .data import ( @@ -46,6 +47,8 @@ class AppInfoForm(CacheableForm): description="Which of these describes how complex your team's use of the cloud will be? (Select all that apply.)", choices=PROJECT_COMPLEXITY, default="", + widget=ListWidget(prefix_label=False), + option_widget=CheckboxInput(), ) complexity_other = StringField("Project Complexity Other") dev_team = SelectMultipleField( @@ -53,6 +56,8 @@ class AppInfoForm(CacheableForm): description="Which people or teams will be completing the development work for your cloud applications?", choices=DEV_TEAM, default="", + widget=ListWidget(prefix_label=False), + option_widget=CheckboxInput(), ) dev_team_other = StringField("Development Team Other") team_experience = RadioField( diff --git a/atst/models/task_order.py b/atst/models/task_order.py index 85e4f4ba..29b220d2 100644 --- a/atst/models/task_order.py +++ b/atst/models/task_order.py @@ -52,11 +52,6 @@ class TaskOrder(Base, mixins.TimestampsMixin): filter(None, [self.clin_01, self.clin_02, self.clin_03, self.clin_04]) ) - def __repr__(self): - return "".format( - self.number, self.budget, self.end_date, self.id - ) - @property def portfolio_name(self): return self.workspace.name @@ -70,3 +65,8 @@ class TaskOrder(Base, mixins.TimestampsMixin): if c.name not in ["id"] }, } + + def __repr__(self): + return "".format( + self.number, self.budget, self.end_date, self.id + ) diff --git a/atst/routes/task_orders/new.py b/atst/routes/task_orders/new.py index 9cf07f05..9f0b38b4 100644 --- a/atst/routes/task_orders/new.py +++ b/atst/routes/task_orders/new.py @@ -49,12 +49,20 @@ class ShowTaskOrderWorkflow: return self._task_order + @property + def task_order_formdata(self): + task_order_dict = self.task_order.to_dictionary() + for field in task_order_dict: + if task_order_dict[field] is None: + task_order_dict[field] = "" + return task_order_dict + @property def form(self): if self._form: pass elif self.task_order: - self._form = self._section["form"](data=self.task_order.to_dictionary()) + self._form = self._section["form"](formdata=self.task_order_formdata) else: self._form = self._section["form"]() diff --git a/js/components/forms/poc.js b/js/components/forms/poc.js index 8b60c0b6..91b5dbfc 100644 --- a/js/components/forms/poc.js +++ b/js/components/forms/poc.js @@ -1,5 +1,4 @@ import FormMixin from '../../mixins/form' -import optionsinput from '../options_input' import textinput from '../text_input' import checkboxinput from '../checkbox_input' @@ -9,7 +8,6 @@ export default { mixins: [FormMixin], components: { - optionsinput, textinput, checkboxinput, }, diff --git a/js/components/multi_checkbox_input.js b/js/components/multi_checkbox_input.js new file mode 100644 index 00000000..7c0b822c --- /dev/null +++ b/js/components/multi_checkbox_input.js @@ -0,0 +1,60 @@ +import otherinput from '../components/other_input' +import optionsinput from '../components/options_input' +import textinput from '../components/text_input' + +export default { + name: 'multicheckboxinput', + + components: { + otherinput, + optionsinput, + textinput, + }, + + props: { + name: String, + initialErrors: { + type: Array, + default: () => [] + }, + initialValue: { + type: Array, + default: () => [] + }, + initialOtherValue: String, + }, + + + data: function () { + const showError = (this.initialErrors && this.initialErrors.length) || false + return { + showError: showError, + showValid: !showError && !!this.initialValue, + validationError: this.initialErrors.join(' '), + otherChecked: this.initialValue.includes("other") ? true : this.otherChecked, + otherText: this.initialOtherValue, + selections: [] + } + }, + + mounted: function () { + for (let choice of this.initialValue) { + this.selections.push(choice) + } + }, + + methods: { + onInput: function (e) { + this.$root.$emit('field-change', { + value: e.target.value, + name: this.name + }) + this.showError = false + this.showValid = true + }, + otherToggle: function() { + this.otherChecked = !this.otherChecked + this.otherText = '' + } + } +} diff --git a/js/components/other_input.js b/js/components/other_input.js new file mode 100644 index 00000000..c2431b85 --- /dev/null +++ b/js/components/other_input.js @@ -0,0 +1,29 @@ +import FormMixin from '../mixins/form' +import textinput from '../components/text_input' + +export default { + name: 'otherinput', + + mixins: [FormMixin], + + components: { + textinput, + }, + + props: { + initialData: { + type: Array, + default: () => ({}) + } + }, + + data: function () { + const { + other = true + } = this.initialData + + return { + other + } + } +} diff --git a/js/index.js b/js/index.js index 1cfea514..39271984 100644 --- a/js/index.js +++ b/js/index.js @@ -6,6 +6,8 @@ import Vue from 'vue/dist/vue' import VTooltip from 'v-tooltip' import optionsinput from './components/options_input' +import multicheckboxinput from './components/multi_checkbox_input' +import otherinput from './components/other_input' import textinput from './components/text_input' import checkboxinput from './components/checkbox_input' import DetailsOfUse from './components/forms/details_of_use' @@ -37,6 +39,8 @@ const app = new Vue({ components: { toggler, optionsinput, + multicheckboxinput, + otherinput, textinput, checkboxinput, DetailsOfUse, diff --git a/templates/components/multi_checkbox_input.html b/templates/components/multi_checkbox_input.html new file mode 100644 index 00000000..3bd294c5 --- /dev/null +++ b/templates/components/multi_checkbox_input.html @@ -0,0 +1,60 @@ +{% from "components/icon.html" import Icon %} +{% from "components/tooltip.html" import Tooltip %} + +{% macro MultiCheckboxInput(field, other_input_field, tooltip, inline=False) -%} + +
+ +
+ +
+ {{ field.label | striptags}} + {% if tooltip %}{{ Tooltip(tooltip) }}{% endif %} +
+ + {% if field.description %} + {{ field.description | safe }} + {% endif %} + + {{ Icon('alert',classes="icon-validation") }} + {{ Icon('ok',classes="icon-validation") }} +
+ +
    + {% for choice in field.choices %} +
  • + {% if choice[0] != 'other' %} + + + {% else %} + + + +
    + +
    + {% endif %} +
  • + {% endfor %} +
+ + + + + +
+
+ +
+ +{%- endmacro %} diff --git a/templates/task_orders/new/app_info.html b/templates/task_orders/new/app_info.html index 09a088a7..9005bc2b 100644 --- a/templates/task_orders/new/app_info.html +++ b/templates/task_orders/new/app_info.html @@ -3,6 +3,7 @@ {% from "components/text_input.html" import TextInput %} {% from "components/options_input.html" import OptionsInput %} {% from "components/date_input.html" import DateInput %} +{% from "components/multi_checkbox_input.html" import MultiCheckboxInput %} {% block heading %} What You're Building @@ -28,14 +29,12 @@

About Your Project

{{ OptionsInput(form.app_migration) }} {{ OptionsInput(form.native_apps) }} -{{ OptionsInput(form.complexity) }} -{{ TextInput(form.complexity_other) }} +{{ MultiCheckboxInput(form.complexity, form.complexity_other) }}

About Your Team

-{{ OptionsInput(form.dev_team) }} -{{ TextInput(form.dev_team_other) }} +{{ MultiCheckboxInput(form.dev_team, form.dev_team_other) }} {{ OptionsInput(form.team_experience) }}
diff --git a/tests/routes/task_orders/test_new_task_order.py b/tests/routes/task_orders/test_new_task_order.py index ea023e38..09412b3d 100644 --- a/tests/routes/task_orders/test_new_task_order.py +++ b/tests/routes/task_orders/test_new_task_order.py @@ -78,6 +78,16 @@ def test_show_task_order(): assert another_workflow.task_order == task_order +def test_show_task_order_formdata(): + task_order = TaskOrderFactory.create() + workflow = ShowTaskOrderWorkflow(task_order_id=task_order.id) + + assert workflow.task_order.to_dictionary()["user_id"] is None + assert workflow.task_order_formdata["user_id"] is "" + for field in workflow.task_order_formdata: + assert not field is None + + def test_show_task_order_form(): workflow = ShowTaskOrderWorkflow() assert not workflow.form.data["app_migration"]