Support for markdown in settings description of model description attributes.

This commit is contained in:
Martin Edenhofer 2015-09-13 01:04:31 +02:00
parent 5be3eb29b9
commit 79666ba324
17 changed files with 1571 additions and 40 deletions

View file

@ -98,8 +98,9 @@ class App.ControllerGenericEdit extends App.ControllerModal
class App.ControllerGenericIndex extends App.Controller
events:
'click [data-type = edit]': 'edit'
'click [data-type = new]': 'new'
'click [data-type=edit]': 'edit'
'click [data-type=new]': 'new'
'click .js-description': 'description'
constructor: ->
super
@ -147,13 +148,25 @@ class App.ControllerGenericIndex extends App.Controller
return item
)
# show description button, only if content exists
showDescription = false
if App[ @genericObject ].description && !_.isEmpty(objects)
showDescription = true
@html App.view('generic/admin/index')(
head: @pageData.objects
notes: @pageData.notes
buttons: @pageData.buttons
menus: @pageData.menus
head: @pageData.objects
notes: @pageData.notes
buttons: @pageData.buttons
menus: @pageData.menus
showDescription: showDescription
)
# show description in content if no no content exists
if _.isEmpty(objects) && App[ @genericObject ].description
description = marked(App[ @genericObject ].description)
@$('.table-overview').html(description)
return
# append content table
params = _.extend(
{
@ -193,6 +206,26 @@ class App.ControllerGenericIndex extends App.Controller
container: @container
)
description: (e) =>
new App.ControllerGenericDescription(
description: App[ @genericObject ].description
container: @container
)
class App.ControllerGenericDescription extends App.ControllerModal
constructor: ->
super
@head = 'Description'
@cancel = false
@button = 'Close'
description = marked(@description)
@show(description)
onSubmit: (e) ->
e.preventDefault()
@hide()
class App.ControllerGenericDestroyConfirm extends App.ControllerModal
constructor: ->
super

View file

@ -45,6 +45,10 @@ class App.ChannelEmailFilter extends App.Controller
template = $( '<div><div class="overview"></div><a data-type="new" class="btn btn--success">' + App.i18n.translateContent('New') + '</a></div>' )
description = '''
With Filters you can e. g. dispatch new Tickets into certain groups or set a certain priority for Tickets of an VIP customer.
'''
new App.ControllerTable(
el: template.find('.overview')
model: App.PostmasterFilter
@ -52,6 +56,7 @@ class App.ChannelEmailFilter extends App.Controller
bindRow:
events:
'click': @edit
explanation: description
)
@html template
@ -135,6 +140,13 @@ class App.ChannelEmailSignature extends App.Controller
data = App.Signature.search( sortBy: 'name' )
template = $( '<div><div class="overview"></div><a data-type="new" class="btn btn--success">' + App.i18n.translateContent('New') + '</a></div>' )
description = '''
You can define differenct signatures for each group. So you can have different email signatures for different departments.
Once you have created a signature here, you need also to edit the groups where you want to use it.
'''
new App.ControllerTable(
el: template.find('.overview')
model: App.Signature
@ -142,6 +154,7 @@ class App.ChannelEmailSignature extends App.Controller
bindRow:
events:
'click': @edit
explanation: description
)
@html template

View file

@ -1,6 +1,8 @@
class Index extends App.ControllerContent
events:
'click .js-new': 'newDialog'
'click .js-new': 'newDialog'
'click .js-description': 'description'
constructor: ->
super
@ -11,7 +13,9 @@ class Index extends App.ControllerContent
App.Calendar.fetch()
render: =>
calendars = App.Calendar.all()
calendars = App.Calendar.search(
sortBy: 'name'
)
for calendar in calendars
# get preview public holidays
@ -27,8 +31,18 @@ class Index extends App.ControllerContent
public_holidays_preview[day] = calendar.public_holidays[day]
calendar.public_holidays_preview = public_holidays_preview
# show description button, only if content exists
showDescription = false
if App.Calendar.description
if !_.isEmpty(calendars)
showDescription = true
else
description = marked(App[ @genericObject ].description)
@html App.view('calendar')(
calendars: calendars
calendars: calendars
showDescription: showDescription
description: description
)
release: =>
@ -50,4 +64,10 @@ class Index extends App.ControllerContent
@$('.js-time').timepicker
showMeridian: true # show am/pm
description: (e) =>
new App.ControllerGenericDescription(
description: App.Calendar.description
container: @el.closest('.content')
)
App.Config.set( 'Calendars', { prio: 2400, name: 'Calendars', parent: '#manage', target: '#manage/calendars', controller: Index, role: ['Admin'] }, 'NavBarAdmin' )

View file

@ -21,7 +21,6 @@ class Index extends App.ControllerContent
buttons: [
{ name: 'New TextModule', 'data-type': 'new', class: 'btn--success' }
]
explanation: 'Create Text Modules to spend less time writing responses. TextModules can include smart variables like the users name or email address.'
container: @el.closest('.content')
)

View file

@ -241,6 +241,15 @@ class App extends Spine.Controller
params.Icon = (name, className = '') ->
"<svg class=\"icon icon-#{name} #{className}\"><use xlink:href=\"#icon-#{name}\" /></svg>"
# define richtext helper
params.RichText = ( string ) ->
if string.match(/@T\('/)
string = string.replace(/@T\('(.+?)'\)/g, (match, capture) ->
App.i18n.translateContent(capture)
)
return marked(string)
App.i18n.translateContent(string)
# define template
JST["app/views/#{name}"](params)
template

File diff suppressed because it is too large Load diff

View file

@ -5,3 +5,11 @@ class App.Calendar extends App.Model
displayName: ->
"#{@name} - #{@timezone}"
@description = '''
Ein **Kalender** wird benötigt um Eskalationen oder Auswertungen anhand von Geschäftszeiten zu berechnen.
Definieren Sie einen **"Standard"-Kalender** welcher Systemweit gültig ist. Nur in den angegebenen Geschäftszeiten werden Eskalations-Benachrichtigungen an Agenten versendet.
Haben Sie Kunden für welche Sie unterschiedliche Geschäftszeiten einhalten müssen, so können Sie mehrere Kalender anlegen. Die Zuweisung zu den Kunden-Tickets geschieht über die **SLAs**.
'''

View file

@ -14,6 +14,13 @@ class App.Organization extends App.Model
'shared',
]
@description = '''
Mit **Organisationen** können Sie Kunden **gruppieren**. Dies hat u. a. zwei bedeutende Vorteile.
1. Als **Agent** haben Sie nicht nur die Übersicht über die Tickets eines Kunden sondern zusätzlich die **Übersicht über die gesamte Organisation**. Z. B. über die Suchen nach der Organisation, diese per einfachen klick öffnen.
2. Als **Kunde** können Sie die **Tickets ihrer Kollegen mit einsehen** und bearbeiten (sofern die Organisation eine "teilende" ist, dies können Sie je Organisation als Parameter einstellen).
'''
uiUrl: ->
'#organization/profile/' + @id
@ -36,4 +43,4 @@ class App.Organization extends App.Model
id: @id
class: "organization organization-popover"
url: @uiUrl()
iconClass: "organization"
iconClass: "organization"

View file

@ -144,3 +144,9 @@ class App.Overview extends App.Model
'role',
'prio',
]
@description = '''
Übersichten können Sie Ihren Agenten und Kunden bereitstellen. Sie dienen als eine Art Arbeitslisten von Aufgaben welche der Agent abarbeiten soll.
Sie können auch individuelle Übersichten für einzelne Agenten oder agenten Gruppen erstellen.
'''

View file

@ -18,3 +18,11 @@ class App.Sla extends App.Model
@configure_overview = [
'name',
]
@description = '''
**Service-Level-Agreements**, abgekürzt **SLAs**, unterstützen Sie gegenüber Kunden gewisse zeitliche Reaktionen einzuhalten. Somit können Sie z. B. sagen Kunden sollen immer nach spätestens 8 Stunden eine Reaktion von Ihnen bekommen. Falls es zu einer drohenden Unterschreitung oder einer Unterschreitung kommt, weißt Zammad Sie auf solche Ereignisse hin.
Es können **Reaktionszeit** (Zeit zwischen Erstellung eines Tickets und erster Reaktion eines Agenten), **Aktualisierungszeit** (Zeit zwischen Nachfrage eines Kunden und Reaktion eines Agenten) und **Lösungszeit** (Zeit zwischen Erstellung und schließen eines Tickets) definiert werden.
Drohenden Unterschreitungen oder Unterschreitungen werden in einer eigenen Ansicht in den Übersichten angezeigt. Zudem können **E-Mail Benachrichtigungen** konfiguriert werden.
'''

View file

@ -15,3 +15,22 @@ class App.TextModule extends App.Model
'keywords',
'content',
]
@description = '''
Create Text Modules to **spend less time writing responses**. TextModules can include smart variables like the users name or email address.
Examples of snippets are:
* Hallo Frau <%= @ticket.customer.lastname %>,
* Hallo Herr <%= @ticket.customer.lastname %>,
* Hallo <%= @ticket.customer.firstname %>,
Of course you can also use multi line snippets.
Available objects are:
* @ticket (e. g. @ticket.state, @ticket.group)
* @ticket.customer (e. g. @ticket.customer.firstname, @ticket.customer.lastname)
* @ticket.owner (e. g. @ticket.owner.firstname, @ticket.owner.lastname)
* @ticket.organization (e. g. @ticket.organization.name)
'''

View file

@ -4,10 +4,17 @@
</div>
<div class="page-header-meta">
<% if @showDescription: %>
<a class="btn js-description"><%- @T('Description') %></a>
<% end %>
<a class="btn btn--success js-new"><%- @T('New Calendar') %></a>
</div>
</div>
<% if _.isEmpty(@calendars): %>
<%- @description %>
<% end %>
<% for calendar in @calendars: %>
<div class="action">
<div class="action-flow">

View file

@ -1 +1 @@
<p><%= @Ti( @explanation ) %></p>
<p><%= @T(@explanation) %></p>

View file

@ -3,10 +3,13 @@
<h1><%- @T( @head ) %> <small><%- @T( 'Management' ) %></small></h1>
</div>
<div class="page-header-meta">
<% if @buttons: %>
<% for button in @buttons: %>
<a data-type="<%= button['data-type'] %>" class="btn <%= button['class'] %>"><%- @T( button.name ) %></a>
<% if @showDescription: %>
<a class="btn js-description"><%- @T('Description') %></a>
<% end %>
<% if @buttons: %>
<% for button in @buttons: %>
<a data-type="<%= button['data-type'] %>" class="btn <%= button['class'] %>"><%- @T( button.name ) %></a>
<% end %>
<% end %>
</div>
</div>

View file

@ -1,6 +1,6 @@
<form class="settings-entry" id="<%= @setting.name %>">
<h2><%- @T( @setting.title ) %></h2>
<p><%- @T( @setting.description ) %></p>
<p><%- @RichText( @setting.description ) %></p>
<div class="horizontal end">
<div class="form-item flex"></div>
<button type="submit" class="btn btn--primary"><%- @T( 'Submit' ) %></button>

View file

@ -0,0 +1,123 @@
class UpdateSettings4 < ActiveRecord::Migration
def up
Setting.create_or_update(
title: 'Authentication via Twitter',
name: 'auth_twitter',
area: 'Security::ThirdPartyAuthentication',
description: "@T('Enables user authentication via twitter. Register your app first at [Twitter Developer Site](https://dev.twitter.com/apps)')",
options: {
form: [
{
display: '',
null: true,
name: 'auth_twitter',
tag: 'boolean',
options: {
true => 'yes',
false => 'no',
},
},
],
},
state: false,
frontend: true
)
Setting.create_or_update(
title: 'Authentication via Facebook',
name: 'auth_facebook',
area: 'Security::ThirdPartyAuthentication',
description: "@T('Enables user authentication via Facebook. Register your app first at [Facebook Developer Site](https://developers.facebook.com/apps/)')",
options: {
form: [
{
display: '',
null: true,
name: 'auth_facebook',
tag: 'boolean',
options: {
true => 'yes',
false => 'no',
},
},
],
},
state: false,
frontend: true
)
Setting.create_or_update(
title: 'Ticket Hook Position',
name: 'ticket_hook_position',
area: 'Ticket::Base',
description: "@T('The format of the subject.')
* @T('**Right** means **Some Subject [Ticket#12345]**')
* @T('**Left** means **[Ticket#12345] Some Subject**')
* @T('**None** means **Some Subject** (without ticket number). In the last case you should enable *postmaster_follow_up_search_in* to recognize followups based on email headers and/or body.')",
options: {
form: [
{
display: '',
null: true,
name: 'ticket_hook_position',
tag: 'select',
options: {
'left' => 'Left',
'right' => 'Right',
'none' => 'None',
},
},
],
},
state: 'right',
frontend: false
)
Setting.create_or_update(
title: 'Ticket Number Format',
name: 'ticket_number',
area: 'Ticket::Number',
description: "@T('Selects the ticket number generator module.')
* @T('**Increment** increments the ticket number, the SystemID and the counter are used with SystemID.Counter format (e.g. 1010138, 1010139).')
* @T('With **Date** the ticket numbers will be generated by the current date, the SystemID and the counter. The format looks like Year.Month.Day.SystemID.counter (e.g. 201206231010138, 201206231010139).')
@T('With param 'Checksum => true' the counter will be appended as checksum to the string. The format looks like SystemID.Counter.CheckSum (e. g. 10101384, 10101392) or Year.Month.Day.SystemID.Counter.CheckSum (e.g. 2012070110101520, 2012070110101535).')",
options: {
form: [
{
display: '',
null: true,
name: 'ticket_number',
tag: 'select',
options: {
'Ticket::Number::Increment' => 'Increment (SystemID.Counter)',
'Ticket::Number::Date' => 'Date (Year.Month.Day.SystemID.Counter)',
},
},
],
},
state: 'Ticket::Number::Increment',
frontend: false
)
Setting.create_or_update(
title: 'Additional follow up detection',
name: 'postmaster_follow_up_search_in',
area: 'Email::Base',
description: 'In default the follow up check is done via the subject of an email. With this setting you can add more fields where the follow up ckeck is executed.',
options: {
form: [
{
display: '',
null: true,
name: 'postmaster_follow_up_search_in',
tag: 'checkbox',
options: {
'references' => 'References - Search for follow up also in In-Reply-To or References headers.',
'body' => 'Body - Search for follow up also in mail body.',
'attachment' => 'Attachment - Search for follow up also in attachments.',
},
},
],
},
state: [],
frontend: false
)
end
end

View file

@ -417,7 +417,7 @@ Setting.create_if_not_exists(
title: 'Authentication via Twitter',
name: 'auth_twitter',
area: 'Security::ThirdPartyAuthentication',
description: 'Enables user authentication via twitter. Register your app first at https://dev.twitter.com/apps',
description: "@T('Enables user authentication via twitter. Register your app first at [Twitter Developer Site](https://dev.twitter.com/apps)')",
options: {
form: [
{
@ -463,7 +463,7 @@ Setting.create_if_not_exists(
title: 'Authentication via Facebook',
name: 'auth_facebook',
area: 'Security::ThirdPartyAuthentication',
description: 'Enables user authentication via Facebook. Register your app first at https://developers.facebook.com/apps/',
description: "@T('Enables user authentication via Facebook. Register your app first at [Facebook Developer Site](https://developers.facebook.com/apps/)')",
options: {
form: [
{
@ -760,7 +760,10 @@ Setting.create_if_not_exists(
title: 'Ticket Hook Position',
name: 'ticket_hook_position',
area: 'Ticket::Base',
description: 'The format of the subject. "Left" means "[Ticket#12345] Some Subject", "Right" means "Some Subject [Ticket#12345]", "None" means "Some Subject" and no ticket number. In the last case you should enable "postmaster_follow_up_search_in" to recognize followups based on email headers and/or body.',
description: "@T('The format of the subject.')
* @T('**Right** means **Some Subject [Ticket#12345]**')
* @T('**Left** means **[Ticket#12345] Some Subject**')
* @T('**None** means **Some Subject** (without ticket number). In the last case you should enable *postmaster_follow_up_search_in* to recognize followups based on email headers and/or body.')",
options: {
form: [
{
@ -815,27 +818,15 @@ Setting.create_if_not_exists(
state: 'RE',
frontend: false
)
#Setting.create(
# :title => 'Ticket Subject Forward',
# :name => 'ticket_subject_fw',
# :area => 'Ticket::Base',
# :description => 'The text at the beginning of the subject when an email is forwarded, e.g. FW, Fwd, or WG.',
# :state => {
# :value => 'FW',
# },
# :frontend => false
#)
Setting.create_if_not_exists(
title: 'Ticket Number Format',
name: 'ticket_number',
area: 'Ticket::Number',
description: 'Selects the ticket number generator module. "Increment" increments the ticket
number, the SystemID and the counter are used with SystemID.Counter format (e.g. 1010138, 1010139).
With "Date" the ticket numbers will be generated by the current date, the SystemID and the counter.
The format looks like Year.Month.Day.SystemID.counter (e.g. 201206231010138, 201206231010139).
With param "Checksum => true" the counter will be appended as checksum to the string. The format
looks like SystemID.Counter.CheckSum (e. g. 10101384, 10101392) or Year.Month.Day.SystemID.Counter.CheckSum (e.g. 2012070110101520, 2012070110101535).',
description: "@T('Selects the ticket number generator module.')
* @T('**Increment** increments the ticket number, the SystemID and the counter are used with SystemID.Counter format (e.g. 1010138, 1010139).')
* @T('With **Date** the ticket numbers will be generated by the current date, the SystemID and the counter. The format looks like Year.Month.Day.SystemID.counter (e.g. 201206231010138, 201206231010139).')
@T('With param 'Checksum => true' the counter will be appended as checksum to the string. The format looks like SystemID.Counter.CheckSum (e. g. 10101384, 10101392) or Year.Month.Day.SystemID.Counter.CheckSum (e.g. 2012070110101520, 2012070110101535).')",
options: {
form: [
{
@ -1115,7 +1106,7 @@ Setting.create_if_not_exists(
title: 'Additional follow up detection',
name: 'postmaster_follow_up_search_in',
area: 'Email::Base',
description: 'In default the follow up check is done via the subject of an email. With this setting you can add more fields where the follow up ckeck is executed. "References" - Executes follow up check on In-Reply-To or References headers for mails. "Body" - Executes follow up check in mail body. "Attachment" - Executes follow up check in mail attachments.',
description: 'In default the follow up check is done via the subject of an email. With this setting you can add more fields where the follow up ckeck is executed.',
options: {
form: [
{
@ -1124,9 +1115,9 @@ Setting.create_if_not_exists(
name: 'postmaster_follow_up_search_in',
tag: 'checkbox',
options: {
'references' => 'References',
'body' => 'Body',
'attachment' => 'Attachment',
'references' => 'References - Search for follow up also in In-Reply-To or References headers.',
'body' => 'Body - Search for follow up also in mail body.',
'attachment' => 'Attachment - Search for follow up also in attachments.',
},
},
],