Fixes #2867 - KB links are in the header and footer of the public KB, Fixes #2834 - unclear meaning of "Public Menu" tab in KB admin

This commit is contained in:
Mantas Masalskis 2020-05-13 20:01:42 +03:00 committed by Thorsten Eckel
parent a69aebcd0c
commit cc2bc4f188
24 changed files with 607 additions and 125 deletions

View file

@ -91,6 +91,7 @@ RSpec/FilePath:
- 'spec/db/migrate/issue_2460_fix_corrupted_twitter_ids_spec.rb'
- 'spec/db/migrate/issue_2715_fix_broken_twitter_urls_spec.rb'
- 'spec/jobs/issue_2715_fix_broken_twitter_urls_job_spec.rb'
- 'spec/db/migrate/issue_2867_footer_header_public_link_spec.rb'
- 'spec/lib/import/base_factory_spec.rb'
# Offense count: 60

View file

@ -109,7 +109,7 @@ class App.ManageKnowledgeBase extends App.ControllerTabs
},{
name: 'Public Menu'
target: 'public_menu'
controller: App.KnowledgeBasePublicMenuForm
controller: App.KnowledgeBasePublicMenuManager
params: _.extend({}, params, { screen: 'public_menu' })
},{
name: 'Delete'

View file

@ -1,17 +1,69 @@
class App.KnowledgeBasePublicMenuForm extends App.Controller
events:
'show.bs.tab': 'willShow'
class App.KnowledgeBasePublicMenuForm extends App.ControllerModal
autoFocusOnFirstInput: false
includeForm: true
willShow: ->
@el.empty()
constructor: (params) ->
@formItems = []
@head = params.location.headline
super
for kb_locale in App.KnowledgeBase.find(@knowledge_base_id).kb_locales()
menu_items = App.KnowledgeBaseMenuItem.using_kb_locale(kb_locale)
formParams: =>
@formItems.map (elem) -> elem.buildData()
form_item = new App.KnowledgeBasePublicMenuFormItem(
knowledge_base_id: @knowledge_base_id,
kb_locale: kb_locale,
menu_items: menu_items
)
content: ->
@formItems = App.KnowledgeBase
.find(@knowledge_base_id)
.kb_locales()
.map (kb_locale) =>
menu_items = App.KnowledgeBaseMenuItem.using_kb_locale_location(kb_locale, @location.identifier)
@el.append form_item.el
new App.KnowledgeBasePublicMenuFormItem(
parent: @,
knowledge_base_id: @knowledge_base_id,
location: @location.identifier,
kb_locale: kb_locale,
menu_items: menu_items
)
@formItems.map (elem) -> elem.el
hasError: ->
@formItems
.map (elem) -> elem.hasError()
.filter((elem) -> elem)
.pop()
onSubmit: (e) ->
@preventDefaultAndStopPropagation(e)
if error = @hasError()
@showAlert(error)
return
@clearAlerts()
@formItems.forEach (elem) -> elem.toggleUserInteraction(false)
kb = App.KnowledgeBase.find(@knowledge_base_id)
@ajax(
id: 'update_menu_items'
type: 'PATCH'
url: kb.manageUrl('update_menu_items')
data: JSON.stringify(menu_items_sets: @formParams())
processData: true
success: @onSuccess
error: @onError
)
onSuccess: (data, status, xhr) =>
for formItem in @formItems
for menuItem in App.KnowledgeBaseMenuItem.using_kb_locale_location(formItem.kb_locale, formItem.location)
menuItem.remove(clear: true)
App.Collection.loadAssets(data.assets)
App.KnowledgeBaseMenuItem.trigger('kb_data_change_loaded')
@close()
onError: (xhr) =>
@showAlert(xhr.responseJSON?.error_human || 'Couldn\'t save changes')
@formItems.forEach (elem) -> elem.toggleUserInteraction(true)

View file

@ -3,7 +3,6 @@ class App.KnowledgeBasePublicMenuFormItem extends App.Controller
'click .js-add': 'add'
'click .js-remove': 'remove'
'input input': 'input'
'submit form': 'submit'
elements:
'.js-alert': 'alert'
@ -14,30 +13,29 @@ class App.KnowledgeBasePublicMenuFormItem extends App.Controller
render: ->
@html App.view('knowledge_base/public_menu_form_item')(
kb_locale_id: @kb_locale.id
rows: @menu_items
title: @kb_locale.systemLocale().name
rows: @menu_items
title: @kb_locale.systemLocale().name
)
@applySortable()
applySortable: ->
dndOptions =
tolerance: 'pointer'
distance: 15
opacity: 0.6
items: 'tr.sortable'
start: (e, ui) ->
tolerance: 'pointer'
distance: 15
opacity: 0.6
items: 'tr.sortable'
start: (e, ui) ->
ui.placeholder.height( ui.item.height() )
helper: (e, tr) ->
helper: (e, tr) ->
originals = tr.children()
helper = tr
helper.children().each (index, el) ->
# Set helper cell sizes to match the original sizes
$(@).width( originals.eq(index).width() )
return helper
update: @dndCallback
stop: (e, ui) ->
update: @dndCallback
stop: (e, ui) ->
ui.item.children().each (index, element) ->
element.style.width = ''
@ -66,13 +64,14 @@ class App.KnowledgeBasePublicMenuFormItem extends App.Controller
}
{
kb_locale_id: @$('form').data('kb-locale-id'),
menu_items: items
kb_locale_id: @kb_locale.id,
location: @location,
menu_items: items
}
input: ->
if @validateForm(false)
@hideAlert()
if !@hasError()
@parent.clearAlerts()
add: ->
el = App.view('knowledge_base/public_menu_form_item_row')()
@ -88,57 +87,14 @@ class App.KnowledgeBasePublicMenuFormItem extends App.Controller
else
row.remove()
showAlert: (message) ->
translated = App.i18n.translatePlain(message)
@alert
.text(translated)
.removeClass('hidden')
hideAlert: ->
@alert.addClass('hidden')
emptyFields: ->
findEmptyFields: ->
@$('tr.sortable:not(.js-deleted)')
.find('input[data-name]')
.toArray()
.filter (elem) -> $(elem).val().length == 0
validateForm: (showAlert = true) ->
if @emptyFields().length == 0
return true
hasError: ->
if @findEmptyFields().length == 0
return false
if showAlert
@showAlert('Please fill in all fields')
false
submit: (e) ->
@preventDefaultAndStopPropagation(e)
if !@validateForm()
return
@hideAlert()
@toggleUserInteraction(false)
kb = App.KnowledgeBase.find(@knowledge_base_id)
@ajax(
id: 'update_menu_items'
type: 'PATCH'
url: kb.manageUrl('update_menu_items')
data: JSON.stringify(@buildData())
processData: true
success: (data, status, xhr) =>
for menu_item in App.KnowledgeBaseMenuItem.using_kb_locale(@kb_locale)
menu_item.remove(clear: true)
App.Collection.loadAssets(data.assets)
@menu_items = App.KnowledgeBaseMenuItem.using_kb_locale(@kb_locale)
@render()
error: (xhr) =>
@showAlert(xhr.responseJSON?.error_human || 'Couldn\'t save changes')
@toggleUserInteraction(true)
)
'Please fill in all fields'

View file

@ -0,0 +1,49 @@
class App.KnowledgeBasePublicMenuManager extends App.Controller
events:
'show.bs.tab': 'willShow'
'click .js-edit': 'edit'
constructor: ->
super
@listenTo App.KnowledgeBaseMenuItem, 'kb_data_change_loaded', =>
@render()
willShow: ->
@render()
render: ->
kb = App.KnowledgeBase.find(@knowledge_base_id)
@html App.view('knowledge_base/public_menu_manager')(
locations: @locations(),
locales: kb.kb_locales()
)
locations: ->
kb = App.KnowledgeBase.find(@knowledge_base_id)
[
{
headline: 'Header menu',
identifier: 'header',
color: kb.color_header
},
{
headline: 'Footer menu',
identifier: 'footer'
}
]
edit: (e) =>
@preventDefaultAndStopPropagation(e)
identifier = $(e.target).data('target-location')
location = _.find @locations(), (elem) -> elem.identifier == identifier
new App.KnowledgeBasePublicMenuForm(
location: location,
knowledge_base_id: @knowledge_base_id
container: @el.closest('.main')
)

View file

@ -5,3 +5,8 @@ class App.KnowledgeBaseMenuItem extends App.Model
items = @findAllByAttribute('kb_locale_id', kb_locale.id)
items.sort( (a, b) -> if a.position < b.position then -1 else 1)
items
@using_kb_locale_location: (kb_locale, location) ->
items = @all().filter (elem) -> elem.kb_locale_id is kb_locale.id and elem.location is location
items.sort( (a, b) -> if a.position < b.position then -1 else 1)
items

View file

@ -1,4 +1,4 @@
<form data-kb-locale-id="<%= @kb_locale_id %>" class="settings-entry">
<div data-kb-locale-id="<%= @kb_locale_id %>" class="settings-entry">
<h2><%= @title %></h2>
<div class="js-alert alert alert--danger hidden"></div>
@ -28,8 +28,4 @@
</a>
</table>
</div>
<div class="horizontal justify-end">
<button type="submit" class="btn btn--primary"><%- @T('Submit') %></button>
</div>
</form>
</div>

View file

@ -0,0 +1,40 @@
<h2>
<%- @T 'Public Menu' %>
</h2>
<p class="help-text">
<%- @T 'Here you can add further links to your public FAQ page, which will be displayed either in the header or footer.' %>
</p>
<% for location in @locations: %>
<div class="settings-entry kb-menu-settings-entry">
<h3><%= @T(location.headline) %></h3>
<% for kb_locale in @locales: %>
<div class="kb-menu-preview">
<div class="label"><%= kb_locale.systemLocale().name %></div>
<div class="kb-menu-preview-container kb-menu-preview-container--<%= location.identifier %>" style="background-color: <%= location.color %>">
<% menu_items = App.KnowledgeBaseMenuItem.using_kb_locale_location(kb_locale, location.identifier) %>
<% if menu_items.length == 0: %>
<span class="text-muted"><%= @T 'Empty' %></span>
<% else: %>
<% for item in menu_items: %>
<a href="<%= item.url %>" target="_blank"><%= item.title %></a>
<% end %>
<% end %>
</div>
</div>
<% end %>
<a
class="btn btn--primary js-edit btn-manage-public-menu-edit"
href="#"
data-target-location="<%= location.identifier %>"
data-target-locale="<%= kb_locale.id %>">
<%= @T 'Edit' %>
</a>
</div>
<% end %>

View file

@ -2472,6 +2472,36 @@ input.has-error {
}
}
.kb-menu-preview {
margin-bottom: 1em;
&-container {
display: flex;
justify-content: flex-end;
border: 1px solid hsl(213,14%,91%);
&--footer {
justify-content: center;
}
}
a, span {
font-size: 14px;
padding: .5em 1em;
white-space: nowrap;
text-decoration: none;
line-height: 2em;
}
a {
color: hsl(206,8%,50%);
}
.label {
text-transform: none;
}
}
.modified-icon {
position: relative;
line-height: 1;
@ -11684,3 +11714,11 @@ span.is-disabled {
width: 100%;
height: 100%;
}
.btn-manage-public-menu-edit {
margin-top: 0
}
.kb-menu-settings-entry {
margin-bottom: 12px
}

View file

@ -31,13 +31,10 @@ class KnowledgeBase::ManageController < KnowledgeBase::BaseController
def update_menu_items
kb = KnowledgeBase.find params[:id]
kb_locale = kb.kb_locales.find params[:kb_locale_id]
KnowledgeBase::MenuItemUpdateAction
.new(kb_locale, params[:menu_items])
.perform!
affected_items = KnowledgeBase::MenuItemUpdateAction.update_using_params! kb, params_for_permission[:menu_items_sets]
render json: { assets: ApplicationModel::CanAssets.reduce(kb_locale.menu_items.reload, {}) }
render json: { assets: ApplicationModel::CanAssets.reduce(affected_items || [], {}) }
end
def destroy

View file

@ -24,9 +24,7 @@ class KnowledgeBase::Public::BaseController < ApplicationController
end
def menu_items
@menu_items ||= KnowledgeBase::MenuItem
.sorted
.using_locale(guess_locale_via_uri || filter_primary_kb_locale)
@menu_items ||= KnowledgeBase::MenuItem.using_locale(guess_locale_via_uri || filter_primary_kb_locale)
end
def system_locale_via_uri

View file

@ -1,17 +1,24 @@
class KnowledgeBase::MenuItem < ApplicationModel
belongs_to :kb_locale, class_name: 'KnowledgeBase::Locale', inverse_of: :menu_items, touch: true
validates :title, presence: true, length: { maximum: 100 }
validates :url, presence: true, length: { maximum: 100 }
validates :title, presence: true, length: { maximum: 100 }
validates :url, presence: true, length: { maximum: 500 }
validates :location, presence: true, inclusion: { in: %w[header footer] }
acts_as_list scope: :kb_locale, top_of_list: 0
acts_as_list scope: %i[kb_locale_id location], top_of_list: 0
scope :sorted, -> { order(position: :asc) }
scope :using_locale, ->(locale) { locale.present? ? joins(:kb_locale).where(knowledge_base_locales: { system_locale_id: locale.id } ) : none }
scope :sorted, -> { order(position: :asc) }
scope :using_locale, ->(locale) { locale.present? ? joins(:kb_locale).where(knowledge_base_locales: { system_locale_id: locale.id } ) : none }
scope :location, ->(location) { sorted.where(location: location) }
scope :location_header, -> { location(:header) }
scope :location_footer, -> { location(:footer) }
private
def add_protocol_prefix
return if url.blank?
url.strip!
return if url.match? %r{^\S+\:\/\/}

View file

@ -25,7 +25,7 @@
<% end %>
</h1>
<nav class="menu">
<% menu_items.each do |menu_item| %>
<% menu_items.location_header.each do |menu_item| %>
<%= link_to menu_item.title, menu_item.url, class: 'menu-item', target: menu_item.new_tab ? '_blank' : nil %>
<% end %>
</nav>
@ -51,6 +51,13 @@
<div class="copyright">
<%= @knowledge_base.translation.footer_note %>
</div>
<nav class="menu">
<% menu_items.location_footer.each do |menu_item| %>
<%= link_to menu_item.title, menu_item.url, class: 'menu-item', target: menu_item.new_tab ? '_blank' : nil %>
<% end %>
</nav>
<div class="language-picker">
<a class="btn btn--action" href="#" data-toggle="dropdown" aria-expanded="false">
<%= system_locale_via_uri.name %>

View file

@ -92,6 +92,7 @@ class InitializeKnowledgeBase < ActiveRecord::Migration[5.0]
create_table :knowledge_base_menu_items do |t|
t.references :kb_locale, null: false, foreign_key: { to_table: :knowledge_base_locales, on_delete: :cascade }
t.string :location, null: false, index: true
t.integer :position, null: false, index: true
t.string :title, null: false, limit: 100
t.string :url, null: false, limit: 500

View file

@ -0,0 +1,14 @@
class Issue2867FooterHeaderPublicLink < ActiveRecord::Migration[5.2]
def up
# return if it's a new setup
return if !Setting.find_by(name: 'system_init_done')
add_column :knowledge_base_menu_items, :location, :string, null: false, default: 'header'
add_index :knowledge_base_menu_items, :location
change_column_default :knowledge_base_menu_items, :location, nil
end
def down
remove_column :knowledge_base_menu_items, :location
end
end

View file

@ -1,10 +1,15 @@
class KnowledgeBase
class MenuItemUpdateAction
def initialize(kb_locale, menu_items_data)
def initialize(kb_locale, location, menu_items_data)
@kb_locale = kb_locale
@location = location
@menu_items_data = menu_items_data
end
def scope
@kb_locale.menu_items.location(@location)
end
def perform!
raise_unprocessable unless all_ids_present?
@ -16,15 +21,49 @@ class KnowledgeBase
end
end
# Mass-update KB menu items
#
# @param [KnowledgeBase] knowledge_base
# @param [[<Hash>]] params @see .update_location_params!
#
# @return [<KnowledgeBase::MenuItem>]
def self.update_using_params!(knowledge_base, params)
return if params.blank?
params
.map { |location_params| update_location_using_params! knowledge_base, location_params }
.map(&:reload)
.reduce(:+)
end
# Mass-update KB menu items in a given location
#
# @param [KnowledgeBase] knowledge_base
# @param [Hash] location_params
#
# @option location_params [Integer] :kb_locale_id
# @option location_params [String] :location header or footer
# @option location_params [[<Hash>]] :menu_items @see #update_order
def self.update_location_using_params!(knowledge_base, location_params)
action = new(
knowledge_base.kb_locales.find(location_params[:kb_locale_id]),
location_params[:location],
location_params[:menu_items]
)
action.perform!
action.scope
end
private
def update_order
old_items = @kb_locale.menu_items.to_a
old_items = scope.to_a
@menu_items_data
.reject { |elem| elem[:_destroy] }
.each_with_index do |data_elem, index|
item = old_items.find { |record| record.id == data_elem[:id] } || @kb_locale.menu_items.build
item = old_items.find { |record| record.id == data_elem[:id] } || scope.build
item.position = index
item.title = data_elem[:title]
@ -43,7 +82,7 @@ class KnowledgeBase
end
def all_ids_present?
old_ids = @kb_locale.menu_items.pluck(:id)
old_ids = scope.pluck(:id)
new_ids = @menu_items_data.map { |elem| elem[:id]&.to_i }.compact
old_ids.sort == new_ids.sort

View file

@ -0,0 +1,39 @@
require 'rails_helper'
RSpec.describe Issue2867FooterHeaderPublicLink, type: :db_migration do
self.use_transactional_tests = false # see comments on #without_index method
before { without_column(table, column: column) }
let(:table) { :knowledge_base_menu_items }
let(:column) { :location }
it 'adds an index' do
expect { migrate }.to change { index_exists?(table, column) }.to(true)
end
it 'sets no default' do
expect { migrate }
.not_to change {
KnowledgeBase::MenuItem.reset_column_information
KnowledgeBase::MenuItem.column_defaults['location']
}.from(nil)
end
it 'sets location for existing items' do
# create menu item without touching location column
menu_item = KnowledgeBase::MenuItem.acts_as_list_no_update do
attrs = attributes_for(:knowledge_base_menu_item)
attrs.delete :location
item = KnowledgeBase::MenuItem.new(attrs)
item.position = 0
item.kb_locale = create(:knowledge_base).kb_locales.first
item.save(validate: false)
item
end
expect { migrate }.to change { menu_item.reload.attributes['location'] }.from(nil).to('header')
end
end

View file

@ -1,8 +1,10 @@
FactoryBot.define do
factory 'knowledge_base/menu_item', aliases: %i[knowledge_base_menu_item] do
kb_locale { nil }
title { Faker::Kpop.iii_groups }
url { Faker::Internet.url }
kb_locale { nil }
sequence(:title) { |n| "menu_#{n}" }
url { Faker::Internet.url }
for_header
before :create do |menu_item|
if menu_item.kb_locale.blank?
@ -10,5 +12,13 @@ FactoryBot.define do
menu_item.kb_locale = kb.kb_locales.first
end
end
trait :for_footer do
location { 'footer' }
end
trait :for_header do
location { 'header' }
end
end
end

View file

@ -6,39 +6,64 @@ RSpec.describe KnowledgeBase::MenuItem, type: :model do
include_context 'factory'
context 'when url without prefix is added' do
before { kb_menu_item.update(url: Faker::Internet.domain_name) }
context 'item' do
it { is_expected.to validate_presence_of :title }
it { is_expected.to validate_presence_of :url }
it { is_expected.to validate_presence_of :location }
it { is_expected.to validate_inclusion_of(:location).in_array(%w[header footer]) }
end
it 'is saved' do
expect(kb_menu_item).not_to be_changed
context 'has scopes for' do
let(:kb_locale) { kb_menu_item.kb_locale }
let(:scope) { described_class.where(kb_locale: kb_locale) }
let!(:header) { create(:knowledge_base_menu_item, :for_header, kb_locale: kb_locale) }
let!(:footer) { create(:knowledge_base_menu_item, :for_footer, kb_locale: kb_locale) }
it 'header' do
expect(scope.location_header).to match [kb_menu_item, header]
end
it 'prefix is added to hostname' do
expect(kb_menu_item.url).to start_with 'http://'
it 'footer' do
expect(scope.location_footer).to match [footer]
end
end
context 'when url with custom prefix is added' do
before { kb_menu_item.update(url: "scheme://#{Faker::Internet.domain_name}") }
context 'when url' do
context 'without prefix is added' do
before { kb_menu_item.update(url: Faker::Internet.domain_name) }
it 'is saved' do
expect(kb_menu_item).not_to be_changed
it 'is saved' do
expect(kb_menu_item).not_to be_changed
end
it 'prefix is added to hostname' do
expect(kb_menu_item.url).to start_with 'http://'
end
end
it 'given scheme is not touched' do
expect(kb_menu_item.url).to start_with 'scheme://'
end
end
context 'with custom prefix is added' do
before { kb_menu_item.update(url: "scheme://#{Faker::Internet.domain_name}") }
context 'protocol prefix is not added to relative url' do
before { kb_menu_item.update(url: '/loremipsum') }
it 'is saved' do
expect(kb_menu_item).not_to be_changed
end
it 'is saved' do
expect(kb_menu_item).not_to be_changed
it 'given scheme is not touched' do
expect(kb_menu_item.url).to start_with 'scheme://'
end
end
it 'path is not modified' do
expect(kb_menu_item.url).not_to start_with 'http://'
context 'is relative and protocol prefix is not added' do
before { kb_menu_item.update(url: '/loremipsum') }
it 'is saved' do
expect(kb_menu_item).not_to be_changed
end
it 'path is not modified' do
expect(kb_menu_item.url).not_to start_with 'http://'
end
end
end
end

View file

@ -0,0 +1,67 @@
require 'rails_helper'
RSpec.describe 'Admin Knowledge Base Public Menu', type: :request, authenticated_as: :admin_user do
let(:url) { "/api/v1/knowledge_bases/manage/#{knowledge_base.id}/update_menu_items" }
let(:params) do
{
menu_items_sets: [{
"kb_locale_id": kb_locale.id,
"location": location,
"menu_items": menu_items
}]
}
end
let(:menu_item) { create(:knowledge_base_menu_item) }
let(:kb_locale) { menu_item.kb_locale }
let(:knowledge_base) { kb_locale.knowledge_base }
let(:location) { 'header' }
it 'edit title' do
attrs = to_params(menu_item)
attrs[:title] = 'new title'
params = build_params([attrs])
expect { make_request(params) }.to change { menu_item.reload.title }.to 'new title'
end
it 'delete item' do
attrs = to_params(menu_item)
attrs[:_destroy] = true
params = build_params([attrs])
expect { make_request(params) }.to change { KnowledgeBase::MenuItem.count }.by(-1)
end
it 'add item' do
new_item = {
title: 'new item',
new_tab: false,
url: '/new_url'
}
params = build_params([to_params(menu_item), new_item])
expect { make_request(params) }.to change { KnowledgeBase::MenuItem.count }.by(1)
end
def to_params(item)
item.slice :id, :title, :url, :new_tab
end
def make_request(params)
patch url, params: params, as: :json
end
def build_params(menu_items)
{
menu_items_sets: [{
"kb_locale_id": kb_locale.id,
"location": location,
"menu_items": menu_items
}]
}
end
end

View file

@ -53,6 +53,27 @@ module DbMigrationHelper
end
end
# Helper method for setting up specs on DB migrations that add columns.
# Make sure to define type: :db_migration in your RSpec.describe call
# and add `self.use_transactional_tests = false` to your context.
#
# @param [Symbol] from_table the name of the table with the indexed column
# @param [Symbol] name(s) of indexed column(s)
#
# @example
# without_column(:online_notifications, column: :user_id)
#
# @return [nil]
def without_column(from_table, column:)
suppress_messages do
Array(column).each do |elem|
next unless column_exists?(from_table, elem)
remove_column(from_table, elem)
end
end
end
# Helper method for setting up specs on DB migrations that add indices.
# Make sure to define type: :db_migration in your RSpec.describe call
# and add `self.use_transactional_tests = false` to your context.

View file

@ -35,3 +35,11 @@ RSpec.shared_context 'basic Knowledge Base', current_user_id: 1 do
create(:knowledge_base_answer, category: category, archived_at: 1.week.ago)
end
end
RSpec.shared_context 'Knowledge Base menu items', current_user_id: 1 do
let!(:menu_item_1) { create(:knowledge_base_menu_item, :for_header, kb_locale: primary_locale) }
let!(:menu_item_2) { create(:knowledge_base_menu_item, :for_header, kb_locale: primary_locale) }
let!(:menu_item_3) { create(:knowledge_base_menu_item, :for_footer, kb_locale: primary_locale) }
let!(:menu_item_4) { create(:knowledge_base_menu_item, :for_footer, kb_locale: alternative_locale) }
let!(:menu_item_5) { create(:knowledge_base_menu_item, :for_footer, kb_locale: alternative_locale) }
end

View file

@ -0,0 +1,74 @@
require 'rails_helper'
# https://github.com/zammad/zammad/issues/266
RSpec.describe 'Admin Panel > Knowledge Base > Public Menu', type: :system, authenticated: true do
include_context 'basic Knowledge Base'
include_context 'Knowledge Base menu items'
before do
visit '/#manage/knowledge_base'
find('a', text: 'Public Menu').click
end
context 'lists menu items' do
it { expect(find_locale('Footer menu', alternative_locale).text).to include menu_item_4.title }
it { expect(find_locale('Header menu', primary_locale).text).to include menu_item_1.title }
it { expect(find_locale('Header menu', alternative_locale).text).not_to include menu_item_2.title }
it { expect(find_locale('Header menu', primary_locale).text).to include menu_item_2.title }
end
context 'edit menu items' do
before do
find_location('Header menu').find('a', text: 'Edit').click
modal_ready
end
it 'edit menu item' do
find('input') { |elem| elem.value == menu_item_1.title }.fill_in with: 'test menu'
find('button', text: 'Submit').click
modal_disappear
expect(find_locale('Header menu', primary_locale).text).to include 'test menu'
end
it 'adds menu item' do
container = find(:css, '.modal-body h2', text: alternative_locale.system_locale.name).find(:xpath, '..')
container.find('a', text: 'Add').click
container.find('input') { |elem| elem['data-name'] == 'title' }.fill_in with: 'new item'
container.find('input') { |elem| elem['data-name'] == 'url' }.fill_in with: '/new_item'
find('button', text: 'Submit').click
modal_disappear
expect(find_locale('Header menu', alternative_locale).text).to include 'new item'
end
it 'deletes menu item' do
find(:css, '.modal-body')
.find('input') { |elem| elem.value == menu_item_1.title }
.ancestor('tr')
.find('.js-remove')
.click
find('button', text: 'Submit').click
modal_disappear
expect(find_locale('Header menu', alternative_locale).text).not_to include menu_item_1.title
end
end
def find_locale(location, locale)
find_location(location)
.find('.label', text: /#{Regexp.escape locale.system_locale.name}/i)
.ancestor('.kb-menu-preview')
end
def find_location(location)
find('h3', text: location).ancestor('.settings-entry')
end
end

View file

@ -0,0 +1,38 @@
require 'rails_helper'
RSpec.describe 'Public Knowledge Base menu items', type: :system, authenticated: false do
include_context 'basic Knowledge Base'
include_context 'Knowledge Base menu items'
before do
published_answer
visit help_no_locale_path
end
it 'shows header public link' do
expect(page).to have_css('header .menu-item', text: menu_item_1.title)
end
it 'shows another header public link' do
expect(page).to have_css('header .menu-item', text: menu_item_2.title)
end
it "doesn't show footer link in header" do
expect(page).not_to have_css('header .menu-item', text: menu_item_3.title)
end
it 'shows footer public link' do
expect(page).to have_css('footer .menu-item', text: menu_item_3.title)
end
it "doesn't show footer link of another locale" do
expect(page).not_to have_css('footer .menu-item', text: menu_item_4.title)
end
it 'shows public links in given order' do
index_1 = page.body.index menu_item_1.title
index_2 = page.body.index menu_item_2.title
expect(index_1).to be < index_2
end
end