Merge pull request #23311 from opf/implementation/75165-show-error-states-in-page-link-component

[#75165] show error states in the page link component
This commit is contained in:
Eric Schubert
2026-05-26 16:32:58 +02:00
committed by GitHub
6 changed files with 175 additions and 15 deletions
@@ -29,14 +29,14 @@ See COPYRIGHT and LICENSE files for more details.
<%=
render(OpPrimer::InlineMacroComponent.new) do |inline_macro|
inline_macro.with_leading_visual_icon(icon: :"op-file-doc")
page_info_result.either(
->(page_info) do
inline_macro.with_leading_visual_icon(icon: :"op-file-doc")
render(Primer::Beta::Link.new(href: page_info.href)) { page_info.title }
end,
->(_error) do
render(Primer::Beta::Text.new(color: :muted)) { I18n.t("wikis.macro.page_not_found") }
->(error) do
inline_macro.with_leading_visual_icon(icon: :alert)
render(Primer::Beta::Text.new(color: :muted)) { error_text(error) }
end
)
end
@@ -34,5 +34,16 @@ module Wikis
include OpPrimer::ComponentHelpers
alias_method :page_info_result, :model
def error_text(error)
case error
in { code: :not_found }
I18n.t("wikis.page_links.errors.page_not_found")
in { code: :forbidden }
I18n.t("wikis.page_links.errors.page_access_forbidden")
else
I18n.t("wikis.page_links.errors.unexpected")
end
end
end
end
@@ -28,17 +28,27 @@ See COPYRIGHT and LICENSE files for more details.
++#%>
<%= render(Primer::Alpha::Stack.new(direction: :horizontal, gap: :condensed, align: :center)) do %>
<%= render(Primer::Beta::Octicon.new(icon: :"op-file-doc")) %>
<%=
if error?
render(Primer::Beta::Octicon.new(icon: :alert, color: :muted))
else
render(Primer::Beta::Octicon.new(icon: :"op-file-doc"))
end
%>
<%=
render(Primer::Alpha::StackItem.new(grow: true, classes: "ellipsis")) do
render(Primer::Beta::Link.new(href: page_href, scheme: :primary)) { page_title }
if error?
render(Primer::Beta::Text.new(color: :muted)) { page_title }
else
render(Primer::Beta::Link.new(href: page_href, scheme: :primary)) { page_title }
end
end
%>
<%=
if show_action_menu?
render(Primer::Alpha::ActionMenu.new) do |menu|
render(Primer::Alpha::ActionMenu.new(test_selector: "wiki-page-link-action-menu")) do |menu|
menu.with_show_button(icon: :"kebab-horizontal", "aria-label": t(:label_more), scheme: :invisible)
menu_items(menu)
end
@@ -45,17 +45,31 @@ module Wikis
end
def page_title
# TODO: Define behaviour for errors
page_info_result.either(->(pi) { pi.title }, ->(_) { "Nothing to see here" })
page_info_result.either(
->(pi) { pi.title },
->(error) do
case error
in { code: :not_found }
I18n.t("wikis.page_links.errors.page_not_found")
in { code: :forbidden }
I18n.t("wikis.page_links.errors.page_access_forbidden")
else
I18n.t("wikis.page_links.errors.unexpected")
end
end
)
end
def page_href
# TODO: Define behaviour for errors
page_info_result.either(->(pi) { pi.href }, ->(_) { "#" })
page_info_result.value!.href
end
def error?
page_info_result.failure?
end
def show_action_menu?
page_info_result.success? && actions.any?
actions.any?
end
def menu_items(menu)
+6 -3
View File
@@ -14,7 +14,7 @@ en:
universal_identifier: Universal identifier
url: Instance URL
wiki_audience: XWiki Audience
errors: {}
errors: { }
models:
wikis/inline_page_link:
one: Inline page link
@@ -57,6 +57,11 @@ en:
work_package_wikis_tab_component:
inline_page_links: Inline page links
referencing_pages: Referenced in
page_links:
errors:
page_not_found: Linked wiki page no longer available
page_access_forbidden: You do not have permission to access this wiki page
unexpected: An unexpected error occurred
page_link_component:
remove: Remove page link
relation_page_links_component:
@@ -135,5 +140,3 @@ en:
openproject_oauth_description: Allow XWiki to access OpenProject data using an OAuth.
xwiki_oauth: XWiki OAuth
xwiki_oauth_description: Allow OpenProject to access XWiki data using an OAuth.
macro:
page_not_found: Linked wiki page no longer available
@@ -0,0 +1,122 @@
# frozen_string_literal: true
#-- copyright
# OpenProject is an open source project management software.
# Copyright (C) the OpenProject GmbH
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License version 3.
#
# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2010-2013 the ChiliProject Team
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# See COPYRIGHT and LICENSE files for more details.
#++
require "spec_helper"
require_module_spec_helper
RSpec.describe Wikis::PageLinkComponent, type: :component do
let(:project) { create(:project) }
let(:work_package) { create(:work_package, project:) }
let(:provider) { create(:internal_wiki_provider) }
let(:page_link) { create(:relation_wiki_page_link, linkable: work_package, provider:) }
let(:page_info) do
Wikis::Adapters::Results::PageInfo.new(
identifier: page_link.identifier,
title: "Stormtrooper training",
provider:,
href: "https://wiki.death.star/Home/stormtrooper_training"
)
end
let(:page_info_result) { Success(page_info) }
let(:permissions) { [:manage_wiki_page_links] }
let(:actions) { [] }
current_user { create(:user, member_with_permissions: { project => permissions }) }
subject(:render_component) { render_inline(described_class.new(page_info_result, actions:, page_link:)) }
before { render_component }
it "renders the page link successfully" do
expect(page).to have_link(text: page_info.title, href: page_info.href)
end
context "when the page link has the remove action" do
let(:actions) { [:remove] }
context "when the user has no permission to manage wiki page links" do
let(:permissions) { [] }
it "does not render the action menu" do
expect(page).not_to have_test_selector("wiki-page-link-action-menu")
end
end
context "when the user has the permission to manage wiki page links" do
it "shows the remove page link action in the action menu" do
expect(page).to have_test_selector("wiki-page-link-action-menu")
end
end
end
context "when the page link has no actions" do
it "does not render the action menu" do
expect(page).not_to have_test_selector("wiki-page-link-action-menu")
end
end
context "if there are errors retrieving the page info" do
let(:page_info_result) do
Failure(
Wikis::Adapters::Results::Error.new(
source: Wikis::Adapters::Providers::Internal::Queries::PageInfo,
code: error_code
)
)
end
context "if the page was not found" do
let(:error_code) { :not_found }
it "renders an error text" do
expect(page).not_to have_link
expect(page).to have_text(I18n.t("wikis.page_links.errors.page_not_found"))
end
end
context "if the page access is forbidden" do
let(:error_code) { :forbidden }
it "renders an error text" do
expect(page).not_to have_link
expect(page).to have_text(I18n.t("wikis.page_links.errors.page_access_forbidden"))
end
end
context "if an unknown error occurred" do
let(:error_code) { :timeout }
it "renders an error text" do
expect(page).not_to have_link
expect(page).to have_text(I18n.t("wikis.page_links.errors.unexpected"))
end
end
end
end