From 3fc3ad5e5a5bf52d741f2f23bc3ea97dccb44d7f Mon Sep 17 00:00:00 2001 From: Martin Edenhofer Date: Thu, 17 Sep 2015 03:04:16 +0200 Subject: [PATCH] Added preview for ticket selector. --- .../_ui_element/ticket_selector.js.coffee | 64 +++++++++++++++---- .../javascripts/app/models/sla.js.coffee | 16 ++--- .../app/views/generic/ticket_selector.jst.eco | 4 ++ app/controllers/tickets_controller.rb | 23 +++++++ app/models/ticket.rb | 46 +++++++++++++ config/routes/ticket.rb | 1 + 6 files changed, 133 insertions(+), 21 deletions(-) diff --git a/app/assets/javascripts/app/controllers/_ui_element/ticket_selector.js.coffee b/app/assets/javascripts/app/controllers/_ui_element/ticket_selector.js.coffee index 378333ff9..6eca4740a 100644 --- a/app/assets/javascripts/app/controllers/_ui_element/ticket_selector.js.coffee +++ b/app/assets/javascripts/app/controllers/_ui_element/ticket_selector.js.coffee @@ -1,4 +1,4 @@ -class App.UiElement.ticket_selector extends App.UiElement.ApplicationUiElement +class App.UiElement.ticket_selector @render: (attribute, params = {}) -> # list of attributes @@ -129,25 +129,19 @@ class App.UiElement.ticket_selector extends App.UiElement.ApplicationUiElement groupAndAttribute = $(e.target).find('option:selected').attr('value') elementRow = $(e.target).closest('.js-filterElement') - console.log('CHANGE', groupAndAttribute, $(e.target)) - @rebuildAttributeSelectors(item, elementRow, groupAndAttribute) @rebuildOperater(item, elementRow, groupAndAttribute, elements) @buildValue(item, elementRow, groupAndAttribute, elements) ) # build inital params - console.log('P', params) if !_.isEmpty(params.condition) selectorExists = false - for position of params.condition.attribute - - # get stored params - groupAndAttribute = params.condition.attribute[position] - if params.condition[groupAndAttribute] + for groupAndAttribute, meta of params.condition + if groupAndAttribute isnt 'attribute' selectorExists = true - operator = params.condition[groupAndAttribute].operator - value = params.condition[groupAndAttribute].value + operator = meta.operator + value = meta.value # get selector rows elementFirst = item.find('.js-filterElement').first() @@ -163,8 +157,49 @@ class App.UiElement.ticket_selector extends App.UiElement.ApplicationUiElement # remove first dummy row if selectorExists item.find('.js-filterElement').first().remove() + + # bind for preview + search = => + @preview(item) + item.on('change', 'select.form-control', (e) => + App.Delay.set( + search, + 600, + 'preview', + ) + ) + item.on('keyup', 'input.form-control', (e) => + App.Delay.set( + search, + 600, + 'preview', + ) + ) + item + @preview: (item) -> + params = App.ControllerForm.params(item) + + # ajax call + App.Ajax.request( + id: 'ticket_selector' + type: 'POST' + url: "#{App.Config.get('api_path')}/tickets/selector" + data: JSON.stringify(params) + processData: true, + success: (data, status, xhr) => + App.Collection.loadAssets( data.assets ) + @ticketTable(data.ticket_ids, data.ticket_count, item) + ) + + @ticketTable: (ticket_ids, ticket_count, item) => + item.find('.js-previewCounter').html(ticket_count) + new App.TicketList( + el: item.find('.js-previewTable') + ticket_ids: ticket_ids + ) + @getElementConfig: (groupAndAttribute, elements) -> for elementGroup, elementConfig of elements for elementKey, elementItem of elementConfig @@ -253,7 +288,8 @@ class App.UiElement.ticket_selector extends App.UiElement.ApplicationUiElement elementRow.find('.js-operator select').replaceWith(operator) @humanText: (condition) -> - return [] if _.isEmpty(condition) + none = App.i18n.translateContent('No filter.') + return [none] if _.isEmpty(condition) rules = [] for position of condition.attribute @@ -263,5 +299,7 @@ class App.UiElement.ticket_selector extends App.UiElement.ApplicationUiElement selectorExists = true operator = condition[groupAndAttribute].operator value = condition[groupAndAttribute].value - rules.push "Where #{groupAndAttribute} #{operator} #{value}." + rules.push "#{App.i18n.translateContent('Where')} #{App.i18n.translateContent(groupAndAttribute)} #{App.i18n.translateContent(operator)} #{App.i18n.translateContent(value)}." + + return [none] if _.isEmpty(rules) rules \ No newline at end of file diff --git a/app/assets/javascripts/app/models/sla.js.coffee b/app/assets/javascripts/app/models/sla.js.coffee index 102fa0992..aaf7d3ed8 100644 --- a/app/assets/javascripts/app/models/sla.js.coffee +++ b/app/assets/javascripts/app/models/sla.js.coffee @@ -3,14 +3,14 @@ class App.Sla extends App.Model @extend Spine.Model.Ajax @url: @apiPath + '/slas' @configure_attributes = [ - { name: 'name', display: 'Name', tag: 'input', type: 'text', limit: 100, null: false }, - { name: 'condition', display: 'Selector', tag: 'ticket_selector', null: false, note: 'Create rules that single out the tickets for the Service Level Agreement.' }, - { name: 'calendar_id', display: 'Calendar', tag: 'select', relation: 'Calendar', null: false }, - { name: 'sla_times', display: 'SLA Times', tag: 'sla_times', null: true }, - { name: 'created_by_id', display: 'Created by', relation: 'User', readonly: 1 }, - { 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: 'name', display: 'Name', tag: 'input', type: 'text', limit: 100, null: false }, + { name: 'condition', display: 'Ticket Selector', tag: 'ticket_selector', null: false, note: 'Create rules that single out the tickets for the Service Level Agreement.' }, + { name: 'calendar_id', display: 'Calendar', tag: 'select', relation: 'Calendar', null: false }, + { name: 'sla_times', display: 'SLA Times', tag: 'sla_times', null: true }, + { name: 'created_by_id', display: 'Created by', relation: 'User', readonly: 1 }, + { 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 }, ] @configure_delete = true @configure_overview = [ diff --git a/app/assets/javascripts/app/views/generic/ticket_selector.jst.eco b/app/assets/javascripts/app/views/generic/ticket_selector.jst.eco index edc7adf08..74f7825e8 100644 --- a/app/assets/javascripts/app/views/generic/ticket_selector.jst.eco +++ b/app/assets/javascripts/app/views/generic/ticket_selector.jst.eco @@ -23,4 +23,8 @@ + +
+

<%- @T('Preview') %> ? <%- @T('matches') %>

+
\ No newline at end of file diff --git a/app/controllers/tickets_controller.rb b/app/controllers/tickets_controller.rb index e7e0cb549..90e918d39 100644 --- a/app/controllers/tickets_controller.rb +++ b/app/controllers/tickets_controller.rb @@ -345,6 +345,29 @@ class TicketsController < ApplicationController } end + # GET /api/v1/tickets/selector + def selector + return if deny_if_not_role(Z_ROLENAME_ADMIN) + + ticket_count, tickets = Ticket.selectors(params[:condition], 6) + + assets = {} + ticket_ids = [] + if tickets + tickets.each do |ticket| + ticket_ids.push ticket.id + assets = ticket.assets(assets) + end + end + + # return result + render json: { + ticket_ids: ticket_ids, + ticket_count: ticket_count || 0, + assets: assets, + } + end + # GET /api/v1/ticket_stats def stats diff --git a/app/models/ticket.rb b/app/models/ticket.rb index 2ee46b9d3..867dd1f5e 100644 --- a/app/models/ticket.rb +++ b/app/models/ticket.rb @@ -268,6 +268,52 @@ returns false end + def self.selectors(selectors, limit = 10) + return if !selectors + query, bind_params = _selectors(selectors) + ticket_count = Ticket.where(query, *bind_params).count + tickets = Ticket.where(query, *bind_params).limit(limit) + [ticket_count, tickets] + end + + def self._selectors(selectors) + return if !selectors + query = '' + bind_params = [] + + selectors.each {|attribute, selector| + if query != '' + query += ' AND ' + end + next if !selector + next if !selector.respond_to?(:key?) + next if !selector['operator'] + return nil if !selector['value'] + return nil if selector['value'].respond_to?(:key?) && selector['value'].empty? + if selector['operator'] == 'is' + query += "#{attribute} IN (?)" + bind_params.push selector['value'] + elsif selector['operator'] == 'is not' + query += "#{attribute} NOT IN (?)" + bind_params.push selector['value'] + elsif selector['operator'] == 'contains' + query += "#{attribute} LIKE (?)" + value = "%#{selector['value']}%" + bind_params.push value + elsif selector['operator'] == 'contains not' + query += "#{attribute} NOT LIKE (?)" + value = "%#{selector['value']}%" + bind_params.push value + elsif selector['operator'] == 'before' + query += "#{attribute} <= (?)" + bind_params.push selector['value'] + else + fail "Invalid operator '#{selector['operator']}' for '#{selector['value'].inspect}'" + end + } + [query, bind_params] + end + private def check_generate diff --git a/config/routes/ticket.rb b/config/routes/ticket.rb index a4ef33bc4..29ac05365 100644 --- a/config/routes/ticket.rb +++ b/config/routes/ticket.rb @@ -3,6 +3,7 @@ Zammad::Application.routes.draw do # tickets match api_path + '/tickets/search', to: 'tickets#search', via: [:get, :post] + match api_path + '/tickets/selector', to: 'tickets#selector', via: :post match api_path + '/tickets', to: 'tickets#index', via: :get match api_path + '/tickets/:id', to: 'tickets#show', via: :get match api_path + '/tickets', to: 'tickets#create', via: :post