- Added SearchableAjaxSelect.

- Refactored search_controller.
This commit is contained in:
Thorsten Eckel 2015-08-05 11:47:00 +02:00
parent f2b1dd2f26
commit 804e9ddcfe
6 changed files with 178 additions and 109 deletions

View file

@ -1435,7 +1435,18 @@ class InputsRef extends App.ControllerContent
id: 'project-name-123'
placeholder: 'Enter Project Name'
options: [{"value":0,"name":"Apple"},{"value":1,"name":"Microsoft","selected":true},{"value":2,"name":"Google"},{"value":3,"name":"Deutsche Bahn"},{"value":4,"name":"Sparkasse"},{"value":5,"name":"Deutsche Post"},{"value":6,"name":"Mitfahrzentrale"},{"value":7,"name":"Starbucks"},{"value":8,"name":"Mac Donalds"},{"value":9,"name":"Flixbus"},{"value":10,"name":"Betahaus"},{"value":11,"name":"Bruno Banani"},{"value":12,"name":"Alpina"},{"value":13,"name":"Samsung"},{"value":14,"name":"ChariTea"},{"value":15,"name":"fritz-kola"},{"value":16,"name":"Vitamin Water"},{"value":17,"name":"Znuny"},{"value":18,"name":"Max & Moritz"}]
@$('.searchableSelectPlaceholder').replaceWith( searchableSelectObject.el )
@$('.searchableSelectPlaceholder').replaceWith( searchableSelectObject.element() )
# selectable search
searchableAjaxSelectObject = new App.SearchableAjaxSelect
attribute:
name: 'user'
id: 'user-123'
placeholder: 'Enter User'
limt: 10
object: 'User'
@$('.searchableAjaxSelectPlaceholder').replaceWith( searchableAjaxSelectObject.element() )
# time and timeframe
@$('.time').timepicker()

View file

@ -14,7 +14,7 @@ class App.UserOrganizationAutocompletion extends App.Controller
@key = Math.floor( Math.random() * 999999 ).toString()
if !@attribute.source
@attribute.source = @apiPath + '/search_user_org'
@attribute.source = @apiPath + '/search/user-organization'
@build()
element: =>

View file

@ -3,12 +3,81 @@ class App.SearchableAjaxSelect extends App.SearchableSelect
onInput: (event) =>
super
# send ajax request @query
# convert requested object
# e.g. Ticket to ticket or AnotherObject to another_object
objectString = underscored( @options.attribute.object )
onAjaxResponse: (data) =>
# create common accessors
@apiPath = App.Config.get('api_path')
# create cache and cache key
@searchResultCache = @searchResultCache || {}
@cacheKey = "#{objectString}+#{@query}"
# use cache for search result
if @searchResultCache[@cacheKey]
return @onAjaxResponse( @searchResultCache[@cacheKey] )
# add timout for loader icon
clearTimeout @loaderTimeoutId
@loaderTimeoutId = setTimeout @showLoader, 1000
# start search request and update options
App.Ajax.request(
id: @options.attribute.id
type: 'GET'
url: "#{@apiPath}/search/#{objectString}"
data:
query: @query
limit: @options.attribute.limit
processData: true
success: @onAjaxResponse
)
onAjaxResponse: (data, status, xhr) =>
# clear timout and remove loader icon
clearTimeout @loaderTimeoutId
@el.removeClass('is-loading')
# cache search result
@searchResultCache[@cacheKey] = data
# load assets
App.Collection.loadAssets( data.assets )
# get options from search result
options = []
for object in data.result
if object.type is 'Ticket'
ticket = App.Ticket.find( object.id )
data =
name: "##{ticket.number} - #{ticket.title}"
value: ticket.id
options.push data
else if object.type is 'User'
user = App.User.find( object.id )
data =
name: "#{user.displayName()}"
value: user.id
options.push data
else if object.type is 'Organization'
organization = App.Organization.find( object.id )
data =
name: "#{organization.displayName()}"
value: organization.id
options.push data
# fill template with gathered options
@optionsList.html App.view('generic/searchable_select_options')
options: data
options: options
# refresh elements
@refreshElements()
# execute filter
@filterByQuery @query
showLoader: =>
@el.addClass('is-loading')

View file

@ -66,6 +66,10 @@
<div class="searchableSelectPlaceholder"></div>
</div>
<div class="select form-group">
<label for="b">Users (searchable ajax)</label>
<div class="searchableAjaxSelectPlaceholder"></div>
</div>
<h2>Checkbox</h2>
<div class="checkbox form-group">

View file

@ -3,8 +3,9 @@
class SearchController < ApplicationController
before_action :authentication_check
# GET /api/v1/search_user_org
def search_user_org
# GET|POST /api/v1/search/:objects
def search_generic
# enable search only for agents and admins
if !current_user.role?(Z_ROLENAME_AGENT) && !current_user.role?(Z_ROLENAME_ADMIN)
@ -16,11 +17,17 @@ class SearchController < ApplicationController
query = params[:query]
limit = params[:limit] || 10
# convert objects string into array of class names
# e.g. user-ticket-another_object = %w( User Ticket AnotherObject )
objects = params[:objects].split('-').map { |object|
object.camelize
}
# try search index backend
assets = {}
result = []
if SearchIndexBackend.enabled?
items = SearchIndexBackend.search( query, limit, %w(User Organization) )
items = SearchIndexBackend.search( query, limit, objects )
items.each { |item|
require item[:type].to_filename
record = Kernel.const_get( item[:type] ).find( item[:id] )
@ -29,34 +36,23 @@ class SearchController < ApplicationController
}
else
# do query
users = User.search(
query: query,
limit: limit,
current_user: current_user,
)
users.each do |user|
item = {
id: user.id,
type: user.class.to_s
}
result.push item
assets = user.assets(assets)
end
objects.each { |object|
organizations = Organization.search(
found_objects = object.constantize.search(
query: query,
limit: limit,
current_user: current_user,
)
organizations.each do |organization|
found_objects.each do |found_object|
item = {
id: organization.id,
type: organization.class.to_s
id: found_object.id,
type: found_object.class.to_s
}
result.push item
assets = organization.assets(assets)
assets = found_object.assets(assets)
end
}
end
render json: {
@ -68,64 +64,54 @@ class SearchController < ApplicationController
# GET /api/v1/search
def search
# build result list
tickets = Ticket.search(
limit: params[:limit],
query: params[:term],
current_user: current_user,
)
assets = {}
ticket_result = []
tickets.each do |ticket|
assets = ticket.assets(assets)
ticket_result.push ticket.id
end
# do query
users = User.search(
query: params[:term],
limit: params[:limit],
current_user: current_user,
)
user_result = []
users.each do |user|
user_result.push user.id
assets = user.assets(assets)
end
organizations = Organization.search(
query: params[:term],
limit: params[:limit],
current_user: current_user,
)
organization_result = []
organizations.each do |organization|
organization_result.push organization.id
assets = organization.assets(assets)
end
result = []
if ticket_result[0]
objects = %w( Ticket User Organization )
if SearchIndexBackend.enabled?
found_objects = {}
items = SearchIndexBackend.search( params[:term], params[:limit], objects )
items.each { |item|
require item[:type].to_filename
record = Kernel.const_get( item[:type] ).find( item[:id] )
assets = record.assets(assets)
found_objects[ item[:type] ] ||= []
found_objects[ item[:type] ].push item[:id]
}
found_objects.each { |object, object_ids|
data = {
name: 'Ticket',
ids: ticket_result,
name: object,
ids: object_ids,
}
result.push data
}
else
objects.each { |object|
found_objects = object.constantize.search(
query: params[:term],
limit: params[:limit],
current_user: current_user,
)
object_ids = []
found_objects.each do |found_object|
object_ids.push found_object.id
assets = found_object.assets(assets)
end
if user_result[0]
next if object_ids.empty?
data = {
name: 'User',
ids: user_result,
name: object,
ids: object_ids,
}
result.push data
end
if organization_result[0]
data = {
name: 'Organization',
ids: organization_result,
}
result.push data
end
# return result

View file

@ -4,7 +4,6 @@ Zammad::Application.routes.draw do
# search
match api_path + '/search', to: 'search#search', via: [:get, :post]
# search_user_org
match api_path + '/search_user_org', to: 'search#search_user_org', via: [:get, :post]
# search_generic
match api_path + '/search/:objects', to: 'search#search_generic', via: [:get, :post]
end