From 4324db9b9f386988470c9219b5b156957baba7b5 Mon Sep 17 00:00:00 2001 From: Martin Edenhofer Date: Mon, 14 Mar 2016 00:25:05 +0100 Subject: [PATCH] Improved ticket selector. Added browser tests. --- .../_ui_element/ticket_perform_action.coffee | 236 ++++++++++----- .../_ui_element/ticket_selector.coffee | 269 +++++++++-------- .../generic/ticket_perform_action.jst.eco | 13 +- .../app/views/generic/time_range.jst.eco | 2 +- app/models/overview.rb | 5 +- public/assets/tests/form_extended.js | 283 ++++++++++++------ script/build/test_slice_tests.sh | 2 + test/browser/admin_overview_test.rb | 41 +++ test/browser_test_helper.rb | 85 +++++- 9 files changed, 642 insertions(+), 294 deletions(-) create mode 100644 test/browser/admin_overview_test.rb diff --git a/app/assets/javascripts/app/controllers/_ui_element/ticket_perform_action.coffee b/app/assets/javascripts/app/controllers/_ui_element/ticket_perform_action.coffee index ea6562a43..187ee15a0 100644 --- a/app/assets/javascripts/app/controllers/_ui_element/ticket_perform_action.coffee +++ b/app/assets/javascripts/app/controllers/_ui_element/ticket_perform_action.coffee @@ -8,9 +8,6 @@ class App.UiElement.ticket_perform_action name: 'Ticket' model: 'Ticket' - operators = - 'ticket.tags': ['add', 'remove'] - # megre config elements = {} for groupKey, groupMeta of groups @@ -22,13 +19,15 @@ class App.UiElement.ticket_perform_action # ignore readonly attributes if !row.readonly config = _.clone(row) + if config.tag is 'tag' + config.operator = ['add', 'remove'] elements["#{groupKey}.#{config.name}"] = config - [defaults, groups, operators, elements] + [defaults, groups, elements] @render: (attribute, params = {}) -> - [defaults, groups, operators, elements] = @defaults() + [defaults, groups, elements] = @defaults() selector = @buildAttributeSelector(groups, elements) @@ -42,22 +41,22 @@ class App.UiElement.ticket_perform_action elementClone = element.clone(true) element.after(elementClone) elementClone.find('.js-attributeSelector select').trigger('change') + @updateAttributeSelectors(item) ) # remove filter item.find('.js-remove').bind('click', (e) => + return if $(e.currentTarget).hasClass('is-disabled') $(e.target).closest('.js-filterElement').remove() - @rebuildAttributeSelectors(item) + @updateAttributeSelectors(item) ) # change attribute selector item.find('.js-attributeSelector select').bind('change', (e) => - groupAndAttribute = $(e.target).find('option:selected').attr('value') elementRow = $(e.target).closest('.js-filterElement') - - @rebuildAttributeSelectors(item, elementRow, groupAndAttribute) - @buildOperator(item, elementRow, groupAndAttribute, elements, undefined, attribute, operators) - @buildValue(item, elementRow, groupAndAttribute, elements, undefined, attribute) + groupAndAttribute = elementRow.find('.js-attributeSelector option:selected').attr('value') + @rebuildAttributeSelectors(item, elementRow, groupAndAttribute, elements, {}, attribute) + @updateAttributeSelectors(item) ) # build inital params @@ -75,9 +74,7 @@ class App.UiElement.ticket_perform_action # clone, rebuild and append elementClone = elementFirst.clone(true) - @rebuildAttributeSelectors(item, elementClone, groupAndAttribute) - @buildOperator(item, elementClone, groupAndAttribute, elements, value, attribute, operators, operator) - @buildValue(item, elementClone, groupAndAttribute, elements, value, attribute) + @rebuildAttributeSelectors(item, elementClone, groupAndAttribute, elements, meta, attribute) elementLast.after(elementClone) # remove first dummy row @@ -85,7 +82,7 @@ class App.UiElement.ticket_perform_action item.find('.js-filterElement').first().remove() else - for default_row in defaults + for groupAndAttribute in defaults # get selector rows elementFirst = item.find('.js-filterElement').first() @@ -93,64 +90,28 @@ class App.UiElement.ticket_perform_action # clone, rebuild and append elementClone = elementFirst.clone(true) - @rebuildAttributeSelectors(item, elementClone, default_row) + @rebuildAttributeSelectors(item, elementClone, groupAndAttribute, elements, {}, attribute) + elementLast.after(elementClone) item.find('.js-filterElement').first().remove() + # change attribute selector + item.find('.js-attributeSelector select').bind('change', (e) => + elementRow = $(e.target).closest('.js-filterElement') + groupAndAttribute = elementRow.find('.js-attributeSelector option:selected').attr('value') + @rebuildAttributeSelectors(item, elementRow, groupAndAttribute, elements, {}, attribute) + @updateAttributeSelectors(item) + ) + + # change operator selector + item.on('change', '.js-operator select', (e) => + elementRow = $(e.target).closest('.js-filterElement') + groupAndAttribute = elementRow.find('.js-attributeSelector option:selected').attr('value') + @buildOperator(item, elementRow, groupAndAttribute, elements, {}, attribute) + ) + item - @buildOperator: (elementFull, elementRow, groupAndAttribute, elements, value, attribute, operators, operator) -> - name = "#{attribute.name}::#{groupAndAttribute}::operator" - if !operators[groupAndAttribute] - elementRow.find('.js-operator').html('') - return - - # get current operator - if !operator - operator = elementRow.find('.js-operator select').val() - - # build new operator - selection = $("") - for operatorKey in operators[groupAndAttribute] - operatorKeyName = App.i18n.translateInline(operatorKey) - selected = '' - if operatorKey is operator - selected = 'selected' - selection.append("") - elementRow.find('.js-operator').html(selection) - - @buildValue: (elementFull, elementRow, groupAndAttribute, elements, value, attribute) -> - - # do nothing if item already exists - name = "#{attribute.name}::#{groupAndAttribute}::value" - return if elementRow.find("[name=\"#{name}\"]").get(0) - return if elementRow.find("[data-name=\"#{name}\"]").get(0) - - # build new item - attributeConfig = elements[groupAndAttribute] - config = _.clone(attributeConfig) - - # force to use auto compition on user lookup - if config.relation is 'User' - config.tag = 'user_autocompletion' - - # render ui element - item = '' - if config && App.UiElement[config.tag] - config['name'] = name - config['value'] = value - if 'multiple' of config - config.multiple = false - config.nulloption = false - if config.tag is 'checkbox' - config.tag = 'select' - tagSearch = "#{config.tag}_search" - if App.UiElement[tagSearch] - item = App.UiElement[tagSearch].render(config, {}) - else - item = App.UiElement[config.tag].render(config, {}) - elementRow.find('.js-value').html(item) - @buildAttributeSelector: (groups, elements) -> selection = $('') for groupKey, groupMeta of groups @@ -165,7 +126,7 @@ class App.UiElement.ticket_perform_action optgroup.append("") selection - @rebuildAttributeSelectors: (elementFull, elementRow, groupAndAttribute) -> + @updateAttributeSelectors: (elementFull) -> # enable all elementFull.find('.js-attributeSelector select option').removeAttr('disabled') @@ -182,10 +143,147 @@ class App.UiElement.ticket_perform_action else elementFull.find('.js-remove').addClass('is-disabled') + @rebuildAttributeSelectors: (elementFull, elementRow, groupAndAttribute, elements, meta, attribute) -> + console.log('aa', groupAndAttribute, meta) # set attribute if groupAndAttribute elementRow.find('.js-attributeSelector select').val(groupAndAttribute) + @buildOperator(elementFull, elementRow, groupAndAttribute, elements, meta, attribute) + + @buildOperator: (elementFull, elementRow, groupAndAttribute, elements, meta, attribute) -> + currentOperator = elementRow.find('.js-operator option:selected').attr('value') + + if !meta.operator + meta.operator = currentOperator + + name = "#{attribute.name}::#{groupAndAttribute}::operator" + + selection = $("") + + attributeConfig = elements[groupAndAttribute] + + if !attributeConfig.operator + elementRow.find('.js-operator').addClass('hide') + else + elementRow.find('.js-operator').removeClass('hide') + if attributeConfig.operator + for operator in attributeConfig.operator + operatorName = App.i18n.translateInline(operator) + selected = '' + if meta.operator is operator + selected = 'selected="selected"' + selection.append("") + selection + + elementRow.find('.js-operator select').replaceWith(selection) + + @buildPreCondition(elementFull, elementRow, groupAndAttribute, elements, meta, attribute) + + @buildPreCondition: (elementFull, elementRow, groupAndAttribute, elements, meta, attributeConfig) -> + currentOperator = elementRow.find('.js-operator option:selected').attr('value') + currentPreCondition = elementRow.find('.js-preCondition option:selected').attr('value') + + if !meta.pre_condition + meta.pre_condition = currentPreCondition + + toggleValue = => + preCondition = elementRow.find('.js-preCondition option:selected').attr('value') + if preCondition isnt 'specific' + elementRow.find('.js-value select').html('') + elementRow.find('.js-value').addClass('hide') + else + elementRow.find('.js-value').removeClass('hide') + @buildValue(elementFull, elementRow, groupAndAttribute, elements, meta, attribute) + + # force to use auto complition on user lookup + attribute = _.clone(attributeConfig) + + name = "#{attribute.name}::#{groupAndAttribute}::value" + attributeSelected = elements[groupAndAttribute] + + preCondition = false + if attributeSelected.relation is 'User' + preCondition = 'user' + attribute.tag = 'user_autocompletion' + if attributeSelected.relation is 'Organization' + preCondition = 'org' + attribute.tag = 'autocompletion_ajax' + if !preCondition + elementRow.find('.js-preCondition select').html('') + elementRow.find('.js-preCondition').addClass('hide') + toggleValue() + @buildValue(elementFull, elementRow, groupAndAttribute, elements, meta, attribute) + return + + elementRow.find('.js-preCondition').removeClass('hide') + name = "#{attribute.name}::#{groupAndAttribute}::pre_condition" + + selection = $("") + options = {} + if preCondition is 'user' + options = + 'current_user.id': App.i18n.translateInline('current user') + 'specific': App.i18n.translateInline('specific user') + #'set': App.i18n.translateInline('set') + else if preCondition is 'org' + options = + 'current_user.organization_id': App.i18n.translateInline('current user organization') + 'specific': App.i18n.translateInline('specific organization') + #'set': App.i18n.translateInline('set') + + for key, value of options + selected = '' + if key is meta.pre_condition + selected = 'selected="selected"' + selection.append("") + elementRow.find('.js-preCondition').removeClass('hide') + elementRow.find('.js-preCondition select').replaceWith(selection) + + elementRow.find('.js-preCondition select').bind('change', (e) -> + toggleValue() + ) + + @buildValue(elementFull, elementRow, groupAndAttribute, elements, meta, attribute) + toggleValue() + + @buildValue: (elementFull, elementRow, groupAndAttribute, elements, meta, attribute) -> + name = "#{attribute.name}::#{groupAndAttribute}::value" + + # build new item + attributeConfig = elements[groupAndAttribute] + config = _.clone(attributeConfig) + + if config.relation is 'User' + config.tag = 'user_autocompletion' + if config.relation is 'Organization' + config.tag = 'autocompletion_ajax' + + # render ui element + item = '' + if config && App.UiElement[config.tag] + config['name'] = name + if attribute.value && attribute.value[groupAndAttribute] + config['value'] = _.clone(attribute.value[groupAndAttribute]['value']) + config.multiple = false + config.nulloption = false + if config.tag is 'checkbox' + config.tag = 'select' + tagSearch = "#{config.tag}_search" + if App.UiElement[tagSearch] + item = App.UiElement[tagSearch].render(config, {}) + else + item = App.UiElement[config.tag].render(config, {}) + if meta.operator is 'before (relative)' || meta.operator is 'within next (relative)' || meta.operator is 'within last (relative)' || meta.operator is 'after (relative)' + config['name'] = "#{attribute.name}::#{groupAndAttribute}" + if attribute.value && attribute.value[groupAndAttribute] + config['value'] = _.clone(attribute.value[groupAndAttribute]) + item = App.UiElement['time_range'].render(config, {}) + + elementRow.find('.js-value').removeClass('hide').html(item) + + + @humanText: (condition) -> none = App.i18n.translateContent('No filter.') return [none] if _.isEmpty(condition) diff --git a/app/assets/javascripts/app/controllers/_ui_element/ticket_selector.coffee b/app/assets/javascripts/app/controllers/_ui_element/ticket_selector.coffee index a71e02224..54fb79081 100644 --- a/app/assets/javascripts/app/controllers/_ui_element/ticket_selector.coffee +++ b/app/assets/javascripts/app/controllers/_ui_element/ticket_selector.coffee @@ -64,34 +64,23 @@ class App.UiElement.ticket_selector elementClone = element.clone(true) element.after(elementClone) elementClone.find('.js-attributeSelector select').trigger('change') + @updateAttributeSelectors(item) @preview(item) ) # remove filter item.find('.js-remove').bind('click', (e) => + return if $(e.currentTarget).hasClass('is-disabled') $(e.target).closest('.js-filterElement').remove() - @rebuildAttributeSelectors(item) + @updateAttributeSelectors(item) @preview(item) ) - # change attribute selector - item.find('.js-attributeSelector select').bind('change', (e) => - groupAndAttribute = $(e.target).find('option:selected').attr('value') - elementRow = $(e.target).closest('.js-filterElement') - - @rebuildAttributeSelectors(item, elementRow, groupAndAttribute) - @rebuildOperater(item, elementRow, groupAndAttribute, elements, undefined, attribute) - @buildValue(item, elementRow, groupAndAttribute, elements, undefined, undefined, attribute) - ) - # build inital params if !_.isEmpty(params[attribute.name]) - selectorExists = false for groupAndAttribute, meta of params[attribute.name] selectorExists = true - operator = meta.operator - value = meta.value # get selector rows elementFirst = item.find('.js-filterElement').first() @@ -99,9 +88,7 @@ class App.UiElement.ticket_selector # clone, rebuild and append elementClone = elementFirst.clone(true) - @rebuildAttributeSelectors(item, elementClone, groupAndAttribute) - @rebuildOperater(item, elementClone, groupAndAttribute, elements, operator, attribute) - @buildValue(item, elementClone, groupAndAttribute, elements, value, operator, attribute) + @rebuildAttributeSelectors(item, elementClone, groupAndAttribute, elements, meta, attribute) elementLast.after(elementClone) # remove first dummy row @@ -109,7 +96,7 @@ class App.UiElement.ticket_selector item.find('.js-filterElement').first().remove() else - for default_row in defaults + for groupAndAttribute in defaults # get selector rows elementFirst = item.find('.js-filterElement').first() @@ -117,7 +104,7 @@ class App.UiElement.ticket_selector # clone, rebuild and append elementClone = elementFirst.clone(true) - @rebuildAttributeSelectors(item, elementClone, default_row) + @rebuildAttributeSelectors(item, elementClone, groupAndAttribute, elements, {}, attribute) elementLast.after(elementClone) item.find('.js-filterElement').first().remove() @@ -138,12 +125,25 @@ class App.UiElement.ticket_selector triggerSearch() ) + # change attribute selector + item.find('.js-attributeSelector select').bind('change', (e) => + elementRow = $(e.target).closest('.js-filterElement') + groupAndAttribute = elementRow.find('.js-attributeSelector option:selected').attr('value') + @rebuildAttributeSelectors(item, elementRow, groupAndAttribute, elements, {}, attribute) + @updateAttributeSelectors(item) + ) + + # change operator selector + item.on('change', '.js-operator select', (e) => + elementRow = $(e.target).closest('.js-filterElement') + groupAndAttribute = elementRow.find('.js-attributeSelector option:selected').attr('value') + @buildOperator(item, elementRow, groupAndAttribute, elements, {}, attribute) + ) + item @preview: (item) -> params = App.ControllerForm.params(item) - - # ajax call App.Ajax.request( id: 'ticket_selector' type: 'POST' @@ -151,7 +151,7 @@ class App.UiElement.ticket_selector data: JSON.stringify(params) processData: true, success: (data, status, xhr) => - App.Collection.loadAssets( data.assets ) + App.Collection.loadAssets(data.assets) item.find('.js-previewCounterContainer').removeClass('hide') item.find('.js-previewLoader').addClass('hide') @ticketTable(data.ticket_ids, data.ticket_count, item) @@ -164,92 +164,6 @@ class App.UiElement.ticket_selector ticket_ids: ticket_ids ) - @buildValue: (elementFull, elementRow, groupAndAttribute, elements, value, operator, attribute) -> - - # do nothing if item already exists - operator = elementRow.find('.js-operator option:selected').attr('value') - name = "#{attribute.name}::#{groupAndAttribute}::value" - - # build new item - attributeConfig = elements[groupAndAttribute] - config = _.clone(attributeConfig) - - # force to use auto complition on user lookup - config.preCondition = false - if config.relation is 'User' - config.preCondition = 'user' - config.tag = 'user_autocompletion' - if config.relation is 'Organization' - config.tag = 'autocompletion_ajax' - config.preCondition = 'org' - - @buildPreCondition(config, elementFull, elementRow, groupAndAttribute, attribute) - - # render ui element - item = '' - if config && App.UiElement[config.tag] - config['name'] = name - if attribute.value && attribute.value[groupAndAttribute] - config['value'] = _.clone(attribute.value[groupAndAttribute]['value']) - if 'multiple' of config - config.multiple = true - config.nulloption = false - if config.tag is 'checkbox' - config.tag = 'select' - tagSearch = "#{config.tag}_search" - if App.UiElement[tagSearch] - item = App.UiElement[tagSearch].render(config, {}) - else - item = App.UiElement[config.tag].render(config, {}) - - if operator is 'before (relative)' || operator is 'within next (relative)' || operator is 'within last (relative)' || operator is 'after (relative)' - config['name'] = "#{attribute.name}::#{groupAndAttribute}" - config['value'] = _.clone(attribute.value[groupAndAttribute]) - item = App.UiElement['time_range'].render(config, {}) - - elementRow.find('.js-value').html(item) - - @buildPreCondition: (config, elementFull, elementRow, groupAndAttribute, attribute) -> - if !config.preCondition - elementRow.find('.js-preCondition').addClass('hide') - return - - name = "#{attribute.name}::#{groupAndAttribute}::pre_condition" - preConditionCurrent = elementRow.find('.js-preCondition option:selected').attr('value') - if !preCondition && attribute.value && attribute.value[groupAndAttribute] - preCondition = attribute.value[groupAndAttribute].pre_condition - selection = $("") - options = {} - if config.preCondition is 'user' - options = - 'set': App.i18n.translateInline('set') - 'current_user.id': App.i18n.translateInline('current user') - 'specific': App.i18n.translateInline('specific user') - else if config.preCondition is 'org' - options = - 'set': App.i18n.translateInline('set') - 'current_user.organization_id': App.i18n.translateInline('current user organization') - 'specific': App.i18n.translateInline('specific organization') - for key, value of options - selected = preConditionCurrent - if key is preCondition - selected = 'selected="selected"' - selection.append("") - elementRow.find('.js-preCondition').removeClass('hide') - elementRow.find('.js-preCondition select').replaceWith(selection) - - toggle = -> - preCondition = elementRow.find('.js-preCondition option:selected').attr('value') - if preCondition is 'specific' - elementRow.find('.js-value').removeClass('hide') - else - elementRow.find('.js-value').addClass('hide') - toggle() - - elementRow.find('.js-preCondition select').bind('change', (e) -> - toggle() - ) - @buildAttributeSelector: (groups, elements) -> selection = $('') for groupKey, groupMeta of groups @@ -265,7 +179,7 @@ class App.UiElement.ticket_selector optgroup.append("") selection - @rebuildAttributeSelectors: (elementFull, elementRow, groupAndAttribute) -> + @updateAttributeSelectors: (elementFull) -> # enable all elementFull.find('.js-attributeSelector select option').removeAttr('disabled') @@ -282,41 +196,142 @@ class App.UiElement.ticket_selector else elementFull.find('.js-remove').addClass('is-disabled') + + @rebuildAttributeSelectors: (elementFull, elementRow, groupAndAttribute, elements, meta, attribute) -> + # set attribute if groupAndAttribute elementRow.find('.js-attributeSelector select').val(groupAndAttribute) - @buildOperator: (elementFull, elementRow, groupAndAttribute, elements, current_operator, attribute) -> - selection = $("") + @buildOperator(elementFull, elementRow, groupAndAttribute, elements, meta, attribute) + + @buildOperator: (elementFull, elementRow, groupAndAttribute, elements, meta, attribute) -> + currentOperator = elementRow.find('.js-operator option:selected').attr('value') + + if !meta.operator + meta.operator = currentOperator + + name = "#{attribute.name}::#{groupAndAttribute}::operator" + + selection = $("") attributeConfig = elements[groupAndAttribute] if attributeConfig.operator for operator in attributeConfig.operator operatorName = App.i18n.translateInline(operator) selected = '' - if current_operator is operator + if meta.operator is operator selected = 'selected="selected"' selection.append("") selection - @rebuildOperater: (elementFull, elementRow, groupAndAttribute, elements, current_operator, attribute) -> - return if !groupAndAttribute + elementRow.find('.js-operator select').replaceWith(selection) - # do nothing if item already exists - name = "#{attribute.name}::#{groupAndAttribute}::operator" - return if elementRow.find("[name=\"#{name}\"]").get(0) + @buildPreCondition(elementFull, elementRow, groupAndAttribute, elements, meta, attribute) - # render new operator - operator = @buildOperator(elementFull, elementRow, groupAndAttribute, elements, current_operator, attribute) - elementRow.find('.js-operator select').replaceWith(operator) + @buildPreCondition: (elementFull, elementRow, groupAndAttribute, elements, meta, attributeConfig) -> + currentOperator = elementRow.find('.js-operator option:selected').attr('value') + currentPreCondition = elementRow.find('.js-preCondition option:selected').attr('value') - # render not value option - elementRow.find('.js-operator select').bind('change', (e) => - groupAndAttribute = elementRow.find('.js-attributeSelector option:selected').attr('value') - operator = elementRow.find('.js-operator option:selected').attr('value') - @buildValue(elementFull, elementRow, groupAndAttribute, elements, undefined, operator, attribute) + if !meta.pre_condition + meta.pre_condition = currentPreCondition + + toggleValue = => + preCondition = elementRow.find('.js-preCondition option:selected').attr('value') + if preCondition isnt 'specific' + elementRow.find('.js-value select').html('') + elementRow.find('.js-value').addClass('hide') + else + elementRow.find('.js-value').removeClass('hide') + @buildValue(elementFull, elementRow, groupAndAttribute, elements, meta, attribute) + + # force to use auto complition on user lookup + attribute = _.clone(attributeConfig) + + name = "#{attribute.name}::#{groupAndAttribute}::value" + attributeSelected = elements[groupAndAttribute] + + preCondition = false + if attributeSelected.relation is 'User' + preCondition = 'user' + attribute.tag = 'user_autocompletion' + if attributeSelected.relation is 'Organization' + preCondition = 'org' + attribute.tag = 'autocompletion_ajax' + if !preCondition + elementRow.find('.js-preCondition select').html('') + elementRow.find('.js-preCondition').addClass('hide') + toggleValue() + @buildValue(elementFull, elementRow, groupAndAttribute, elements, meta, attribute) + return + + elementRow.find('.js-preCondition').removeClass('hide') + name = "#{attribute.name}::#{groupAndAttribute}::pre_condition" + + selection = $("") + options = {} + if preCondition is 'user' + options = + 'current_user.id': App.i18n.translateInline('current user') + 'specific': App.i18n.translateInline('specific user') + #'set': App.i18n.translateInline('set') + else if preCondition is 'org' + options = + 'current_user.organization_id': App.i18n.translateInline('current user organization') + 'specific': App.i18n.translateInline('specific organization') + #'set': App.i18n.translateInline('set') + + for key, value of options + selected = '' + if key is meta.pre_condition + selected = 'selected="selected"' + selection.append("") + elementRow.find('.js-preCondition').removeClass('hide') + elementRow.find('.js-preCondition select').replaceWith(selection) + + elementRow.find('.js-preCondition select').bind('change', (e) -> + toggleValue() ) + @buildValue(elementFull, elementRow, groupAndAttribute, elements, meta, attribute) + toggleValue() + + @buildValue: (elementFull, elementRow, groupAndAttribute, elements, meta, attribute) -> + name = "#{attribute.name}::#{groupAndAttribute}::value" + + # build new item + attributeConfig = elements[groupAndAttribute] + config = _.clone(attributeConfig) + + if config.relation is 'User' + config.tag = 'user_autocompletion' + if config.relation is 'Organization' + config.tag = 'autocompletion_ajax' + + # render ui element + item = '' + if config && App.UiElement[config.tag] + config['name'] = name + if attribute.value && attribute.value[groupAndAttribute] + config['value'] = _.clone(attribute.value[groupAndAttribute]['value']) + if 'multiple' of config + config.multiple = true + config.nulloption = false + if config.tag is 'checkbox' + config.tag = 'select' + tagSearch = "#{config.tag}_search" + if App.UiElement[tagSearch] + item = App.UiElement[tagSearch].render(config, {}) + else + item = App.UiElement[config.tag].render(config, {}) + if meta.operator is 'before (relative)' || meta.operator is 'within next (relative)' || meta.operator is 'within last (relative)' || meta.operator is 'after (relative)' + config['name'] = "#{attribute.name}::#{groupAndAttribute}" + if attribute.value && attribute.value[groupAndAttribute] + config['value'] = _.clone(attribute.value[groupAndAttribute]) + item = App.UiElement['time_range'].render(config, {}) + + elementRow.find('.js-value').removeClass('hide').html(item) + @humanText: (condition) -> none = App.i18n.translateContent('No filter.') return [none] if _.isEmpty(condition) @@ -354,5 +369,5 @@ class App.UiElement.ticket_selector data = App[config.relation].fullLocal(value) return value if !data if data.displayName - return App.i18n.translateContent( data.displayName() ) - valueHuman.push App.i18n.translateContent( data.name ) + return App.i18n.translateContent(data.displayName()) + valueHuman.push App.i18n.translateContent(data.name) diff --git a/app/assets/javascripts/app/views/generic/ticket_perform_action.jst.eco b/app/assets/javascripts/app/views/generic/ticket_perform_action.jst.eco index 4f9566af6..c30b659e0 100644 --- a/app/assets/javascripts/app/views/generic/ticket_perform_action.jst.eco +++ b/app/assets/javascripts/app/views/generic/ticket_perform_action.jst.eco @@ -6,7 +6,18 @@ <%- @Icon('arrow-down', 'dropdown-arrow') %> -
+
+
+ + <%- @Icon('arrow-down', 'dropdown-arrow') %> +
+
+
+
+ + <%- @Icon('arrow-down', 'dropdown-arrow') %> +
+
diff --git a/app/assets/javascripts/app/views/generic/time_range.jst.eco b/app/assets/javascripts/app/views/generic/time_range.jst.eco index ba3cf44e8..16587f36e 100644 --- a/app/assets/javascripts/app/views/generic/time_range.jst.eco +++ b/app/assets/javascripts/app/views/generic/time_range.jst.eco @@ -1,7 +1,7 @@
<%- @Icon('arrow-down', 'dropdown-arrow') %> diff --git a/app/models/overview.rb b/app/models/overview.rb index 35bbe97db..521c9328c 100644 --- a/app/models/overview.rb +++ b/app/models/overview.rb @@ -5,7 +5,6 @@ class Overview < ApplicationModel store :order store :view validates :name, presence: true - validates :prio, presence: true before_create :fill_link_on_create, :fill_prio before_update :fill_link_on_update @@ -16,8 +15,8 @@ class Overview < ApplicationModel private def fill_prio - return true if prio - prio = 9999 + return true if !prio.empty? + self.prio = 9999 end def fill_link_on_create diff --git a/public/assets/tests/form_extended.js b/public/assets/tests/form_extended.js index 1e688067e..ffcffe6e8 100644 --- a/public/assets/tests/form_extended.js +++ b/public/assets/tests/form_extended.js @@ -1,6 +1,6 @@ // form -test( 'form checks', function() { +test('form checks', function() { App.TicketPriority.refresh([ { @@ -54,8 +54,9 @@ test( 'form checks', function() { }, ]) - $('#forms').append('

form time check

') + /* working hours and escalation_times */ + $('#forms').append('

form condition check

') var el = $('#form1') var defaults = { working_hours: { @@ -106,42 +107,6 @@ test( 'form checks', function() { first_response_time: 150, solution_time: '', update_time: 45, - conditions: { - 'ticket.title': { - operator: 'contains', - value: 'some title', - }, - 'ticket.priority_id': { - operator: 'is', - value: [1,2,3], - }, - 'ticket.created_at': { - operator: 'before (absolute)', - value: '2015-09-20T03:41:00.000Z', - }, - 'ticket.organization_id': { - operator: 'is not', - pre_condition: 'specific', - value: 12, - }, - 'ticket.owner_id': { - operator: 'is', - pre_condition: 'specific', - value: 47, - }, - }, - executions: { - 'ticket.title': { - value: 'some title new', - }, - 'ticket.priority_id': { - value: 3, - }, - 'ticket.tags': { - operator: 'remove', - value: 'tag1, tag2', - }, - }, } new App.ControllerForm({ el: el, @@ -149,15 +114,12 @@ test( 'form checks', function() { configure_attributes: [ { name: 'escalation_times', display: 'Times', tag: 'sla_times', null: true }, { name: 'working_hours', display: 'Hours', tag: 'business_hours', null: true }, - { name: 'conditions', display: 'Conditions', tag: 'ticket_selector', null: true }, - { name: 'executions', display: 'Executions', tag: 'ticket_perform_action', null: true }, ] }, params: defaults, autofocus: true - }); - - var params = App.ControllerForm.params( el ) + }) + var params = App.ControllerForm.params(el) var test_params = { first_response_time: '150', first_response_time_in_text: '02:30', @@ -165,43 +127,6 @@ test( 'form checks', function() { solution_time_in_text: '', update_time: '45', update_time_in_text: '00:45', - conditions: { - 'ticket.title': { - operator: 'contains', - value: 'some title', - }, - 'ticket.priority_id': { - operator: 'is', - value: ['1', '3'], - }, - 'ticket.created_at': { - operator: 'before (absolute)', - value: '2015-09-20T03:41:00.000Z', - }, - 'ticket.organization_id': { - operator: 'is not', - pre_condition: 'specific', - value: '12', - }, - 'ticket.owner_id': { - operator: 'is', - pre_condition: 'specific', - value: '47', - value_completion: 'Bob Smith ', - }, - }, - executions: { - 'ticket.title': { - value: 'some title new', - }, - 'ticket.priority_id': { - value: '3', - }, - 'ticket.tags': { - operator: 'remove', - value: 'tag1, tag2', - }, - }, working_hours: { mon: { active: true, @@ -248,17 +173,13 @@ test( 'form checks', function() { }, }, } - deepEqual( params, test_params, 'form param check' ); + deepEqual(params, test_params, 'form param check') // change sla times el.find('[name="first_response_time_in_text"]').val('0:30').trigger('blur') el.find('#update_time').click() - // change selector - el.find('[name="conditions::ticket.priority_id::value"]').closest('.js-filterElement').find('.js-remove').click() - el.find('[name="executions::ticket.title::value"]').closest('.js-filterElement').find('.js-remove').click() - - var params = App.ControllerForm.params( el ) + var params = App.ControllerForm.params(el) var test_params = { working_hours: { mon: { @@ -311,15 +232,125 @@ test( 'form checks', function() { solution_time_in_text: '', update_time: '', update_time_in_text: '', - conditions: { + } + deepEqual(params, test_params, 'form param check') + + + /* empty params or defaults */ + $('#forms').append('

form condition check

') + var el = $('#form2') + new App.ControllerForm({ + el: el, + model: { + configure_attributes: [ + { name: 'condition', display: 'Conditions', tag: 'ticket_selector', null: true }, + { name: 'executions', display: 'Executions', tag: 'ticket_perform_action', null: true }, + ] + }, + autofocus: true + }) + var params = App.ControllerForm.params(el) + var test_params = { + condition: { + 'ticket.state_id': { + operator: 'is', + value: '2', + }, + }, + executions: { + 'ticket.state_id': { + value: '2', + }, + }, + } + deepEqual(params, test_params, 'form param check'); + + /* with params or defaults */ + $('#forms').append('

form time check

') + var el = $('#form3') + var defaults = { + condition: { 'ticket.title': { operator: 'contains', value: 'some title', }, + 'ticket.priority_id': { + operator: 'is', + value: [1,2,3], + }, 'ticket.created_at': { operator: 'before (absolute)', value: '2015-09-20T03:41:00.000Z', }, + 'ticket.updated_at': { + operator: 'within last (relative)', + range: 'year', + value: 2, + }, + 'ticket.organization_id': { + operator: 'is not', + pre_condition: 'specific', + value: 12, + }, + 'ticket.owner_id': { + operator: 'is', + pre_condition: 'specific', + value: 47, + }, + 'ticket.created_by_id': { + operator: 'is', + pre_condition: 'current_user.id', + value: '', + }, + }, + executions: { + 'ticket.title': { + value: 'some title new', + }, + 'ticket.priority_id': { + value: 3, + }, + 'ticket.owner_id': { + pre_condition: 'specific', + value: 47, + }, + 'ticket.tags': { + operator: 'remove', + value: 'tag1, tag2', + }, + }, + } + new App.ControllerForm({ + el: el, + model: { + configure_attributes: [ + { name: 'condition', display: 'Conditions', tag: 'ticket_selector', null: true }, + { name: 'executions', display: 'Executions', tag: 'ticket_perform_action', null: true }, + ] + }, + params: defaults, + autofocus: true + }) + var params = App.ControllerForm.params(el) + var test_params = { + condition: { + 'ticket.title': { + operator: 'contains', + value: 'some title', + }, + 'ticket.priority_id': { + operator: 'is', + value: ['1', '3'], + }, + 'ticket.created_at': { + operator: 'before (absolute)', + value: '2015-09-20T03:41:00.000Z', + }, + 'ticket.updated_at': { + operator: 'within last (relative)', + range: 'year', + value: '2', + }, 'ticket.organization_id': { operator: 'is not', pre_condition: 'specific', @@ -331,8 +362,22 @@ test( 'form checks', function() { value: '47', value_completion: 'Bob Smith ', }, + 'ticket.created_by_id': { + operator: 'is', + pre_condition: 'current_user.id', + value: '', + value_completion: '' + }, }, executions: { + 'ticket.title': { + value: 'some title new', + }, + 'ticket.owner_id': { + pre_condition: 'specific', + value: '47', + value_completion: 'Bob Smith ' + }, 'ticket.priority_id': { value: '3', }, @@ -342,10 +387,66 @@ test( 'form checks', function() { }, }, } - deepEqual( params, test_params, 'form param check' ); + deepEqual(params, test_params, 'form param check') - //deepEqual( el.find('[name="times::days"]').val(), ['mon', 'wed'], 'check times::days value') - //equal( el.find('[name="times::hours"]').val(), 2, 'check times::hours value') - //equal( el.find('[name="times::minutes"]').val(), null, 'check times::minutes value') + // change selector + el.find('[name="condition::ticket.priority_id::value"]').closest('.js-filterElement').find('.js-remove').click() + el.find('[name="executions::ticket.title::value"]').closest('.js-filterElement').find('.js-remove').click() + + var params = App.ControllerForm.params(el) + var test_params = { + condition: { + 'ticket.title': { + operator: 'contains', + value: 'some title', + }, + 'ticket.created_at': { + operator: 'before (absolute)', + value: '2015-09-20T03:41:00.000Z', + }, + 'ticket.updated_at': { + operator: 'within last (relative)', + range: 'year', + value: '2', + }, + 'ticket.organization_id': { + operator: 'is not', + pre_condition: 'specific', + value: '12', + }, + 'ticket.owner_id': { + operator: 'is', + pre_condition: 'specific', + value: '47', + value_completion: 'Bob Smith ', + }, + 'ticket.created_by_id': { + operator: 'is', + pre_condition: 'current_user.id', + value: '', + value_completion: '' + }, + }, + executions: { + 'ticket.priority_id': { + value: '3', + }, + 'ticket.owner_id': { + pre_condition: 'specific', + value: '47', + value_completion: 'Bob Smith ' + }, + 'ticket.tags': { + operator: 'remove', + value: 'tag1, tag2', + }, + }, + } + deepEqual(params, test_params, 'form param check') + console.log('APO3', App.Organization.find(12)) + + //deepEqual(el.find('[name="times::days"]').val(), ['mon', 'wed'], 'check times::days value') + //equal(el.find('[name="times::hours"]').val(), 2, 'check times::hours value') + //equal(el.find('[name="times::minutes"]').val(), null, 'check times::minutes value') }); \ No newline at end of file diff --git a/script/build/test_slice_tests.sh b/script/build/test_slice_tests.sh index 39f34133d..674d1623f 100755 --- a/script/build/test_slice_tests.sh +++ b/script/build/test_slice_tests.sh @@ -6,6 +6,7 @@ if [ "$LEVEL" == '1' ]; then # no ticket action rm test/browser/admin_channel_email_test.rb + rm test/browser/admin_overview_test.rb rm test/browser/agent_user_profile_test.rb rm test/browser/agent_organization_profile_test.rb rm test/browser/agent_ticket_*.rb @@ -23,6 +24,7 @@ elif [ "$LEVEL" == '2' ]; then rm test/browser/aac_basic_richtext_test.rb rm test/browser/aab_basic_urls_test.rb rm test/browser/admin_channel_email_test.rb + rm test/browser/admin_overview_test.rb rm test/browser/agent_organization_profile_test.rb rm test/browser/agent_user_*.rb rm test/browser/auth_test.rb diff --git a/test/browser/admin_overview_test.rb b/test/browser/admin_overview_test.rb new file mode 100644 index 000000000..d04081298 --- /dev/null +++ b/test/browser/admin_overview_test.rb @@ -0,0 +1,41 @@ +# encoding: utf-8 +require 'browser_test_helper' + +class AdminOverviewTest < TestCase + def test_account_add + name = "some overview #{rand(99_999_999)}" + + @browser = browser_instance + login( + username: 'master@example.com', + password: 'test', + url: browser_url, + ) + tasks_close_all() + + # add new overview + overview_create( + data: { + name: name, + role: 'Agent', + selector: { + 'Priority' => '1 low', + }, + 'order::direction' => 'down', + } + ) + + # edit overview + overview_update( + data: { + name: name, + role: 'Agent', + selector: { + 'State' => 'new', + }, + 'order::direction' => 'up', + } + ) + end + +end diff --git a/test/browser_test_helper.rb b/test/browser_test_helper.rb index 392966931..de22a6bb4 100644 --- a/test/browser_test_helper.rb +++ b/test/browser_test_helper.rb @@ -1233,7 +1233,7 @@ wait untill text in selector disabppears =begin - username = overview_create( + overview_create( browser: browser1, data: { name: name, @@ -1241,7 +1241,6 @@ wait untill text in selector disabppears selector: { 'Priority': '1 low', }, - prio: 1000, 'order::direction' => 'down', } ) @@ -1278,6 +1277,7 @@ wait untill text in selector disabppears element = instance.find_elements(css: '.modal .ticket_selector .js-attributeSelector select')[0] dropdown = Selenium::WebDriver::Support::Select.new(element) dropdown.select_by(:text, key) + sleep 0.5 element = instance.find_elements(css: '.modal .ticket_selector .js-value select')[0] dropdown = Selenium::WebDriver::Support::Select.new(element) dropdown.deselect_all @@ -1309,6 +1309,87 @@ wait untill text in selector disabppears raise 'overview creation failed' end +=begin + + overview_update( + browser: browser1, + data: { + name: name, + role: 'Agent', + selector: { + 'Priority': '1 low', + }, + 'order::direction' => 'down', + } + ) + +=end + + def overview_update(params) + switch_window_focus(params) + log('overview_create', params) + + instance = params[:browser] || @browser + data = params[:data] + + instance.find_elements(css: 'a[href="#manage"]')[0].click + sleep 0.2 + instance.find_elements(css: 'a[href="#manage/overviews"]')[0].click + sleep 0.2 + #instance.find_elements(css: '#content a[data-type="new"]')[0].click + #sleep 2 + + instance.execute_script("$(\"#content td:contains('#{params[:name]}')\").first().click()") + sleep 2 + + if data[:name] + element = instance.find_elements(css: '.modal input[name=name]')[0] + element.clear + element.send_keys(data[:name]) + end + if data[:role] + element = instance.find_elements(css: '.modal select[name="role_id"]')[0] + dropdown = Selenium::WebDriver::Support::Select.new(element) + dropdown.select_by(:text, data[:role]) + end + + if data[:selector] + data[:selector].each {|key, value| + element = instance.find_elements(css: '.modal .ticket_selector .js-attributeSelector select')[0] + dropdown = Selenium::WebDriver::Support::Select.new(element) + dropdown.select_by(:text, key) + instance.execute_script("$('#content .modal .ticket_selector .js-attributeSelector select').first().trigger('change')") + element = instance.find_elements(css: '.modal .ticket_selector .js-value select')[0] + dropdown = Selenium::WebDriver::Support::Select.new(element) + dropdown.deselect_all + dropdown.select_by(:text, value) + } + end + + if data['order::direction'] + element = instance.find_elements(css: '.modal select[name="order::direction"]')[0] + dropdown = Selenium::WebDriver::Support::Select.new(element) + dropdown.select_by(:text, data['order::direction']) + end + + instance.find_elements(css: '.modal button.js-submit')[0].click + (1..12).each { + element = instance.find_elements(css: 'body')[0] + text = element.text + if text =~ /#{Regexp.quote(data[:name])}/ + assert(true, 'overview updated') + overview = { + name: name, + } + sleep 1 + return overview + end + sleep 1 + } + screenshot(browser: instance, comment: 'overview_update_failed') + raise 'overview update failed' + end + =begin ticket = ticket_create(