Browse Source

Implemented issue#341 - optional subject for email, define if twitter initials are used and default internal state of new notes.

Martin Edenhofer 7 years ago
parent
commit
0065028ee6

+ 13 - 6
app/assets/javascripts/app/controllers/ticket_zoom.coffee

@@ -404,7 +404,7 @@ class App.TicketZoom extends App.Controller
       )
 
       new App.TicketZoomOverviewNavigator(
-        el:          elLocal.find('.overview-navigator')
+        el:          elLocal.find('.js-overviewNavigatorContainer')
         ticket_id:   @ticket_id
         overview_id: @overview_id
       )
@@ -412,13 +412,13 @@ class App.TicketZoom extends App.Controller
       new App.TicketZoomTitle(
         object_id:   @ticket_id
         overview_id: @overview_id
-        el:          elLocal.find('.ticket-title')
+        el:          elLocal.find('.js-ticketTitleContainer')
         task_key:    @task_key
       )
 
       new App.TicketZoomMeta(
         object_id: @ticket_id
-        el:        elLocal.find('.ticket-meta')
+        el:        elLocal.find('.js-ticketMetaContainer')
       )
 
       @attributeBar = new App.TicketZoomAttributeBar(
@@ -445,7 +445,12 @@ class App.TicketZoom extends App.Controller
       )
 
       @highligher = new App.TicketZoomHighlighter(
-        el:        elLocal.find('.highlighter')
+        el:        elLocal.find('.js-highlighterContainer')
+        ticket_id: @ticket_id
+      )
+
+      new App.TicketZoomSetting(
+        el:        elLocal.find('.js-settingContainer')
         ticket_id: @ticket_id
       )
 
@@ -557,14 +562,16 @@ class App.TicketZoom extends App.Controller
     return if !@ticket
     currentStoreTicket = @ticket.attributes()
     delete currentStoreTicket.article
+    internal = @Config.get('ui_ticket_zoom_article_note_new_internal')
     currentStore  =
       ticket:  currentStoreTicket
       article:
         to:          ''
         cc:          ''
+        subject:     ''
         type:        'note'
         body:        ''
-        internal:    'true'
+        internal:    internal
         in_reply_to: ''
 
     if @permissionCheck('ticket.customer')
@@ -575,7 +582,7 @@ class App.TicketZoom extends App.Controller
   formCurrent: =>
     currentParams =
       ticket:  @formParam(@el.find('.edit'))
-      article: @formParam(@el.find('.article-add'))
+      article: @articleNew.params()
 
     # add attachments if exist
     attachmentCount = @$('.article-add .textBubble .attachments .attachment').length

+ 74 - 60
app/assets/javascripts/app/controllers/ticket_zoom/article_new.coffee

@@ -28,7 +28,62 @@ class App.TicketZoomArticleNew extends App.Controller
   constructor: ->
     super
 
-    # set possble article types
+    @internalSelector = true
+    @type = @defaults['type'] || 'note'
+    @setPossibleArticleTypes()
+
+    if @permissionCheck('ticket.customer')
+      @internalSelector = false
+
+    @textareaHeight =
+      open:   148
+      closed: 20
+
+    @dragEventCounter = 0
+    @attachments      = []
+
+    @render()
+
+    if @defaults.body or @isIE10()
+      @openTextarea(null, true)
+
+    # set article type and expand text area
+    @bind('ui::ticket::setArticleType', (data) =>
+      return if data.ticket.id.toString() isnt @ticket_id.toString()
+
+      @openTextarea(null, true)
+      for key, value of data.article
+        if key is 'body'
+          @$('[data-name="' + key + '"]').html(value)
+        else
+          @$('[name="' + key + '"]').val(value).trigger('change')
+
+      # preselect article type
+      @setArticleType(data.type.name)
+
+      # set focus at end of field
+      if data.position is 'end'
+        @placeCaretAtEnd(@textarea.get(0))
+        return
+
+      # set focus into field
+      @textarea.focus()
+    )
+
+    # reset new article screen
+    @bind('ui::ticket::taskReset', (data) =>
+      return if data.ticket_id.toString() isnt @ticket_id.toString()
+      @type     = 'note'
+      @defaults = {}
+      @render()
+    )
+
+    # rerender, e. g. on language change
+    @bind('ui:rerender', =>
+      @render()
+    )
+
+  setPossibleArticleTypes: =>
     possibleArticleType =
       note: true
       phone: true
@@ -50,12 +105,9 @@ class App.TicketZoomArticleNew extends App.Controller
         possibleArticleType['email'] = true
 
     # gets referenced in @setArticleType
-    @internalSelector = true
-    @type = @defaults['type'] || 'note'
     @articleTypes = []
     if possibleArticleType.note
-      internal = @Config.get('ui_ticket_zoom_article_new_internal')
-
+      internal = @Config.get('ui_ticket_zoom_article_note_new_internal')
       @articleTypes.push {
         name:       'note'
         icon:       'note'
@@ -64,10 +116,13 @@ class App.TicketZoomArticleNew extends App.Controller
         features:   ['attachment']
       }
     if possibleArticleType.email
+      attributes = ['to', 'cc', 'subject']
+      if !@Config.get('ui_ticket_zoom_article_email_subject')
+        attributes = ['to', 'cc']
       @articleTypes.push {
         name:       'email'
         icon:       'email'
-        attributes: ['to', 'cc']
+        attributes: attributes
         internal:   false,
         features:   ['attachment']
       }
@@ -80,6 +135,9 @@ class App.TicketZoomArticleNew extends App.Controller
         features:   []
       }
     if possibleArticleType['twitter status']
+      attributes = ['body:limit', 'body:initials']
+      if !@Config.get('ui_ticket_zoom_article_twitter_initials')
+        attributes = ['body:limit']
       @articleTypes.push {
         name:              'twitter status'
         icon:              'twitter'
@@ -90,6 +148,9 @@ class App.TicketZoomArticleNew extends App.Controller
         warningTextLength: 30
       }
     if possibleArticleType['twitter direct-message']
+      attributes = ['body:limit', 'body:initials']
+      if !@Config.get('ui_ticket_zoom_article_twitter_initials')
+        attributes = ['body:limit']
       @articleTypes.push {
         name:              'twitter direct-message'
         icon:              'twitter'
@@ -130,57 +191,6 @@ class App.TicketZoomArticleNew extends App.Controller
         },
       ]
 
-    if @permissionCheck('ticket.customer')
-      @internalSelector = false
-
-    @textareaHeight =
-      open:   148
-      closed: 20
-
-    @dragEventCounter = 0
-    @attachments      = []
-
-    @render()
-
-    if @defaults.body or @isIE10()
-      @openTextarea(null, true)
-
-    # set article type and expand text area
-    @bind('ui::ticket::setArticleType', (data) =>
-      return if data.ticket.id.toString() isnt @ticket_id.toString()
-
-      @openTextarea(null, true)
-      for key, value of data.article
-        if key is 'body'
-          @$('[data-name="' + key + '"]').html(value)
-        else
-          @$('[name="' + key + '"]').val(value).trigger('change')
-
-      # preselect article type
-      @setArticleType(data.type.name)
-
-      # set focus at end of field
-      if data.position is 'end'
-        @placeCaretAtEnd(@textarea.get(0))
-        return
-
-      # set focus into field
-      @textarea.focus()
-    )
-
-    # reset new article screen
-    @bind('ui::ticket::taskReset', (data) =>
-      return if data.ticket_id.toString() isnt @ticket_id.toString()
-      @type     = 'note'
-      @defaults = {}
-      @render()
-    )
-
-    # rerender, e. g. on language change
-    @bind('ui:rerender', =>
-      @render()
-    )
-
   placeCaretAtEnd: (el) ->
     el.focus()
     if typeof window.getSelection isnt 'undefined' && typeof document.createRange isnt 'undefined'
@@ -318,9 +328,6 @@ class App.TicketZoomArticleNew extends App.Controller
       params.form_id      = @form_id
       params.content_type = 'text/html'
 
-      if !params['internal']
-        params['internal'] = false
-
       if @permissionCheck('ticket.customer')
         sender           = App.TicketArticleSender.findByAttribute('name', 'Customer')
         type             = App.TicketArticleType.findByAttribute('name', 'web')
@@ -332,6 +339,11 @@ class App.TicketZoomArticleNew extends App.Controller
         params.sender_id = sender.id
         params.type_id   = type.id
 
+    if params.internal
+      params.internal = true
+    else
+      params.internal = false
+
     if params.type is 'twitter status'
       App.Utils.htmlRemoveRichtext(@$('[data-name=body]'), false)
       params.content_type = 'text/plain'
@@ -478,6 +490,8 @@ class App.TicketZoomArticleNew extends App.Controller
     @articleNewEdit.attr('data-type', type)
     @$('.js-selectableTypes').addClass('hide').filter("[data-type='#{type}']").removeClass('hide')
 
+    @setPossibleArticleTypes()
+
     # get config
     config = {}
     for articleTypeConfig in @articleTypes

+ 0 - 0
app/assets/javascripts/app/controllers/ticket_zoom/higlighter.coffee → app/assets/javascripts/app/controllers/ticket_zoom/highlighter.coffee


+ 35 - 0
app/assets/javascripts/app/controllers/ticket_zoom/setting.coffee

@@ -0,0 +1,35 @@
+class App.TicketZoomSetting extends App.Controller
+  events:
+    'click .js-setting': 'show'
+
+  constructor: ->
+    super
+    return if !@permissionCheck('admin')
+    @render()
+
+  render: ->
+    @html(App.view('ticket_zoom/setting')())
+
+  show: ->
+    new Modal()
+
+class Modal extends App.ControllerModal
+  buttonClose: true
+  buttonCancel: true
+  buttonSubmit: false
+  head: 'Settings'
+
+  constructor: ->
+    super
+
+  render: =>
+    super
+
+  post: =>
+    new App.SettingsArea(
+      area: 'UI::TicketZoom'
+      el: @el.find('.modal-body')
+    )
+
+  content: ->
+    App.view('generic/page_loading')()

+ 8 - 7
app/assets/javascripts/app/views/ticket_zoom.jst.eco

@@ -1,21 +1,22 @@
 <div class="tabsSidebar-holder">
   <div class="scrollPageHeader tabsSidebar-sidebarSpacer" style="right: <%- @scrollbarWidth %>px">
     <small><%- @C('ticket_hook') %> <span class="ticket-number"><%- @ticket.number %></span></small>
-    <div class="ticket-title"></div>
-    <div class="highlighter"></div>
-    <div class="overview-navigator"></div>
+    <div class="js-ticketTitleContainer ticket-title"></div>
+    <div class="js-highlighterContainer highlighter"></div>
+    <div class="js-overviewNavigatorContainer overview-navigator"></div>
   </div>
   <div class="main no-padding flex tabsSidebar-sidebarSpacer tabsSidebar-tabsSpacer">
     <div class="ticketZoom">
       <div class="ticketZoom-controls">
-        <div class="highlighter"></div>
-        <div class="overview-navigator"></div>
+        <div class="js-settingContainer"></div>
+        <div class="js-highlighterContainer highlighter"></div>
+        <div class="js-overviewNavigatorContainer overview-navigator"></div>
       </div>
       <div class="ticketZoom-header">
         <div class="flex vertical center">
           <div class="js-avatar"></div>
-          <div class="ticket-title"></div>
-          <div class="ticket-meta"></div>
+          <div class="js-ticketTitleContainer ticket-title"></div>
+          <div class="js-ticketMetaContainer"></div>
         </div>
       </div>
       <div class="ticket-article"></div>

+ 8 - 2
app/assets/javascripts/app/views/ticket_zoom/article_new.jst.eco

@@ -41,13 +41,19 @@
         <div class="formGroup-label">
           <label for=""><%- @T('To') %></label>
         </div>
-        <div class="controls"><input id="" type="text" name="to" value="<%= @article.to %>" class="form-control js-mail-inputs" required="required"></div>
+        <div class="controls"><input type="text" name="to" value="<%= @article.to %>" class="form-control js-mail-inputs" required="required"></div>
       </div>
       <div class="input form-group">
         <div class="formGroup-label">
           <label for=""><%- @T('Cc') %></label>
         </div>
-        <div class="controls"><input id="" type="text" name="cc" value="<%= @article.cc %>" class="form-control js-mail-inputs"></div>
+        <div class="controls"><input type="text" name="cc" value="<%= @article.cc %>" class="form-control js-mail-inputs"></div>
+      </div>
+      <div class="input form-group">
+        <div class="formGroup-label">
+          <label for=""><%- @T('Subject') %></label>
+        </div>
+        <div class="controls"><input type="text" name="subject" value="<%= @article.subject %>" class="form-control js-mail-inputs2"></div>
       </div>
 
       <div class="textBubble js-writeArea">

+ 3 - 0
app/assets/javascripts/app/views/ticket_zoom/setting.jst.eco

@@ -0,0 +1,3 @@
+<div class="btn btn--action btn--split--first js-setting centered">
+  <%- @Icon('cog', 'dropdown-icon') %>
+</div>

+ 99 - 0
db/migrate/20170630000001_ticket_zoom_setting.rb

@@ -0,0 +1,99 @@
+class TicketZoomSetting < ActiveRecord::Migration
+  def up
+
+    # return if it's a new setup
+    return if !Setting.find_by(name: 'system_init_done')
+
+    setting = Setting.find_by(name: 'ui_ticket_zoom_article_new_internal')
+    if setting
+      setting.title = 'Note - default visibility'
+      setting.name = 'ui_ticket_zoom_article_note_new_internal'
+      setting.description = 'Default visibility for new articles.'
+      setting.preferences[:prio] = 100
+      setting.options[:form][0][:name] = 'ui_ticket_zoom_article_note_new_internal'
+      setting.save!
+    end
+    Setting.create_if_not_exists(
+      title: 'Note - default visibility',
+      name: 'ui_ticket_zoom_article_note_new_internal',
+      area: 'UI::TicketZoom',
+      description: 'Default visibility for new articles.',
+      options: {
+        form: [
+          {
+            display: '',
+            null: true,
+            name: 'ui_ticket_zoom_article_note_new_internal',
+            tag: 'boolean',
+            translate: true,
+            options: {
+              true  => 'internal',
+              false => 'public',
+            },
+          },
+        ],
+      },
+      state: true,
+      preferences: {
+        prio: 100,
+        permission: ['admin.ui'],
+      },
+      frontend: true
+    )
+    Setting.create_if_not_exists(
+      title: 'Email - subject field',
+      name: 'ui_ticket_zoom_article_email_subject',
+      area: 'UI::TicketZoom',
+      description: 'Use subject field for emails. If disabled, the ticket title will be used as subject.',
+      options: {
+        form: [
+          {
+            display: '',
+            null: true,
+            name: 'ui_ticket_zoom_article_email_subject',
+            tag: 'boolean',
+            translate: true,
+            options: {
+              true  => 'yes',
+              false => 'no',
+            },
+          },
+        ],
+      },
+      state: false,
+      preferences: {
+        prio: 200,
+        permission: ['admin.ui'],
+      },
+      frontend: true
+    )
+    Setting.create_if_not_exists(
+      title: 'Twitter - tweet initials',
+      name: 'ui_ticket_zoom_article_twitter_initials',
+      area: 'UI::TicketZoom',
+      description: 'Add sender initials to end of a tweet.',
+      options: {
+        form: [
+          {
+            display: '',
+            null: true,
+            name: 'ui_ticket_zoom_article_twitter_initials',
+            tag: 'boolean',
+            translate: true,
+            options: {
+              true  => 'yes',
+              false => 'no',
+            },
+          },
+        ],
+      },
+      state: true,
+      preferences: {
+        prio: 300,
+        permission: ['admin.ui'],
+      },
+      frontend: true
+    )
+  end
+
+end

+ 59 - 6
db/seeds/settings.rb

@@ -546,18 +546,17 @@ Setting.create_if_not_exists(
   },
   frontend: true
 )
-
 Setting.create_if_not_exists(
-  title: 'Define default visibility of new a new article',
-  name: 'ui_ticket_zoom_article_new_internal',
+  title: 'Note - default visibility',
+  name: 'ui_ticket_zoom_article_note_new_internal',
   area: 'UI::TicketZoom',
-  description: 'Set default visibility of new a new article.',
+  description: 'Default visibility for new note.',
   options: {
     form: [
       {
         display: '',
         null: true,
-        name: 'ui_ticket_zoom_article_new_internal',
+        name: 'ui_ticket_zoom_article_note_new_internal',
         tag: 'boolean',
         translate: true,
         options: {
@@ -569,7 +568,61 @@ Setting.create_if_not_exists(
   },
   state: true,
   preferences: {
-    prio: 1,
+    prio: 100,
+    permission: ['admin.ui'],
+  },
+  frontend: true
+)
+Setting.create_if_not_exists(
+  title: 'Email - subject field',
+  name: 'ui_ticket_zoom_article_email_subject',
+  area: 'UI::TicketZoom',
+  description: 'Use subject field for emails. If disabled, the ticket title will be used as subject.',
+  options: {
+    form: [
+      {
+        display: '',
+        null: true,
+        name: 'ui_ticket_zoom_article_email_subject',
+        tag: 'boolean',
+        translate: true,
+        options: {
+          true  => 'yes',
+          false => 'no',
+        },
+      },
+    ],
+  },
+  state: false,
+  preferences: {
+    prio: 200,
+    permission: ['admin.ui'],
+  },
+  frontend: true
+)
+Setting.create_if_not_exists(
+  title: 'Twitter - tweet initials',
+  name: 'ui_ticket_zoom_article_twitter_initials',
+  area: 'UI::TicketZoom',
+  description: 'Add sender initials to end of a tweet.',
+  options: {
+    form: [
+      {
+        display: '',
+        null: true,
+        name: 'ui_ticket_zoom_article_twitter_initials',
+        tag: 'boolean',
+        translate: true,
+        options: {
+          true  => 'yes',
+          false => 'no',
+        },
+      },
+    ],
+  },
+  state: true,
+  preferences: {
+    prio: 300,
     permission: ['admin.ui'],
   },
   frontend: true

+ 1 - 1
test/browser_test_helper.rb

@@ -2261,7 +2261,7 @@ wait untill text in selector disabppears
     9.times {
       begin
         text = instance.find_elements(css: '.content.active .js-reset')[0].text
-        if !text || text.empty?
+        if text.blank?
           screenshot(browser: instance, comment: 'ticket_update_ok')
           sleep 1
           return true