diff --git a/app/assets/javascripts/app/controllers/_application_controller_form.coffee b/app/assets/javascripts/app/controllers/_application_controller_form.coffee index 496997b06..25ee8959a 100644 --- a/app/assets/javascripts/app/controllers/_application_controller_form.coffee +++ b/app/assets/javascripts/app/controllers/_application_controller_form.coffee @@ -94,8 +94,8 @@ class App.ControllerForm extends App.Controller for attributeName, attribute of attributesClean - # ignore read only attributes - if !attribute.readonly + # ignore read only or not rendered attributes attributes + if !attribute.readonly && !attribute.skipRendering # check generic filter if @filter && !attribute.filter diff --git a/app/assets/javascripts/app/controllers/_ui_element/sla_times.coffee b/app/assets/javascripts/app/controllers/_ui_element/sla_times.coffee index 7679e6e66..1a3fec95c 100644 --- a/app/assets/javascripts/app/controllers/_ui_element/sla_times.coffee +++ b/app/assets/javascripts/app/controllers/_ui_element/sla_times.coffee @@ -2,8 +2,7 @@ class App.UiElement.sla_times @render: (attribute, params = {}) -> - # set default value - if !params.first_response_time && params.first_response_time isnt 0 + if !params.id && !params.first_response_time params.first_response_time = 120 item = $( App.view('generic/sla_times')( @@ -33,32 +32,50 @@ class App.UiElement.sla_times # reset data item row.find('.js-timeConvertFrom').val('') row.find('.js-timeConvertTo').val('') + row.find('.help-inline').empty() + row.removeClass('has-error') ) # convert hours into minutes item.find('.js-timeConvertFrom').bind('keyup focus blur', (e) => element = $(e.target) inText = element.val() + row = element.closest('tr') - dest = element.closest('td').find('.js-timeConvertTo') - inMinutes = @toMinutes(inText) - if !inMinutes - element.addClass('has-error') - dest.val('') - else - element.removeClass('has-error') - dest.val(inMinutes) row.find('.js-activateRow').prop('checked', true) row.addClass('is-active') + + element + .closest('td') + .find('.js-timeConvertTo') + .val(@toMinutes(inText) || '') + ) + + # toggle row on clicking name cell + item.find('.js-forward-click').bind('click', (e) -> + $(e.currentTarget).closest('tr').find('.checkbox-replacement').click() + ) + + # focus time input on clicking surrounding cell + item.find('.js-focus-input').bind('click', (e) -> + $(e.currentTarget).find('.form-control').focus() + ) + + # show placeholder instead of 00:00 + item.find('.js-timeConvertFrom').bind('changeTime.timepicker', (e) -> + if $(e.currentTarget).val() == '00:00' + $(e.currentTarget).val('') ) # set initial active/inactive rows item.find('.js-timeConvertFrom').each(-> - row = $(@).closest('tr').find('.js-activateRow') + row = $(@).closest('tr') + checkbox = row.find('.js-activateRow') if $(@).val() - row.prop('checked', true) + checkbox.prop('checked', true) + row.addClass('is-active') else - row.prop('checked', false) + checkbox.prop('checked', false) ) item @@ -69,6 +86,7 @@ class App.UiElement.sla_times minute = parseInt(hh[1]) return if hour is NaN return if minute is NaN + return if hour is 0 and minute is 0 (hour * 60) + minute @toText: (m) -> diff --git a/app/assets/javascripts/app/models/sla.coffee b/app/assets/javascripts/app/models/sla.coffee index d6599c5d1..909f75da9 100644 --- a/app/assets/javascripts/app/models/sla.coffee +++ b/app/assets/javascripts/app/models/sla.coffee @@ -11,6 +11,9 @@ class App.Sla extends App.Model { name: 'created_at', display: 'Created', tag: 'datetime', readonly: 1 }, { name: 'updated_by_id', display: 'Updated by', relation: 'User', readonly: 1 }, { name: 'updated_at', display: 'Updated', tag: 'datetime', readonly: 1 }, + { name: 'first_response_time', null: false, skipRendering: true, required_if: { 'first_response_time_enabled': ['on'] } }, + { name: 'update_time', null: false, skipRendering: true, required_if: { 'update_time_enabled': ['on'] } }, + { name: 'solution_time', null: false, skipRendering: true, required_if: { 'solution_time_enabled': ['on'] } }, ] @configure_delete = true @configure_overview = [ @@ -23,4 +26,4 @@ class App.Sla extends App.Model It can be ** response time ** (time between the creation of a ticket and the first reaction of an agent), ** update time ** (time between a customer's request and an agent's reaction) and ** solution time ** (time between creation and closing a ticket ) To be defined. Any violations are displayed in a separate view in the overviews. You can also configure ** e-mail notifications **. -''' \ No newline at end of file +''' diff --git a/app/assets/javascripts/app/views/generic/sla_times.jst.eco b/app/assets/javascripts/app/views/generic/sla_times.jst.eco index e602fe6e7..98fe6ea21 100644 --- a/app/assets/javascripts/app/views/generic/sla_times.jst.eco +++ b/app/assets/javascripts/app/views/generic/sla_times.jst.eco @@ -6,48 +6,48 @@ <%- @T('Time') %> <%- @T('in hours') %> - + - - + +
<%- @T('First Response Time') %>

<%- @T('Timeframe for the first response.') %>

- + - + - + - - + +
<%- @T('Update Time') %>

<%- @T('Timeframe for every following response.') %>

- + - + - - + +
<%- @T('Solution Time') %>

<%- @T('Timeframe for solving the problem.') %>

- + - \ No newline at end of file + diff --git a/app/views/tests/form_skip_rendering.html.erb b/app/views/tests/form_skip_rendering.html.erb new file mode 100644 index 000000000..4338f5a29 --- /dev/null +++ b/app/views/tests/form_skip_rendering.html.erb @@ -0,0 +1,21 @@ + +<%= javascript_include_tag "/assets/tests/qunit-1.21.0.js", "/assets/tests/syn-0.14.1.js", "/assets/tests/form_skip_rendering.js", nonce: true %> + + + +<%= javascript_tag nonce: true do -%> +<% end -%> + +
+ +
+
+
+ +
+
+ diff --git a/app/views/tests/form_sla_times.html.erb b/app/views/tests/form_sla_times.html.erb new file mode 100644 index 000000000..2f161a66d --- /dev/null +++ b/app/views/tests/form_sla_times.html.erb @@ -0,0 +1,21 @@ + +<%= javascript_include_tag "/assets/tests/qunit-1.21.0.js", "/assets/tests/syn-0.14.1.js", "/assets/tests/form_sla_times.js", nonce: true %> + + + +<%= javascript_tag nonce: true do -%> +<% end -%> + +
+ +
+
+
+ +
+
+ diff --git a/config/routes/test.rb b/config/routes/test.rb index 6f3052c44..1a12eb804 100644 --- a/config/routes/test.rb +++ b/config/routes/test.rb @@ -20,6 +20,8 @@ Zammad::Application.routes.draw do match '/tests_form_column_select', to: 'tests#form_column_select', via: :get match '/tests_form_searchable_select', to: 'tests#form_searchable_select', via: :get match '/tests_form_ticket_perform_action', to: 'tests#form_ticket_perform_action', via: :get + match '/tests_form_sla_times', to: 'tests#form_sla_times', via: :get + match '/tests_form_skip_rendering', to: 'tests#form_skip_rendering', via: :get match '/tests_table', to: 'tests#table', via: :get match '/tests_table_extended', to: 'tests#table_extended', via: :get match '/tests_html_utils', to: 'tests#html_utils', via: :get diff --git a/public/assets/tests/form_extended.js b/public/assets/tests/form_extended.js index 8c652b0ce..7dda19d27 100644 --- a/public/assets/tests/form_extended.js +++ b/public/assets/tests/form_extended.js @@ -168,10 +168,13 @@ test('form checks', function() { priority4_id: '2', priority5_id: '1', first_response_time: '150', + first_response_time_enabled: 'on', first_response_time_in_text: '02:30', solution_time: '', + solution_time_enabled: undefined, solution_time_in_text: '', update_time: '45', + update_time_enabled: 'on', update_time_in_text: '00:45', working_hours: { mon: { @@ -313,10 +316,13 @@ test('form checks', function() { }, }, first_response_time: '30', + first_response_time_enabled: 'on', first_response_time_in_text: '00:30', solution_time: '', + solution_time_enabled: undefined, solution_time_in_text: '', update_time: '', + update_time_enabled: undefined, update_time_in_text: '', } deepEqual(params, test_params, 'form param check') diff --git a/public/assets/tests/form_skip_rendering.js b/public/assets/tests/form_skip_rendering.js new file mode 100644 index 000000000..0339c9923 --- /dev/null +++ b/public/assets/tests/form_skip_rendering.js @@ -0,0 +1,19 @@ +test("form elements not rendered", function(assert) { + $('#forms').append('

form elements check

') + + var el = $('#form1') + + new App.ControllerForm({ + el: el, + model: { + configure_attributes: [ + { name: 'shown', display: 'Shown', tag: 'input' }, + { name: 'hidden', display: 'Hidden', tag: 'input', skipRendering: true } + ] + }, + autofocus: true + }); + + ok(el.find('input[name=shown]').get(0), 'control element is visible') + notOk(el.find('input[name=hidden]').get(0), 'element with skipRendering is not shown') +}); diff --git a/public/assets/tests/form_sla_times.js b/public/assets/tests/form_sla_times.js new file mode 100644 index 000000000..edc5d4c3c --- /dev/null +++ b/public/assets/tests/form_sla_times.js @@ -0,0 +1,117 @@ +test("form SLA times highlights first row and sets 2:00 by default for new item", function(assert) { + $('#forms').append('

SLA with defaults

') + + var el = $('#form1') + + var item = new App.Sla() + + new App.ControllerForm({ + el: el, + model: item.constructor, + params: item + }); + + var row = el.find('.sla_times tbody > tr:first') + + ok(row.hasClass('is-active')) + equal(row.find('input[data-name=first_response_time]').val(), '02:00') + + $('#forms').append('

SLA with empty times

') + + var el = $('#form2') + + var item = new App.Sla() + item.id = '123' + + new App.ControllerForm({ + el: el, + model: item.constructor, + params: item + }); + + var row = el.find('.sla_times tbody > tr:first') + + notOk(row.hasClass('is-active')) + equal(row.find('input[data-name=first_response_time]').val(), '') +}); + +test("form SLA times highlights and shows settings accordingly", function(assert) { + $('#forms').append('

SLA with non-first time set

') + + var el = $('#form3') + + var item = new App.Sla() + item.id = '123' + item.update_time = 240 + + new App.ControllerForm({ + el: el, + model: item.constructor, + params: item + }); + + var firstRow = el.find('.sla_times tbody > tr:first') + var secondRow = el.find('.sla_times tbody > tr:nth-child(2)') + + notOk(firstRow.hasClass('is-active')) + equal(firstRow.find('input[data-name=first_response_time]').val(), '') + ok(secondRow.hasClass('is-active')) + equal(secondRow.find('input[data-name=update_time]').val(), '04:00') +}) + +test("form SLA times highlights errors when submitting empty active row", function(assert) { + $('#forms').append('

SLA error handling

') + + var el = $('#form4') + + var item = new App.Sla() + item.id = '123' + item.update_time = 240 + + new App.ControllerForm({ + el: el, + model: item.constructor, + params: item + }); + + var row = el.find('.sla_times tbody > tr:nth-child(2)') + var input = row.find('input[data-name=update_time]') + input.val('').trigger('blur') + + item.load(App.ControllerForm.params(el)) + + App.ControllerForm.validate({form: el, errors: item.validate()}) + + equal(input.css('border-top-color'), 'rgb(255, 0, 0)', 'highlighted as error') // checking border-color fails on Firefox + + var anotherRow = el.find('.sla_times tbody > tr:nth-child(3)') + var anotherInput = anotherRow.find('input[data-name=update_time]') + + notEqual(anotherInput.css('border-color'), 'rgb(255, 0, 0)', 'not highlighted as error') + + row.find('td:nth-child(2)').click() + notOk(row.hasClass('is-active'), 'deactivates class by clicking on name cell)') + + notEqual(input.css('border-color'), 'rgb(255, 0, 0)', 'error cleared by deactivating') +}) + +test("form SLA times clears field instead of 00:00", function(assert) { + $('#forms').append('

SLA placeholder instead of 00:00

') + + var el = $('#form5') + + var item = new App.Sla() + + new App.ControllerForm({ + el: el, + model: item.constructor, + params: item + }); + + var row = el.find('.sla_times tbody > tr:nth-child(2)') + var input = row.find('input[data-name=update_time]') + + input.val('asd').blur() + + equal(input.val(), '', 'shows placeholder') +}); diff --git a/spec/system/js/q_unit_spec.rb b/spec/system/js/q_unit_spec.rb index 1905ed2bf..1ad1d3251 100644 --- a/spec/system/js/q_unit_spec.rb +++ b/spec/system/js/q_unit_spec.rb @@ -109,6 +109,14 @@ RSpec.describe 'QUnit', type: :system, authenticated: false, set_up: true, webso it 'Validation' do q_unit_tests('form_validation') end + + it 'Skip rendering' do + q_unit_tests('form_skip_rendering') + end + + it 'SLA times' do + q_unit_tests('form_sla_times') + end end context 'Table' do