diff --git a/app/assets/javascripts/app/controllers/_application_controller.coffee b/app/assets/javascripts/app/controllers/_application_controller.coffee index 522748b13..5de30d05b 100644 --- a/app/assets/javascripts/app/controllers/_application_controller.coffee +++ b/app/assets/javascripts/app/controllers/_application_controller.coffee @@ -528,6 +528,9 @@ class App.Controller extends Spine.Controller # replace new option list form.find('[name="' + fieldNameToChange + '"]').closest('.form-group').replaceWith( newElement ) + stopPropagation: (e) -> + e.stopPropagation() + class App.ControllerPermanent extends App.Controller constructor: -> super 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 a59572b8f..ea6562a43 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,6 +8,9 @@ class App.UiElement.ticket_perform_action name: 'Ticket' model: 'Ticket' + operators = + 'ticket.tags': ['add', 'remove'] + # megre config elements = {} for groupKey, groupMeta of groups @@ -21,11 +24,11 @@ class App.UiElement.ticket_perform_action config = _.clone(row) elements["#{groupKey}.#{config.name}"] = config - [defaults, groups, elements] + [defaults, groups, operators, elements] @render: (attribute, params = {}) -> - [defaults, groups, elements] = @defaults() + [defaults, groups, operators, elements] = @defaults() selector = @buildAttributeSelector(groups, elements) @@ -53,6 +56,7 @@ class App.UiElement.ticket_perform_action 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) ) @@ -63,6 +67,7 @@ class App.UiElement.ticket_perform_action for groupAndAttribute, meta of params[attribute.name] selectorExists = true value = meta.value + operator = meta.operator # get selector rows elementFirst = item.find('.js-filterElement').first() @@ -71,6 +76,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) elementLast.after(elementClone) @@ -93,6 +99,26 @@ class App.UiElement.ticket_perform_action 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 @@ -163,7 +189,7 @@ class App.UiElement.ticket_perform_action @humanText: (condition) -> none = App.i18n.translateContent('No filter.') return [none] if _.isEmpty(condition) - [defaults, groups, elements] = @defaults() + [defaults, groups, operators, elements] = @defaults() rules = [] for attribute, value of condition diff --git a/app/assets/javascripts/app/controllers/macro.coffee b/app/assets/javascripts/app/controllers/macro.coffee new file mode 100644 index 000000000..d6d2c0e18 --- /dev/null +++ b/app/assets/javascripts/app/controllers/macro.coffee @@ -0,0 +1,27 @@ +class Index extends App.ControllerContent + constructor: -> + super + + # check authentication + return if !@authenticate() + + new App.ControllerGenericIndex( + el: @el + id: @id + genericObject: 'Macro' + pageData: + title: 'Macros' + home: 'macros' + object: 'Macro' + objects: 'Macros' + navupdate: '#macros' + notes: [ + 'TextModules are ...' + ] + buttons: [ + { name: 'New Macro', 'data-type': 'new', class: 'btn--success' } + ] + container: @el.closest('.content') + ) + +App.Config.set( 'Macros', { prio: 2310, name: 'Macros', parent: '#manage', target: '#manage/macros', controller: Index, role: ['Admin'] }, 'NavBarAdmin' ) \ No newline at end of file diff --git a/app/assets/javascripts/app/controllers/ticket_zoom.coffee b/app/assets/javascripts/app/controllers/ticket_zoom.coffee index f8fa10cc6..b0d846ec1 100644 --- a/app/assets/javascripts/app/controllers/ticket_zoom.coffee +++ b/app/assets/javascripts/app/controllers/ticket_zoom.coffee @@ -308,6 +308,12 @@ class App.TicketZoom extends App.Controller el: @el.find('.ticket-meta') ) + new App.TicketZoomAttributeBar( + ticket: @ticket + el: @el.find('.js-attributeBar') + callback: @submit + ) + @form_id = App.ControllerForm.formId() new App.TicketZoomArticleNew( @@ -338,7 +344,7 @@ class App.TicketZoom extends App.Controller user_id: @ticket.customer_id size: 50 ) - new App.TicketZoomSidebar( + @sidebar = new App.TicketZoomSidebar( el: @el.find('.tabsSidebar') sidebarState: @sidebarState ticket: @ticket @@ -462,7 +468,7 @@ class App.TicketZoom extends App.Controller resetButton.removeClass('hide') - submit: (e) => + submit: (e, macro = {}) => e.stopPropagation() e.preventDefault() ticketParams = @formParam( @$('.edit') ) @@ -477,6 +483,25 @@ class App.TicketZoom extends App.Controller for key, value of ticketParams ticket[key] = value + # apply macro + for key, content of macro + attributes = key.split('.') + if attributes[0] is 'ticket' + + # apply tag changes + if attributes[1] is 'tags' + if @sidebar && @sidebar.tagWidget + tags = content.value.split(',') + for tag in tags + if content.operator is 'remove' + @sidebar.tagWidget.remove(tag) + else + @sidebar.tagWidget.add(tag) + + # apply direct value changes + else + ticket[attributes[1]] = content.value + # set defaults if !@isRole('Customer') if !ticket['owner_id'] diff --git a/app/assets/javascripts/app/controllers/ticket_zoom/attribute_bar.coffee b/app/assets/javascripts/app/controllers/ticket_zoom/attribute_bar.coffee new file mode 100644 index 000000000..4fc23b084 --- /dev/null +++ b/app/assets/javascripts/app/controllers/ticket_zoom/attribute_bar.coffee @@ -0,0 +1,53 @@ +class App.TicketZoomAttributeBar extends App.Controller + elements: + '.buttonDropdown': 'buttonDropdown' + + events: + 'mousedown .js-openDropdownMacro': 'toggleDropdownMacro' + 'click .js-openDropdownMacro': 'stopPropagation' + 'mouseup .js-dropdownActionMacro': 'performTicketMacro' + 'mouseenter .js-dropdownActionMacro': 'onActionMacroMouseEnter' + 'mouseleave .js-dropdownActionMacro': 'onActionMacroMouseLeave' + + constructor: -> + super + + @subscribeId = App.Macro.subscribe(@render) + @render() + + release: => + App.Macro.unsubscribe(@subscribeId) + + render: => + macros = App.Macro.all() + if _.isEmpty(macros) || !@isRole('Agent') + macroDisabled = true + @html App.view('ticket_zoom/attribute_bar')( + macros: macros + macroDisabled: macroDisabled + ) + + toggleDropdownMacro: => + if @buttonDropdown.hasClass 'is-open' + @closeMacroDropdown() + else + @buttonDropdown.addClass 'is-open' + $(document).bind 'click.buttonDropdown', @closeMacroDropdown + + closeMacroDropdown: => + @buttonDropdown.removeClass 'is-open' + $(document).unbind 'click.buttonDropdown' + + performTicketMacro: (e) => + macroId = $(e.target).data('id') + console.log "perform action", @$(e.currentTarget).text(), macroId + macro = App.Macro.find(macroId) + + @callback(e, macro.perform) + @closeMacroDropdown() + + onActionMacroMouseEnter: (e) => + @$(e.currentTarget).addClass('is-active') + + onActionMacroMouseLeave: (e) => + @$(e.currentTarget).removeClass('is-active') \ No newline at end of file diff --git a/app/assets/javascripts/app/controllers/ticket_zoom/sidebar.coffee b/app/assets/javascripts/app/controllers/ticket_zoom/sidebar.coffee index 4e9c5c93c..9395e5d75 100644 --- a/app/assets/javascripts/app/controllers/ticket_zoom/sidebar.coffee +++ b/app/assets/javascripts/app/controllers/ticket_zoom/sidebar.coffee @@ -50,14 +50,14 @@ class App.TicketZoomSidebar extends App.Controller if !@isRole('Customer') el.append('
') - new App.WidgetTag( + @tagWidget = new App.WidgetTag( el: el.find('.tags') object_type: 'Ticket' object: ticket tags: @tags ) el.append('') - new App.WidgetLink( + @linkWidget = new App.WidgetLink( el: el.find('.links') object_type: 'Ticket' object: ticket diff --git a/app/assets/javascripts/app/controllers/widget/tag.coffee b/app/assets/javascripts/app/controllers/widget/tag.coffee index 3ffa46f5d..a5d18fb15 100644 --- a/app/assets/javascripts/app/controllers/widget/tag.coffee +++ b/app/assets/javascripts/app/controllers/widget/tag.coffee @@ -65,8 +65,10 @@ class App.WidgetTag extends App.Controller e.preventDefault() item = @$('[name="new_tag"]').val() return if !item + @add(item) - if _.contains(@tagList, item) + add: (item) => + if _.contains(@tags, item) @render() return @@ -90,6 +92,10 @@ class App.WidgetTag extends App.Controller item = $(e.target).parents('li').find('.js-tag').text() return if !item + @remove(item) + + remove: (item) => + @tags = _.filter(@tags, (tagItem) -> return tagItem if tagItem isnt item ) @render() diff --git a/app/assets/javascripts/app/lib/app_post/pretty_date.coffee b/app/assets/javascripts/app/lib/app_post/pretty_date.coffee index 8866818fd..69a8b05f3 100644 --- a/app/assets/javascripts/app/lib/app_post/pretty_date.coffee +++ b/app/assets/javascripts/app/lib/app_post/pretty_date.coffee @@ -26,6 +26,9 @@ class App.PrettyDate diff = diff.toString().replace('-', '') diff = parseFloat(diff) + if diff < 60 + return App.i18n.translateInline('just now') + if direction is 'past' && !escalation && diff > ( 60 * 60 * 24 * 14 ) return App.i18n.translateDate(time) diff --git a/app/assets/javascripts/app/models/macro.coffee b/app/assets/javascripts/app/models/macro.coffee new file mode 100644 index 000000000..99a60c96f --- /dev/null +++ b/app/assets/javascripts/app/models/macro.coffee @@ -0,0 +1,20 @@ +class App.Macro extends App.Model + @configure 'Macro', 'name', 'perform', 'active' + @extend Spine.Model.Ajax + @url: @apiPath + '/macros' + @configure_attributes = [ + { name: 'name', display: 'Name', tag: 'input', type: 'text', limit: 100, null: false }, + { name: 'perform', display: 'Execute changes on objects.', tag: 'ticket_perform_action', null: true }, + { name: 'updated_at', display: 'Updated', tag: 'datetime', readonly: 1 }, + { name: 'note', display: 'Note', tag: 'textarea', limit: 250, null: true }, + { name: 'active', display: 'Active', tag: 'active', default: true }, + ] + @configure_delete = true + @configure_overview = [ + 'name', + ] + + @description = ''' +Macros are.... + +''' \ No newline at end of file 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 17e5c88e0..4f9566af6 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,6 +6,7 @@ <%- @Icon('arrow-down', 'dropdown-arrow') %> +