Fixes #3559 - mentioned KB entries with the same title in different categories can not distinguished.
This commit is contained in:
parent
205c717f4d
commit
328845c283
11 changed files with 108 additions and 14 deletions
|
@ -90,9 +90,17 @@ class App.SearchableSelect extends Spine.Controller
|
||||||
renderOptions: (options) ->
|
renderOptions: (options) ->
|
||||||
html = ''
|
html = ''
|
||||||
for option in options
|
for option in options
|
||||||
|
classes = 'u-textTruncate'
|
||||||
|
if option.children
|
||||||
|
classes += ' js-enter'
|
||||||
|
else
|
||||||
|
classes += ' js-option'
|
||||||
|
if option.category
|
||||||
|
classes += ' with-category'
|
||||||
|
|
||||||
html += App.view('generic/searchable_select_option')
|
html += App.view('generic/searchable_select_option')
|
||||||
option: option
|
option: option
|
||||||
class: if option.children then 'js-enter' else 'js-option'
|
class: classes
|
||||||
html
|
html
|
||||||
|
|
||||||
renderAllOptions: (parentName, options, level) ->
|
renderAllOptions: (parentName, options, level) ->
|
||||||
|
|
|
@ -78,8 +78,13 @@ class App.SearchableAjaxSelect extends App.SearchableSelect
|
||||||
renderResponseItemAjax: (elem, data) ->
|
renderResponseItemAjax: (elem, data) ->
|
||||||
result = _.find(data.details, (detailElem) -> detailElem.type == elem.type and detailElem.id == elem.id)
|
result = _.find(data.details, (detailElem) -> detailElem.type == elem.type and detailElem.id == elem.id)
|
||||||
|
|
||||||
|
category = undefined
|
||||||
|
if result.type is 'KnowledgeBase::Answer::Translation' && result.subtitle
|
||||||
|
category = result.subtitle
|
||||||
|
|
||||||
if result
|
if result
|
||||||
{
|
{
|
||||||
|
category: category
|
||||||
name: result.title
|
name: result.title
|
||||||
value: elem.id
|
value: elem.id
|
||||||
}
|
}
|
||||||
|
|
|
@ -577,7 +577,8 @@
|
||||||
'flavor': 'agent',
|
'flavor': 'agent',
|
||||||
'index': 'KnowledgeBase::Answer::Translation',
|
'index': 'KnowledgeBase::Answer::Translation',
|
||||||
'url_type': 'agent',
|
'url_type': 'agent',
|
||||||
'highlight_enabled': false
|
'highlight_enabled': false,
|
||||||
|
'include_locale': true,
|
||||||
}),
|
}),
|
||||||
processData: true,
|
processData: true,
|
||||||
success: function(data, status, xhr) {
|
success: function(data, status, xhr) {
|
||||||
|
@ -588,6 +589,7 @@
|
||||||
.map(function(elem) {
|
.map(function(elem) {
|
||||||
if(result = _.find(data.details, function(detailElem) { return detailElem.type == elem.type && detailElem.id == elem.id })) {
|
if(result = _.find(data.details, function(detailElem) { return detailElem.type == elem.type && detailElem.id == elem.id })) {
|
||||||
return {
|
return {
|
||||||
|
'category': result.subtitle,
|
||||||
'name': result.title,
|
'name': result.title,
|
||||||
'value': elem.id,
|
'value': elem.id,
|
||||||
'url': result.url
|
'url': result.url
|
||||||
|
@ -599,8 +601,11 @@
|
||||||
var element = $('<li>')
|
var element = $('<li>')
|
||||||
.attr('data-id', elem.value)
|
.attr('data-id', elem.value)
|
||||||
.attr('data-url', elem.url)
|
.attr('data-url', elem.url)
|
||||||
.text(elem.name)
|
.addClass('u-clickable u-textTruncate with-category')
|
||||||
.addClass('u-clickable u-textTruncate')
|
|
||||||
|
element.append($('<small>').text(elem.category))
|
||||||
|
element.append('<br>')
|
||||||
|
element.append($('<span>').text(elem.name))
|
||||||
|
|
||||||
if (index == array.length-1) {
|
if (index == array.length-1) {
|
||||||
element.addClass('is-active')
|
element.addClass('is-active')
|
||||||
|
|
|
@ -38,6 +38,22 @@ class App.KnowledgeBaseCategory extends App.Model
|
||||||
memo.concat elem.categoriesForDropdown(nested: options.nested + 1, kb_locale: options.kb_locale)
|
memo.concat elem.categoriesForDropdown(nested: options.nested + 1, kb_locale: options.kb_locale)
|
||||||
, initial
|
, initial
|
||||||
|
|
||||||
|
categoriesForSearch: (options = {}) ->
|
||||||
|
result = [@guaranteedTitle(options.kb_locale.id)]
|
||||||
|
|
||||||
|
check = @
|
||||||
|
while check.parent()
|
||||||
|
result.push(check.parent().guaranteedTitle(options.kb_locale.id))
|
||||||
|
check = check.parent()
|
||||||
|
|
||||||
|
if options.full || result.length <= 2
|
||||||
|
result = result.reverse().join(' > ')
|
||||||
|
else
|
||||||
|
result = result.reverse()
|
||||||
|
result = "#{result[0]} > .. > #{result[result.length - 1]}"
|
||||||
|
|
||||||
|
result
|
||||||
|
|
||||||
configure_attributes: (kb_locale = undefined) ->
|
configure_attributes: (kb_locale = undefined) ->
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
<li role="presentation" class="<%= @class %>" data-value="<%= @option.value %>" title="<%= @option.name %><% if @detail: %><%= @detail %><% end %>">
|
<li role="presentation" class="<%= @class %>" data-value="<%= @option.value %>" title="<%= @option.name %><% if @detail: %><%= @detail %><% end %>">
|
||||||
|
<% if @option.category: %><small><%= @option.category %></small><br><% end %>
|
||||||
<span class="searchableSelect-option-text">
|
<span class="searchableSelect-option-text">
|
||||||
<%= @option.name %><% if @detail: %><span class="dropdown-detail"><%= @detail %></span><% end %>
|
<%= @option.name %><% if @detail: %><span class="dropdown-detail"><%= @detail %></span><% end %>
|
||||||
</span>
|
</span>
|
||||||
|
|
|
@ -27,6 +27,10 @@
|
||||||
-
|
-
|
||||||
<% end %>
|
<% end %>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="column">
|
||||||
|
<label><%- @T('Category') %></label>
|
||||||
|
<a href="<%= @object.parent().category().uiUrl(App.KnowledgeBaseLocale.find(@object.kb_locale_id)) %>" title="<%= @object.parent().category().categoriesForSearch({ full: true, kb_locale: App.KnowledgeBaseLocale.find(@object.kb_locale_id) }) %>"><%= @object.parent().category().guaranteedTitle(@object.kb_locale_id) %></a>
|
||||||
|
</div>
|
||||||
<div class="column">
|
<div class="column">
|
||||||
<label><%- @T('Language') %></label>
|
<label><%- @T('Language') %></label>
|
||||||
<%= App.KnowledgeBaseLocale.localeFor(@object).systemLocale().name %>
|
<%= App.KnowledgeBaseLocale.localeFor(@object).systemLocale().name %>
|
||||||
|
|
|
@ -8371,6 +8371,16 @@ footer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.dropdown li.with-category, .dropdown.dropdown--actions li.with-category {
|
||||||
|
line-height: 19.5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropdown.dropdown--actions li.with-category {
|
||||||
|
height: 39px;
|
||||||
|
padding: 0px 15px;
|
||||||
|
display: list-item;
|
||||||
|
}
|
||||||
|
|
||||||
.dropdown li:not(:first-child) {
|
.dropdown li:not(:first-child) {
|
||||||
box-shadow: 0 1px rgba(255,255,255,.13) inset;
|
box-shadow: 0 1px rgba(255,255,255,.13) inset;
|
||||||
}
|
}
|
||||||
|
@ -13023,4 +13033,3 @@ span.is-disabled {
|
||||||
.text-modules-box {
|
.text-modules-box {
|
||||||
max-height: 40vh;
|
max-height: 40vh;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -76,6 +76,12 @@ class KnowledgeBase::SearchController < ApplicationController
|
||||||
def public_item_details_answer(meta, object)
|
def public_item_details_answer(meta, object)
|
||||||
category_translation = object.answer.category.translation_preferred(object.kb_locale)
|
category_translation = object.answer.category.translation_preferred(object.kb_locale)
|
||||||
path = help_answer_path(category_translation, object, locale: object.kb_locale.system_locale.locale)
|
path = help_answer_path(category_translation, object, locale: object.kb_locale.system_locale.locale)
|
||||||
|
subtitle = object.answer.category.self_with_parents.map { |c| strip_tags(c.translation_preferred(object.kb_locale).title) }.reverse
|
||||||
|
subtitle = if subtitle.count <= 2
|
||||||
|
subtitle.join(' > ')
|
||||||
|
else
|
||||||
|
subtitle.values_at(0, -1).join(' > .. > ')
|
||||||
|
end
|
||||||
|
|
||||||
url = case url_type
|
url = case url_type
|
||||||
when :public
|
when :public
|
||||||
|
@ -91,7 +97,7 @@ class KnowledgeBase::SearchController < ApplicationController
|
||||||
date: object.updated_at,
|
date: object.updated_at,
|
||||||
url: url,
|
url: url,
|
||||||
title: meta.dig(:highlight, 'title')&.first || object.title,
|
title: meta.dig(:highlight, 'title')&.first || object.title,
|
||||||
subtitle: strip_tags(category_translation.title),
|
subtitle: subtitle,
|
||||||
body: meta.dig(:highlight, 'content.body')&.first || strip_tags(object.content.body).truncate(100)
|
body: meta.dig(:highlight, 'content.body')&.first || strip_tags(object.content.body).truncate(100)
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
|
@ -61,6 +61,18 @@ class KnowledgeBase::Category < ApplicationModel
|
||||||
[self] + children.map(&:self_with_children).flatten
|
[self] + children.map(&:self_with_children).flatten
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def self_with_parents
|
||||||
|
result = [self]
|
||||||
|
|
||||||
|
check = self
|
||||||
|
while check.parent.present?
|
||||||
|
result << check.parent
|
||||||
|
check = check.parent
|
||||||
|
end
|
||||||
|
|
||||||
|
result
|
||||||
|
end
|
||||||
|
|
||||||
def self_with_children_answers
|
def self_with_children_answers
|
||||||
KnowledgeBase::Answer.where(category_id: self_with_children_ids)
|
KnowledgeBase::Answer.where(category_id: self_with_children_ids)
|
||||||
end
|
end
|
||||||
|
|
|
@ -40,6 +40,10 @@ RSpec.describe KnowledgeBase::Category, type: :model, current_user_id: 1 do
|
||||||
expect(kb_category_with_tree.self_with_children.count).to eq 7
|
expect(kb_category_with_tree.self_with_children.count).to eq 7
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it 'fetches all parents' do
|
||||||
|
expect(grandchild_category.self_with_parents.count).to eq 3
|
||||||
|
end
|
||||||
|
|
||||||
it 'root category has no parent' do
|
it 'root category has no parent' do
|
||||||
expect(kb_category_with_tree.parent).to be_blank
|
expect(kb_category_with_tree.parent).to be_blank
|
||||||
end
|
end
|
||||||
|
|
|
@ -61,4 +61,28 @@ RSpec.describe 'Knowledge Base search with details', type: :request, searchindex
|
||||||
expect(json_response['details'][0]['subtitle']).to eq category.translation_to(primary_locale).title
|
expect(json_response['details'][0]['subtitle']).to eq category.translation_to(primary_locale).title
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context 'when answer tree is long' do
|
||||||
|
let(:category1) { create('knowledge_base/category') }
|
||||||
|
let(:category2) { create('knowledge_base/category', parent: category1) }
|
||||||
|
let(:category3) { create('knowledge_base/category', parent: category2) }
|
||||||
|
let(:answer_cut_tree) { create(:knowledge_base_answer, :published, :with_attachment, category: category3) }
|
||||||
|
let(:category4) { create('knowledge_base/category') }
|
||||||
|
let(:category5) { create('knowledge_base/category', parent: category4) }
|
||||||
|
let(:answer_full_tree) { create(:knowledge_base_answer, :published, :with_attachment, category: category5) }
|
||||||
|
|
||||||
|
before do
|
||||||
|
answer_cut_tree && answer_full_tree && rebuild_searchindex
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'returns category with cut tree', authenticated_as: -> { create(:admin) } do
|
||||||
|
post endpoint, params: { query: answer_cut_tree.translations.first.title }
|
||||||
|
expect(json_response['details'][0]['subtitle']).to eq("#{category1.translations.first.title} > .. > #{category3.translations.first.title}")
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'returns category with full tree', authenticated_as: -> { create(:admin) } do
|
||||||
|
post endpoint, params: { query: answer_full_tree.translations.first.title }
|
||||||
|
expect(json_response['details'][0]['subtitle']).to eq("#{category4.translations.first.title} > #{category5.translations.first.title}")
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in a new issue