diff --git a/app/assets/javascripts/app/controllers/_application_controller.coffee b/app/assets/javascripts/app/controllers/_application_controller.coffee index 9cfe5ff03..c6fc9fa3f 100644 --- a/app/assets/javascripts/app/controllers/_application_controller.coffee +++ b/app/assets/javascripts/app/controllers/_application_controller.coffee @@ -185,6 +185,17 @@ class App.Controller extends Spine.Controller formValidate: (data) -> App.ControllerForm.validate(data) + # get all query params of the url + queryParam: -> + return if !@query + pairs = @query.split(';') + params = {} + for pair in pairs + result = pair.match('(.+?)=(.*)') + if result && result[1] + params[result[1]] = result[2] + params + # redirectToLogin: (data) -> # diff --git a/app/assets/javascripts/app/controllers/_application_controller_generic.coffee b/app/assets/javascripts/app/controllers/_application_controller_generic.coffee index 7234f6c92..f764e5c57 100644 --- a/app/assets/javascripts/app/controllers/_application_controller_generic.coffee +++ b/app/assets/javascripts/app/controllers/_application_controller_generic.coffee @@ -309,6 +309,23 @@ class App.ControllerConfirm extends App.ControllerModal if @callback @callback() +class App.ControllerErrorModal extends App.ControllerModal + buttonClose: true + buttonCancel: false + buttonSubmit: 'Close' + #buttonClass: 'btn--danger' + head: 'Error' + #small: true + #shown: true + + content: -> + @message + + onSubmit: => + @close() + if @callback + @callback() + class App.ControllerDrox extends App.Controller constructor: (params) -> super diff --git a/app/assets/javascripts/app/controllers/_integration/idoit.coffee b/app/assets/javascripts/app/controllers/_integration/idoit.coffee new file mode 100644 index 000000000..724207069 --- /dev/null +++ b/app/assets/javascripts/app/controllers/_integration/idoit.coffee @@ -0,0 +1,94 @@ +class Index extends App.ControllerIntegrationBase + featureIntegration: 'idoit_integration' + featureName: 'i-doit' + featureConfig: 'idoit_config' + description: [ + ['This service allows you to connect i-doit objects with Zammad.'] + ] + events: + 'change .js-switch input': 'switch' + + render: => + super + new Form( + el: @$('.js-form') + ) + + new App.HttpLog( + el: @$('.js-log') + facility: 'idoit' + ) + +class Form extends App.Controller + events: + 'submit form': 'update' + + constructor: -> + super + @render() + + currentConfig: -> + App.Setting.get('idoit_config') + + setConfig: (value) -> + App.Setting.set('idoit_config', value, {notify: true}) + + render: => + @config = @currentConfig() + + @html App.view('integration/idoit')( + config: @config + ) + + update: (e) => + e.preventDefault() + @config = @formParam(e.target) + @validateAndSave() + + validateAndSave: => + @ajax( + id: 'idoit' + type: 'POST' + url: "#{@apiPath}/integration/idoit/verify" + data: JSON.stringify( + method: 'cmdb.object_types' + api_token: @config.api_token + endpoint: @config.endpoint + client_id: @config.client_id + ) + success: (data, status, xhr) => + if data.result is 'failed' + new App.ControllerErrorModal( + message: data.message + container: @el.closest('.content') + ) + return + @setConfig(@config) + + error: (data, status) => + + # do not close window if request is aborted + return if status is 'abort' + + details = data.responseJSON || {} + @notify( + type: 'error' + msg: App.i18n.translateContent(details.error_human || details.error || 'Unable to save!') + ) + ) + +class State + @current: -> + App.Setting.get('idoit_integration') + +App.Config.set( + 'IntegrationIdoit' + { + name: 'i-doit' + target: '#system/integration/idoit' + description: 'CMDB to document complex relations of your network components.' + controller: Index + state: State + } + 'NavBarIntegrations' +) diff --git a/app/assets/javascripts/app/controllers/agent_ticket_create.coffee b/app/assets/javascripts/app/controllers/agent_ticket_create.coffee index d4123771e..617c83f0c 100644 --- a/app/assets/javascripts/app/controllers/agent_ticket_create.coffee +++ b/app/assets/javascripts/app/controllers/agent_ticket_create.coffee @@ -9,6 +9,7 @@ class App.TicketCreate extends App.Controller constructor: (params) -> super + @sidebarState = {} # define default type @default_type = 'phone-in' @@ -91,6 +92,8 @@ class App.TicketCreate extends App.Controller else @$('[name="cc"]').closest('.form-group').addClass('hide') + App.TaskManager.touch(@task_key) + meta: => text = '' if @articleAttributes @@ -99,10 +102,10 @@ class App.TicketCreate extends App.Controller if title text = "#{text}: #{title}" meta = - url: @url() - head: text - title: text - id: @id + url: @url() + head: text + title: text + id: @id iconClass: 'pen' url: => @@ -335,25 +338,42 @@ class App.TicketCreate extends App.Controller user: App.Session.get() ) - new Sidebar( - el: @sidebar - params: @formDefault - textModule: @textModule + $('#tags').tokenfield() + + @sidebarWidget = new App.TicketCreateSidebar( + el: @sidebar + params: @formDefault + sidebarState: @sidebarState + task_key: @task_key + query: @query ) - $('#tags').tokenfield() + if @formDefault.customer_id + callback = (customer) => + @localUserInfoCallback(@formDefault, customer) + App.User.full(@formDefault.customer_id, callback) # update taskbar with new meta data App.TaskManager.touch(@task_key) localUserInfo: (e) => - + return if !@sidebarWidget params = App.ControllerForm.params($(e.target).closest('form')) - new Sidebar( - el: @sidebar - params: params - textModule: @textModule + if params.customer_id + callback = (customer) => + @localUserInfoCallback(params, customer) + App.User.full(params.customer_id, callback) + return + @localUserInfoCallback(params) + + localUserInfoCallback: (params, customer = {}) => + @sidebarWidget.render(params) + @textModule.reload( + config: App.Config.all() + user: App.Session.get() + ticket: + customer: customer ) cancel: (e) -> @@ -478,6 +498,10 @@ class App.TicketCreate extends App.Controller # scroll to top ui.scrollTo() + # add sidebar params + if ui.sidebarWidget + ui.sidebarWidget.commit(ticket_id: @id) + # access to group for group_id, access of App.Session.get('group_ids') if @group_id.toString() is group_id.toString() @@ -498,114 +522,6 @@ class App.TicketCreate extends App.Controller ) ) -class Sidebar extends App.Controller - constructor: -> - super - - # load user - if @params['customer_id'] - App.User.full(@params['customer_id'], @render) - return - - # render ui - @render() - - render: (user) => - - items = [] - if user - - showCustomer = (el) => - # update text module UI - if @textModule - @textModule.reload( - ticket: - customer: user - user: App.Session.get() - ) - - new App.WidgetUser( - el: el - user_id: user.id - ) - - editCustomer = (e, el) => - new App.ControllerGenericEdit( - id: @params.customer_id - genericObject: 'User' - screen: 'edit' - pageData: - title: 'Users' - object: 'User' - objects: 'Users' - container: @el.closest('.content') - ) - items.push { - head: 'Customer' - name: 'customer' - icon: 'person' - actions: [ - { - title: 'Edit Customer' - name: 'Edit Customer' - class: 'glyphicon glyphicon-edit' - callback: editCustomer - }, - ] - callback: showCustomer - } - - if user.organization_id - editOrganization = (e, el) => - new App.ControllerGenericEdit( - id: user.organization_id - genericObject: 'Organization' - pageData: - title: 'Organizations' - object: 'Organization' - objects: 'Organizations' - container: @el.closest('.content') - ) - showOrganization = (el) -> - new App.WidgetOrganization( - el: el - organization_id: user.organization_id - ) - items.push { - head: 'Organization' - name: 'organization' - icon: 'group' - actions: [ - { - title: 'Edit Organization' - name: 'Edit Organization' - class: 'glyphicon glyphicon-edit' - callback: editOrganization - }, - ] - callback: showOrganization - } - - showTemplates = (el) -> - - # show template UI - new App.WidgetTemplate( - el: el - #template_id: template['id'] - ) - - items.push { - head: 'Templates' - name: 'template' - icon: 'templates' - callback: showTemplates - } - - new App.Sidebar( - el: @el - items: items - ) - class Router extends App.ControllerPermanent requiredPermission: 'ticket.agent' constructor: (params) -> @@ -621,6 +537,9 @@ class Router extends App.ControllerPermanent if params.customer_id split = "/customer/#{params.customer_id}" + if params.query + split = "/query/#{params.query}" + id = Math.floor( Math.random() * 99999 ) @navigate "#ticket/create/id/#{id}#{split}" return @@ -631,6 +550,7 @@ class Router extends App.ControllerPermanent article_id: params.article_id type: params.type customer_id: params.customer_id + query: params.query id: params.id App.TaskManager.execute( @@ -646,6 +566,7 @@ App.Config.set('ticket/create/', Router, 'Routes') App.Config.set('ticket/create/id/:id', Router, 'Routes') App.Config.set('ticket/create/customer/:customer_id', Router, 'Routes') App.Config.set('ticket/create/id/:id/customer/:customer_id', Router, 'Routes') +App.Config.set('ticket/create/id/:id/query/:query', Router, 'Routes') # split ticket App.Config.set('ticket/create/:ticket_id/:article_id', Router, 'Routes') diff --git a/app/assets/javascripts/app/controllers/agent_ticket_create/sidebar.coffee b/app/assets/javascripts/app/controllers/agent_ticket_create/sidebar.coffee new file mode 100644 index 000000000..88b151449 --- /dev/null +++ b/app/assets/javascripts/app/controllers/agent_ticket_create/sidebar.coffee @@ -0,0 +1,43 @@ +class App.TicketCreateSidebar extends App.Controller + constructor: -> + super + @render() + + reload: (args) => + for key, backend of @sidebarBackends + if backend && backend.reload + backend.reload(args) + + commit: (args) => + for key, backend of @sidebarBackends + if backend && backend.commit + backend.commit(args) + + render: (params) => + if params + @params = params + @sidebarBackends ||= {} + @sidebarItems = [] + sidebarBackends = App.Config.get('TicketCreateSidebar') + keys = _.keys(sidebarBackends).sort() + for key in keys + if !@sidebarBackends[key] || !@sidebarBackends[key].reload + @sidebarBackends[key] = new sidebarBackends[key]( + params: @params + query: @query + taskGet: @taskGet + ) + else + @sidebarBackends[key].reload( + params: @params + query: @query + ) + item = @sidebarBackends[key].sidebarItem() + if item + @sidebarItems.push item + + new App.Sidebar( + el: @el + sidebarState: @sidebarState + items: @sidebarItems + ) diff --git a/app/assets/javascripts/app/controllers/agent_ticket_create/sidebar_customer.coffee b/app/assets/javascripts/app/controllers/agent_ticket_create/sidebar_customer.coffee new file mode 100644 index 000000000..cbfd4e7e9 --- /dev/null +++ b/app/assets/javascripts/app/controllers/agent_ticket_create/sidebar_customer.coffee @@ -0,0 +1,38 @@ +class SidebarCustomer extends App.Controller + sidebarItem: => + return if !@permissionCheck('ticket.agent') + return if !@params.customer_id + { + head: 'Customer' + name: 'customer' + icon: 'person' + actions: [ + { + title: 'Edit Customer' + name: 'customer-edit' + callback: @editCustomer + }, + ] + callback: @showCustomer + } + + showCustomer: (el) => + @el = el + new App.WidgetUser( + el: @el + user_id: @params.customer_id + ) + + editCustomer: => + new App.ControllerGenericEdit( + id: @params.customer_id + genericObject: 'User' + screen: 'edit' + pageData: + title: 'Users' + object: 'User' + objects: 'Users' + container: @el.closest('.content') + ) + +App.Config.set('200-Customer', SidebarCustomer, 'TicketCreateSidebar') diff --git a/app/assets/javascripts/app/controllers/agent_ticket_create/sidebar_organization.coffee b/app/assets/javascripts/app/controllers/agent_ticket_create/sidebar_organization.coffee new file mode 100644 index 000000000..db2a9239d --- /dev/null +++ b/app/assets/javascripts/app/controllers/agent_ticket_create/sidebar_organization.coffee @@ -0,0 +1,41 @@ +class SidebarOrganization extends App.Controller + sidebarItem: => + return if !@permissionCheck('ticket.agent') + return if !@params.customer_id + return if !App.User.exists(@params.customer_id) + customer = App.User.find(@params.customer_id) + @organization_id = customer.organization_id + return if !@organization_id + { + head: 'Organization' + name: 'organization' + icon: 'group' + actions: [ + { + title: 'Edit Organization' + name: 'organization-edit' + callback: @editOrganization + }, + ] + callback: @showOrganization + } + + showOrganization: (el) => + @el = el + new App.WidgetOrganization( + el: @el + organization_id: @organization_id + ) + + editOrganization: => + new App.ControllerGenericEdit( + id: @organization_id, + genericObject: 'Organization' + pageData: + title: 'Organizations' + object: 'Organization' + objects: 'Organizations' + container: @el.closest('.content') + ) + +App.Config.set('300-Organization', SidebarOrganization, 'TicketCreateSidebar') diff --git a/app/assets/javascripts/app/controllers/agent_ticket_create/sidebar_template.coffee b/app/assets/javascripts/app/controllers/agent_ticket_create/sidebar_template.coffee new file mode 100644 index 000000000..bb724bc83 --- /dev/null +++ b/app/assets/javascripts/app/controllers/agent_ticket_create/sidebar_template.coffee @@ -0,0 +1,21 @@ +class SidebarTemplate extends App.Controller + sidebarItem: => + return if !@permissionCheck('ticket.agent') + { + head: 'Templates' + name: 'template' + icon: 'templates' + actions: [] + callback: @showTemplates + } + + showTemplates: (el) => + @el = el + + # show template UI + new App.WidgetTemplate( + el: el + #template_id: template['id'] + ) + +App.Config.set('100-Template', SidebarTemplate, 'TicketCreateSidebar') diff --git a/app/assets/javascripts/app/controllers/idoit_object_selector.coffee b/app/assets/javascripts/app/controllers/idoit_object_selector.coffee new file mode 100644 index 000000000..d2b7f2065 --- /dev/null +++ b/app/assets/javascripts/app/controllers/idoit_object_selector.coffee @@ -0,0 +1,100 @@ +class App.IdoitObjectSelector extends App.ControllerModal + buttonClose: true + buttonCancel: true + buttonSubmit: true + head: 'i-doit' + + content: -> + @ajax( + id: 'idoit-object-selector' + type: 'POST' + url: "#{@apiPath}/integration/idoit" + data: JSON.stringify(method: 'cmdb.object_types') + success: (data, status, xhr) => + if data.result is 'failed' + @contentInline = data.message + @render() + return + + result = _.sortBy(data.response.result, 'title') + @contentInline = $(App.view('integration/idoit_object_selector')()) + + @contentInline.find('.js-typeSelect').html(@renderTypeSelector(result)) + + @contentInline.filter('.js-search').on('change', 'select, input', (e) => + params = @formParam(e.target) + @search(params) + ) + @contentInline.filter('.js-search').on('keyup', 'input', (e) => + params = @formParam(e.target) + @search(params) + ) + @render() + @$('.js-input').focus() + + error: (xhr, status, error) => + + # do not close window if request is aborted + return if status is 'abort' + + # show error message + @contentInline = 'Unable to load content' + @render() + ) + '' + + search: (filter) => + if _.isEmpty(filter.title) + delete filter.title + else + filter.title = "%#{filter.title}%" + @ajax( + id: 'idoit-object-selector' + type: 'POST' + url: "#{@apiPath}/integration/idoit" + data: JSON.stringify(method: 'cmdb.objects', filter: filter) + success: (data, status, xhr) => + @renderResult(data.response.result) + + error: (xhr, status, error) => + + # do not close window if request is aborted + return if status is 'abort' + + # show error message + @contentInline = 'Unable to load content' + @render() + ) + + renderResult: (items) => + table = App.view('integration/idoit_object_result')( + items: items + ) + @el.find('.js-result').html(table) + + renderTypeSelector: (result) -> + options = {} + for item in result + options[item.id] = item.title + return App.UiElement.searchable_select.render( + name: 'type' + multiple: false + limit: 100 + null: false + nulloption: false + options: options + ) + + onSubmit: (e) => + form = @el.find('.js-result') + params = @formParam(form) + return if _.isEmpty(params.object_id) + + if _.isArray(params.object_id) + object_ids = params.object_id + else + object_ids = [params.object_id] + + @formDisable(form) + @callback(object_ids, @) + diff --git a/app/assets/javascripts/app/controllers/ticket_zoom.coffee b/app/assets/javascripts/app/controllers/ticket_zoom.coffee index 7edf7bdcf..a08b201be 100644 --- a/app/assets/javascripts/app/controllers/ticket_zoom.coffee +++ b/app/assets/javascripts/app/controllers/ticket_zoom.coffee @@ -473,6 +473,7 @@ class App.TicketZoom extends App.Controller sidebarState: @sidebarState object_id: @ticket_id model: 'Ticket' + query: @query taskGet: @taskGet task_key: @task_key formMeta: @formMeta @@ -797,6 +798,9 @@ class App.TicketZoom extends App.Controller # reset form after save @reset() + if @sidebar + @sidebar.commit() + if taskAction is 'closeNextInOverview' if @overview_id current_position = 0 diff --git a/app/assets/javascripts/app/controllers/ticket_zoom/sidebar.coffee b/app/assets/javascripts/app/controllers/ticket_zoom/sidebar.coffee index 874922998..1eb4d68ea 100644 --- a/app/assets/javascripts/app/controllers/ticket_zoom/sidebar.coffee +++ b/app/assets/javascripts/app/controllers/ticket_zoom/sidebar.coffee @@ -9,18 +9,32 @@ class App.TicketZoomSidebar extends App.ObserverController if backend && backend.reload backend.reload(args) + commit: (args) => + for key, backend of @sidebarBackends + if backend && backend.commit + backend.commit(args) + render: (ticket) => - @sidebarBackends = {} + @sidebarBackends ||= {} @sidebarItems = [] sidebarBackends = App.Config.get('TicketZoomSidebar') keys = _.keys(sidebarBackends).sort() for key in keys - @sidebarBackends[key] = new sidebarBackends[key]( - ticket: ticket - taskGet: @taskGet - formMeta: @formMeta - markForm: @markForm - ) + if !@sidebarBackends[key] || !@sidebarBackends[key].reload + @sidebarBackends[key] = new sidebarBackends[key]( + ticket: ticket + query: @query + taskGet: @taskGet + formMeta: @formMeta + markForm: @markForm + ) + else + @sidebarBackends[key].reload( + params: @params + query: @query + formMeta: @formMeta + markForm: @markForm + ) item = @sidebarBackends[key].sidebarItem() if item @sidebarItems.push item diff --git a/app/assets/javascripts/app/controllers/ticket_zoom/sidebar_idoit.coffee b/app/assets/javascripts/app/controllers/ticket_zoom/sidebar_idoit.coffee new file mode 100644 index 000000000..5ebce7924 --- /dev/null +++ b/app/assets/javascripts/app/controllers/ticket_zoom/sidebar_idoit.coffee @@ -0,0 +1,132 @@ +class SidebarIdoit extends App.Controller + sidebarItem: => + return if !@Config.get('idoit_integration') + { + head: 'i-doit' + name: 'idoit' + icon: 'printer' + actions: [ + { + title: 'Change Objects' + name: 'objects-change' + callback: @changeObjects + }, + ] + callback: @showObjects + } + + changeObjects: => + new App.IdoitObjectSelector( + task_key: @task_key + container: @el.closest('.content') + callback: (objectIds, objectSelectorUi) => + if @ticket && @ticket.id + @updateTicket(@ticket.id, objectIds, => + objectSelectorUi.close() + @showObjectsContent(objectIds) + ) + return + objectSelectorUi.close() + @showObjectsContent(objectIds) + ) + + showObjects: (el) => + @el = el + + # show placeholder + @objectIds ||= [] + if @ticket && @ticket.preferences && @ticket.preferences.idoit && @ticket.preferences.idoit.object_ids + @objectIds = @ticket.preferences.idoit.object_ids + queryParams = @queryParam() + if queryParams && queryParams.idoit_object_ids + @objectIds.push queryParams.idoit_object_ids + @showObjectsContent() + + showObjectsContent: (objectIds) => + if objectIds + @objectIds = @objectIds.concat(objectIds) + + # show placeholder + if _.isEmpty(@objectIds) + @html("
+ | <%- @T('ID') %> | +<%- @T('Name') %> | +<%- @T('Status') %> | +<%- @T('Link') %> | + + + <% for item in @items: %> +
---|---|---|---|---|
+ | <%= item.id %> | +<%= item.title %> | +<%= item.cmdb_status_title %> | +i-doit | +