mirror of
https://github.com/opf/openproject.git
synced 2026-06-14 03:30:14 +00:00
Refactor static links to ensure users have to go through url_for
This ensures links will be translated if they are part of the website
This commit is contained in:
@@ -22,7 +22,7 @@
|
||||
frameborder: "0",
|
||||
height: "400",
|
||||
width: "100%",
|
||||
src: OpenProject::Static::Links.links[:enterprise_welcome_video][:href],
|
||||
src: OpenProject::Static::Links.url_for(:enterprise_welcome_video),
|
||||
allowfullscreen: true)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -79,7 +79,7 @@ module WorkPackages
|
||||
end
|
||||
|
||||
def learn_more_href
|
||||
OpenProject::Static::Links.links[:progress_tracking_docs][:href]
|
||||
OpenProject::Static::Links.url_for(:progress_tracking_docs)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
@@ -32,11 +32,11 @@ class HelpController < ApplicationController
|
||||
no_authorization_required! :keyboard_shortcuts, :text_formatting
|
||||
|
||||
def keyboard_shortcuts
|
||||
redirect_to OpenProject::Static::Links[:shortcuts][:href], allow_other_host: true
|
||||
redirect_to OpenProject::Static::Links.url_for(:shortcuts), allow_other_host: true
|
||||
end
|
||||
|
||||
def text_formatting
|
||||
default_link = OpenProject::Static::Links[:text_formatting][:href]
|
||||
default_link = OpenProject::Static::Links.url_for(:text_formatting)
|
||||
help_link = OpenProject::Configuration.force_formatting_help_link.presence || default_link
|
||||
|
||||
redirect_to help_link, allow_other_host: true
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
|
||||
class My::LookAndFeelForm < ApplicationForm
|
||||
include ApplicationHelper
|
||||
|
||||
form do |f|
|
||||
f.select_list(
|
||||
name: :theme,
|
||||
@@ -65,7 +66,7 @@ class My::LookAndFeelForm < ApplicationForm
|
||||
f.check_box name: :disable_keyboard_shortcuts,
|
||||
label: I18n.t("activerecord.attributes.user_preference.disable_keyboard_shortcuts"),
|
||||
caption: I18n.t("activerecord.attributes.user_preference.disable_keyboard_shortcuts_caption_html",
|
||||
href: OpenProject::Static::Links.links[:shortcuts][:href]).html_safe
|
||||
href: OpenProject::Static::Links.url_for(:shortcuts)).html_safe
|
||||
|
||||
f.submit(name: :submit,
|
||||
label: I18n.t("activerecord.attributes.user_preference.button_update_look_and_feel"),
|
||||
|
||||
@@ -31,11 +31,12 @@
|
||||
module StaticLinksHelper
|
||||
##
|
||||
# Create a static link to the given key entry
|
||||
def static_link_to(key, label: nil)
|
||||
item = OpenProject::Static::Links.links.fetch key
|
||||
def static_link_to(*path, label: nil)
|
||||
href = OpenProject::Static::Links.url_for(*path)
|
||||
label_text = label || OpenProject::Static::Links.label_for(*path)
|
||||
|
||||
link_to label || t(item[:label]),
|
||||
item[:href],
|
||||
link_to label_text,
|
||||
href,
|
||||
class: "openproject--static-link",
|
||||
target: "_blank", rel: "noopener"
|
||||
end
|
||||
@@ -44,8 +45,7 @@ module StaticLinksHelper
|
||||
# Link to the correct installation guides for the current selected method
|
||||
def installation_guide_link
|
||||
val = OpenProject::Configuration.installation_type
|
||||
link = OpenProject::Static::Links.links[:"#{val}_installation"] || OpenProject::Static::Links.links[:installation_guides]
|
||||
|
||||
link[:href]
|
||||
# Try specific installation type first, fallback to general installation guides
|
||||
OpenProject::Static::Links.url_for(:"#{val}_installation") || OpenProject::Static::Links.url_for(:installation_guides)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -73,7 +73,7 @@ See COPYRIGHT and LICENSE files for more details.
|
||||
if display_security_badge_graphic?
|
||||
content = content_tag :object, nil, data: security_badge_url, type: "image/svg+xml"
|
||||
content += link_to "",
|
||||
::OpenProject::Static::Links[:security_badge_documentation][:href],
|
||||
::OpenProject::Static::Links.url_for(:security_badge_documentation),
|
||||
title: t(:label_what_is_this),
|
||||
class: "security-badge--help-icon icon-context icon-help1",
|
||||
target: "_blank"
|
||||
|
||||
@@ -84,7 +84,7 @@ See COPYRIGHT and LICENSE files for more details.
|
||||
<p><%= t(:text_line_separated) %></p>
|
||||
<p><%= t(
|
||||
:setting_apiv3_cors_origins_text_html,
|
||||
origin_link: ::OpenProject::Static::Links[:origin_mdn_documentation][:href]
|
||||
origin_link: ::OpenProject::Static::Links.url_for(:origin_mdn_documentation)
|
||||
) %></p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -69,7 +69,7 @@ See COPYRIGHT and LICENSE files for more details.
|
||||
<div class="form--field">
|
||||
<%= setting_select :first_week_of_year, [[day_name(1), "1"], [day_name(4), "4"]], blank: :label_language_based, container_class: "-wide" %>
|
||||
<div class="form--field-instructions">
|
||||
<p><%= t("settings.date_format.first_week_of_year_text_html", link: OpenProject::Static::Links[:date_format_settings_documentation][:href]) %></p>
|
||||
<p><%= t("settings.date_format.first_week_of_year_text_html", link: OpenProject::Static::Links.url_for(:date_format_settings_documentation)) %></p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -96,7 +96,7 @@ See COPYRIGHT and LICENSE files for more details.
|
||||
<%= t(
|
||||
:text_notice_security_badge_displayed_html,
|
||||
information_panel_label: t(:label_information),
|
||||
more_info_url: ::OpenProject::Static::Links[:security_badge_documentation][:href],
|
||||
more_info_url: ::OpenProject::Static::Links.url_for(:security_badge_documentation),
|
||||
information_panel_path: info_admin_index_path
|
||||
) %>
|
||||
</span>
|
||||
|
||||
@@ -50,7 +50,7 @@ See COPYRIGHT and LICENSE files for more details.
|
||||
<div class="form--field">
|
||||
<%= setting_check_box :ical_enabled, size: 6 %>
|
||||
<div class="form--field-instructions">
|
||||
<p><%= t("settings.icalendar.enable_subscriptions_text_html", link: OpenProject::Static::Links[:ical_docs][:href]) %></p>
|
||||
<p><%= t("settings.icalendar.enable_subscriptions_text_html", link: OpenProject::Static::Links.url_for(:ical_docs)) %></p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@@ -27,7 +27,7 @@ See COPYRIGHT and LICENSE files for more details.
|
||||
|
||||
++#%>
|
||||
<% content_for :header_tags do %>
|
||||
<%= nonced_javascript_include_tag OpenProject::Static::Links.links[:chargebee][:href],
|
||||
<%= nonced_javascript_include_tag OpenProject::Static::Links.url_for(:chargebee),
|
||||
"data-cb-site": OpenProject::Configuration.enterprise_chargebee_site %>
|
||||
<% end %>
|
||||
|
||||
|
||||
@@ -51,7 +51,7 @@
|
||||
<%= content_tag :div, class: "security-badge--container" do %>
|
||||
<%= content_tag :object, nil, data: security_badge_url, type: "image/svg+xml" %>
|
||||
<%= link_to "",
|
||||
::OpenProject::Static::Links[:security_badge_documentation][:href],
|
||||
::OpenProject::Static::Links.url_for(:security_badge_documentation),
|
||||
title: t(:label_what_is_this),
|
||||
class: "security-badge--help-icon icon-context icon-help1",
|
||||
target: "_blank", rel: "noopener" %>
|
||||
|
||||
@@ -11,30 +11,63 @@
|
||||
<li>
|
||||
<%= static_link_to :forums %></li>
|
||||
<li>
|
||||
<%= static_link_to (EnterpriseToken.active? ? :enterprise_support : :enterprise_support_as_community) %>
|
||||
<%= static_link_to(EnterpriseToken.active? ? :enterprise_support : :enterprise_support_as_community) %>
|
||||
</li>
|
||||
<li>
|
||||
<%= link_to(
|
||||
t("label_openproject_website"), "#{OpenProject::Static::Links.links[:website][:href]}/?utm_source=unknown&utm_medium=op-instance&utm_campaign=website-home-screen",
|
||||
{ aria: { label: t("label_openproject_website") },
|
||||
t("label_openproject_website"),
|
||||
OpenProject::Static::Links.url_for(
|
||||
:website,
|
||||
url_params: {
|
||||
utm_source: "unknown",
|
||||
utm_medium: "op-instance",
|
||||
utm_campaign: "website-home-screen"
|
||||
}
|
||||
),
|
||||
{
|
||||
aria: { label: t("label_openproject_website") },
|
||||
target: "_blank",
|
||||
title: t("label_openproject_website"), rel: "noopener" }
|
||||
title: t("label_openproject_website"),
|
||||
rel: "noopener"
|
||||
}
|
||||
) %>
|
||||
</li>
|
||||
<li>
|
||||
<%= link_to(
|
||||
t("homescreen.links.security_alerts"), "#{OpenProject::Static::Links.links[:security_alerts][:href]}/?utm_source=unknown&utm_medium=op-instance&utm_campaign=security-alerts-home-screen",
|
||||
{ aria: { label: t("homescreen.links.security_alerts") },
|
||||
t("homescreen.links.security_alerts"),
|
||||
OpenProject::Static::Links.url_for(
|
||||
:security_alerts,
|
||||
url_params: {
|
||||
utm_source: "unknown",
|
||||
utm_medium: "op-instance",
|
||||
utm_campaign: "security-alerts-home-screen"
|
||||
}
|
||||
),
|
||||
{
|
||||
aria: { label: t("homescreen.links.security_alerts") },
|
||||
target: "_blank",
|
||||
title: t("homescreen.links.security_alerts"), rel: "noopener" }
|
||||
title: t("homescreen.links.security_alerts"),
|
||||
rel: "noopener"
|
||||
}
|
||||
) %>
|
||||
</li>
|
||||
<li>
|
||||
<%= link_to(
|
||||
t("homescreen.links.newsletter"), "#{OpenProject::Static::Links.links[:newsletter][:href]}/?utm_source=unknown&utm_medium=op-instance&utm_campaign=newsletter-home-screen",
|
||||
{ aria: { label: t("homescreen.links.newsletter") },
|
||||
t("homescreen.links.newsletter"),
|
||||
OpenProject::Static::Links.url_for(
|
||||
:newsletter,
|
||||
url_params: {
|
||||
utm_source: "unknown",
|
||||
utm_medium: "op-instance",
|
||||
utm_campaign: "newsletter-home-screen"
|
||||
}
|
||||
),
|
||||
{
|
||||
aria: { label: t("homescreen.links.newsletter") },
|
||||
target: "_blank",
|
||||
title: t("homescreen.links.newsletter"), rel: "noopener" }
|
||||
title: t("homescreen.links.newsletter"),
|
||||
rel: "noopener"
|
||||
}
|
||||
) %>
|
||||
</li>
|
||||
<li>
|
||||
|
||||
@@ -51,11 +51,18 @@ See COPYRIGHT and LICENSE files for more details.
|
||||
<section class="homescreen--links">
|
||||
|
||||
<% @homescreen[:links].each do |link| %>
|
||||
<% title = I18n.t(link[:label], scope: "homescreen.links") %>
|
||||
<a class="homescreen--links--item" href="<%= link[:url] %>" target="_blank" aria-label="<%= title %>">
|
||||
<%= op_icon(link[:icon]) %>
|
||||
<%= title %>
|
||||
</a>
|
||||
<% url = link[:url] || OpenProject::Static::Links.url_for(link[:url_key]) %>
|
||||
|
||||
<% if url %>
|
||||
<% title = I18n.t(link[:label], scope: "homescreen.links") %>
|
||||
<%= link_to url,
|
||||
class: "homescreen--links--item",
|
||||
target: "_blank",
|
||||
aria_label: title do %>
|
||||
<%= op_icon(link[:icon]) %>
|
||||
<%= title %>
|
||||
<% end %>
|
||||
<% end %>
|
||||
<% end %>
|
||||
</section>
|
||||
<% end %>
|
||||
|
||||
@@ -73,7 +73,7 @@ See COPYRIGHT and LICENSE files for more details.
|
||||
<legend class="form--fieldset-legend"><%= t("ldap_auth_sources.connection_encryption") %></legend>
|
||||
<p>
|
||||
<%= t "ldap_auth_sources.tls_mode.section_more_info_link_html",
|
||||
link: OpenProject::Static::Links[:ldap_encryption_documentation][:href] %>
|
||||
link: OpenProject::Static::Links.url_for(:ldap_encryption_documentation) %>
|
||||
</p>
|
||||
<div class="form--field">
|
||||
<%= f.radio_button :tls_mode,
|
||||
|
||||
@@ -40,10 +40,10 @@ See COPYRIGHT and LICENSE files for more details.
|
||||
<p>
|
||||
<%= t(
|
||||
:mail_body_register_links_html,
|
||||
webinar_link: link_to("Webinar Link", OpenProject::Static::Links.links[:webinar_videos][:href]),
|
||||
webinar_link: link_to("Webinar Link", OpenProject::Static::Links.url_for(:webinar_videos)),
|
||||
youtube_link: link_to("Youtube Link", OpenProject::Configuration.youtube_channel),
|
||||
get_started_link: link_to("Get Started Videos Link", OpenProject::Static::Links.links[:get_started_videos][:href]),
|
||||
documentation_link: link_to("Documentation Link", OpenProject::Static::Links.links[:openproject_docs][:href])
|
||||
get_started_link: link_to("Get Started Videos Link", OpenProject::Static::Links.url_for(:get_started_videos)),
|
||||
documentation_link: link_to("Documentation Link", OpenProject::Static::Links.url_for(:openproject_docs))
|
||||
) %>
|
||||
</p>
|
||||
|
||||
|
||||
@@ -33,10 +33,10 @@ See COPYRIGHT and LICENSE files for more details.
|
||||
|
||||
<%= strip_tags t(
|
||||
:mail_body_register_links_html,
|
||||
webinar_link: OpenProject::Static::Links.links[:webinar_videos][:href],
|
||||
webinar_link: OpenProject::Static::Links.url_for(:webinar_videos),
|
||||
youtube_link: OpenProject::Configuration.youtube_channel,
|
||||
get_started_link: OpenProject::Static::Links.links[:get_started_videos][:href],
|
||||
documentation_link: OpenProject::Static::Links.links[:openproject_docs][:href]
|
||||
get_started_link: OpenProject::Static::Links.url_for(:get_started_videos),
|
||||
documentation_link: OpenProject::Static::Links.url_for(:openproject_docs)
|
||||
)
|
||||
%>
|
||||
|
||||
|
||||
@@ -46,7 +46,7 @@ See COPYRIGHT and LICENSE files for more details.
|
||||
<span class="form--field-instructions">
|
||||
<%= I18n.t(
|
||||
"activerecord.attributes.user_preference.disable_keyboard_shortcuts_caption_html",
|
||||
href: OpenProject::Static::Links.links[:shortcuts][:href]
|
||||
href: OpenProject::Static::Links.url_for(:shortcuts)
|
||||
).html_safe %>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
@@ -72,36 +72,31 @@ OpenProject::Static::Homescreen.manage :blocks do |blocks|
|
||||
end
|
||||
|
||||
OpenProject::Static::Homescreen.manage :links do |links|
|
||||
link_hash = OpenProject::Static::Links.links
|
||||
|
||||
links.push(
|
||||
{
|
||||
label: :user_guides,
|
||||
icon: "icon-context icon-rename",
|
||||
url: link_hash[:user_guides][:href]
|
||||
url_key: :user_guides
|
||||
},
|
||||
{
|
||||
label: :glossary,
|
||||
icon: "icon-context icon-glossar",
|
||||
url: link_hash[:glossary][:href]
|
||||
url_key: :glossary
|
||||
},
|
||||
{
|
||||
label: :shortcuts,
|
||||
icon: "icon-context icon-shortcuts",
|
||||
url: link_hash[:shortcuts][:href]
|
||||
url_key: :shortcuts
|
||||
},
|
||||
{
|
||||
label: :forums,
|
||||
icon: "icon-context icon-forums",
|
||||
url: link_hash[:forums][:href]
|
||||
url_key: :forums
|
||||
},
|
||||
{
|
||||
label: :impressum,
|
||||
icon: "icon-context icon-info1",
|
||||
url_key: :impressum
|
||||
}
|
||||
)
|
||||
|
||||
if impressum_link = link_hash[:impressum]
|
||||
links.push({
|
||||
label: :impressum,
|
||||
url: impressum_link[:href],
|
||||
icon: "icon-context icon-info1"
|
||||
})
|
||||
end
|
||||
end
|
||||
|
||||
@@ -81,6 +81,8 @@ get_started_videos:
|
||||
glossary:
|
||||
href: https://www.openproject.org/docs/glossary/
|
||||
label: homescreen.links.glossary
|
||||
github:
|
||||
href: https://github.com/opf/openproject
|
||||
ical_docs:
|
||||
href: https://www.openproject.org/docs/user-guide/calendar/#subscribe-to-a-calendar
|
||||
installation_guides:
|
||||
|
||||
@@ -94,9 +94,9 @@ class OpenProject::JournalFormatter::Cause < JournalFormatter::Base
|
||||
case feature
|
||||
when "progress_calculation_adjusted_from_disabled_mode",
|
||||
"progress_calculation_adjusted"
|
||||
{ href: OpenProject::Static::Links.links[:blog_article_progress_changes][:href] }
|
||||
{ href: OpenProject::Static::Links.url_for(:blog_article_progress_changes) }
|
||||
when "totals_removed_from_childless_work_packages"
|
||||
{ href: OpenProject::Static::Links.links[:release_notes_14_0_1][:href] }
|
||||
{ href: OpenProject::Static::Links.url_for(:release_notes_14_0_1) }
|
||||
else
|
||||
{}
|
||||
end
|
||||
|
||||
@@ -37,22 +37,28 @@ module OpenProject
|
||||
end
|
||||
|
||||
def help_link
|
||||
OpenProject::Configuration.force_help_link.presence || static_links[:user_guides]
|
||||
OpenProject::Configuration.force_help_link.presence || static_links[:user_guides][:href]
|
||||
end
|
||||
|
||||
delegate :[], to: :links
|
||||
|
||||
def links
|
||||
@links ||= static_links.merge(dynamic_links)
|
||||
def cache_key
|
||||
@cache_key ||= OpenProject::Cache::CacheKey.expand(links)
|
||||
end
|
||||
|
||||
def url_for(*items, localize_url: true)
|
||||
href = links.dig(*items, :href)
|
||||
def label_for(*path)
|
||||
key = links.dig(*path, :label)
|
||||
return if key.nil?
|
||||
|
||||
if localize_url && docs_url?(href)
|
||||
with_locale_param(href)
|
||||
I18n.t(key)
|
||||
end
|
||||
|
||||
def url_for(*path, localize_url: true, url_params: {})
|
||||
href = links.dig(*path, :href)
|
||||
return if href.nil?
|
||||
|
||||
if localize_url && website_link?(href)
|
||||
url_with_query(href, **url_params, go_to_locale: I18n.locale)
|
||||
else
|
||||
href
|
||||
url_with_query(href, **url_params)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -60,22 +66,28 @@ module OpenProject
|
||||
@links.key? name
|
||||
end
|
||||
|
||||
def docs_url?(url)
|
||||
url&.start_with?(docs_url)
|
||||
def website_link?(url)
|
||||
url&.start_with?(website_url)
|
||||
end
|
||||
|
||||
def docs_url
|
||||
links[:openproject_docs][:href]
|
||||
end
|
||||
|
||||
def with_locale_param(href)
|
||||
url = Addressable::URI.parse(href)
|
||||
url.query_values = (url.query_values || {}).merge(go_to_locale: I18n.locale)
|
||||
url.to_s
|
||||
def website_url
|
||||
links[:website][:href]
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def links
|
||||
@links ||= static_links.merge(dynamic_links)
|
||||
end
|
||||
|
||||
def url_with_query(href, **params)
|
||||
return href if params.empty?
|
||||
|
||||
url = Addressable::URI.parse(href)
|
||||
url.query_values = (url.query_values || {}).merge(params)
|
||||
url.to_s
|
||||
end
|
||||
|
||||
def dynamic_links
|
||||
dynamic = {
|
||||
help: {
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
module Redmine::MenuManager::TopMenu::HelpMenu
|
||||
def render_help_top_menu_node(item = help_menu_item)
|
||||
cache_key = ["help_top_menu_node",
|
||||
OpenProject::Static::Links.links,
|
||||
OpenProject::Static::Links.cache_key,
|
||||
I18n.locale,
|
||||
OpenProject::Static::Links.help_link,
|
||||
EnterpriseToken.active?]
|
||||
@@ -100,7 +100,11 @@ module Redmine::MenuManager::TopMenu::HelpMenu
|
||||
unless EnterpriseToken.hide_banners? && EnterpriseToken.active?
|
||||
menu_group.with_item(
|
||||
**link_options_for(:upsell,
|
||||
href_suffix: "/?utm_source=unknown&utm_medium=op-instance&utm_campaign=ee-upsell-help-menu")
|
||||
url_params: {
|
||||
utm_source: "unknown",
|
||||
utm_medium: "op-instance",
|
||||
utm_campaign: "ee-upsell-help-menu"
|
||||
})
|
||||
)
|
||||
end
|
||||
menu_group.with_item(**link_options_for(:user_guides))
|
||||
@@ -131,15 +135,27 @@ module Redmine::MenuManager::TopMenu::HelpMenu
|
||||
menu_group.with_item(**link_options_for(:digital_accessibility))
|
||||
menu_group.with_item(**link_options_for(
|
||||
:website,
|
||||
href_suffix: "/?utm_source=unknown&utm_medium=op-instance&utm_campaign=website-help-menu"
|
||||
url_params: {
|
||||
utm_source: "unknown",
|
||||
utm_medium: "op-instance",
|
||||
utm_campaign: "website-help-menu"
|
||||
}
|
||||
))
|
||||
menu_group.with_item(**link_options_for(
|
||||
:security_alerts,
|
||||
href_suffix: "/?utm_source=unknown&utm_medium=op-instance&utm_campaign=security-help-menu"
|
||||
url_params: {
|
||||
utm_source: "unknown",
|
||||
utm_medium: "op-instance",
|
||||
utm_campaign: "security-help-menu"
|
||||
}
|
||||
))
|
||||
menu_group.with_item(**link_options_for(
|
||||
:newsletter,
|
||||
href_suffix: "/?utm_source=unknown&utm_medium=op-instance&utm_campaign=newsletter-help-menu"
|
||||
url_params: {
|
||||
utm_source: "unknown",
|
||||
utm_medium: "op-instance",
|
||||
utm_campaign: "newsletter-help-menu"
|
||||
}
|
||||
))
|
||||
menu_group.with_item(**link_options_for(:blog))
|
||||
menu_group.with_item(**link_options_for(:release_notes))
|
||||
@@ -151,11 +167,11 @@ module Redmine::MenuManager::TopMenu::HelpMenu
|
||||
end
|
||||
|
||||
def link_options_for(key, options = {})
|
||||
link = OpenProject::Static::Links.links[key]
|
||||
label = I18n.t(link[:label])
|
||||
href = OpenProject::Static::Links.url_for(key, url_params: options[:url_params] || {})
|
||||
label = OpenProject::Static::Links.label_for(key)
|
||||
|
||||
{
|
||||
href: "#{link[:href]}#{options[:href_suffix]}",
|
||||
href: href,
|
||||
label: label,
|
||||
content_arguments: {
|
||||
target: "_blank",
|
||||
|
||||
@@ -87,7 +87,7 @@ module Storages::Admin::Forms
|
||||
I18n.t(
|
||||
"storages.instructions.#{provider_type}.provider_configuration",
|
||||
application_link_text: application_link_text_for(
|
||||
::OpenProject::Static::Links[:storage_docs][:"#{provider_type}_oauth_application"][:href],
|
||||
::OpenProject::Static::Links.url_for(:storage_docs, :"#{provider_type}_oauth_application"),
|
||||
I18n.t("storages.instructions.#{provider_type}.application_link_text")
|
||||
)
|
||||
).html_safe
|
||||
|
||||
@@ -57,12 +57,12 @@ module Storages::Admin::Forms
|
||||
end
|
||||
|
||||
def one_drive_integration_link(target: "_blank")
|
||||
href = ::OpenProject::Static::Links[:storage_docs][:one_drive_oauth_application][:href]
|
||||
href = ::OpenProject::Static::Links.url_for(:storage_docs, :one_drive_oauth_application)
|
||||
render(Primer::Beta::Link.new(href:, underline: true, target:)) { I18n.t("storages.instructions.one_drive.application_link_text") }
|
||||
end
|
||||
|
||||
def sharepoint_integration_link(target: "_blank")
|
||||
href = ::OpenProject::Static::Links[:storage_docs][:sharepoint_oauth_application][:href]
|
||||
href = ::OpenProject::Static::Links.url_for(:storage_docs, :sharepoint_oauth_application)
|
||||
render(Primer::Beta::Link.new(href:, underline: true, target:)) { I18n.t("storages.instructions.sharepoint.application_link_text") }
|
||||
end
|
||||
|
||||
|
||||
@@ -57,7 +57,7 @@ class Storages::OpenProjectStorageModalComponent < ViewComponent::Base
|
||||
end
|
||||
|
||||
def subtitle_timeout_text
|
||||
href = OpenProject::Static::Links[:storage_docs][:health_status][:href]
|
||||
href = OpenProject::Static::Links.url_for(:storage_docs, :health_status)
|
||||
I18n.t(
|
||||
"storages.open_project_storage_modal.timeout.subtitle",
|
||||
storages_health_link: render(Primer::Beta::Link.new(href:, target: "_blank", underline: true)) do
|
||||
|
||||
@@ -44,7 +44,7 @@ module Storages::Admin
|
||||
private
|
||||
|
||||
def caption
|
||||
href = ::OpenProject::Static::Links[:storage_docs][:one_drive_drive_id_guide][:href]
|
||||
href = ::OpenProject::Static::Links.url_for(:storage_docs, :one_drive_drive_id_guide)
|
||||
I18n.t("storages.instructions.one_drive.drive_id",
|
||||
drive_id_link_text: render(Primer::Beta::Link.new(href:, underline: true, target: "_blank")) do
|
||||
I18n.t("storages.instructions.one_drive.documentation_link_text")
|
||||
|
||||
@@ -45,7 +45,7 @@ module Storages::Admin
|
||||
private
|
||||
|
||||
def caption
|
||||
href = ::OpenProject::Static::Links[:storage_docs][:one_drive_oauth_application][:href]
|
||||
href = ::OpenProject::Static::Links.url_for(:storage_docs, :one_drive_oauth_application)
|
||||
I18n.t("storages.instructions.one_drive.tenant_id",
|
||||
application_link_text: render(Primer::Beta::Link.new(href:, underline: true, target: "_blank")) do
|
||||
I18n.t("storages.instructions.one_drive.application_link_text")
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
<% header.with_description(test_selector: 'storage-new-page-header--description') do %>
|
||||
<%=
|
||||
t("storages.instructions.new_storage",
|
||||
provider_link: ::OpenProject::Static::Links[:storage_docs][:"#{@storage}_setup"][:href].html_safe,
|
||||
provider_link: ::OpenProject::Static::Links.url_for(:storage_docs, :"#{@storage}_setup"),
|
||||
provider_name: I18n.t("storages.provider_types.#{@storage}.name")
|
||||
).html_safe
|
||||
%>
|
||||
|
||||
+1
-1
@@ -87,7 +87,7 @@ See COPYRIGHT and LICENSE files for more details.
|
||||
|
||||
<td style="color: #878787; font-size: 12px; font-weight: 400; line-height: 16px;">
|
||||
<%= I18n.t("mail.storages.health.unhealthy.troubleshooting.text") %>
|
||||
<a href="<%= ::OpenProject::Static::Links[:storage_docs][:troubleshooting][:href] %>"><%= I18n.t("mail.storages.health.unhealthy.troubleshooting.link_text") %></a>.
|
||||
<a href="<%= ::OpenProject::Static::Links.url_for(:storage_docs, :troubleshooting) %>"><%= I18n.t("mail.storages.health.unhealthy.troubleshooting.link_text") %></a>.
|
||||
</td>
|
||||
|
||||
<%= placeholder_cell("12px", vertical: true) %>
|
||||
|
||||
+2
-2
@@ -22,9 +22,9 @@
|
||||
<p>
|
||||
<%= t("two_factor_authentication.settings.text_configuration") %>
|
||||
<br>
|
||||
<% configuration_link = OpenProject::Static::Links.links.fetch :configuration_guide %>
|
||||
<% configuration_link = OpenProject::Static::Links.url_for :configuration_guide %>
|
||||
<%= link_to t("two_factor_authentication.settings.text_configuration_guide"),
|
||||
configuration_link[:href],
|
||||
configuration_link,
|
||||
target: "_blank" %>
|
||||
</p>
|
||||
<%= render(AttributeGroups::AttributeGroupComponent.new) do |component|
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<p>
|
||||
<%= t "webhooks.outgoing.form.introduction" %>
|
||||
<br>
|
||||
<%= link_to t("webhooks.outgoing.form.apiv3_doc_url"), OpenProject::Static::Links.links[:api_docs][:href] %>
|
||||
<%= link_to t("webhooks.outgoing.form.apiv3_doc_url"), OpenProject::Static::Links.url_for(:api_docs) %>
|
||||
</p>
|
||||
|
||||
<div class="form--field -required">
|
||||
|
||||
@@ -257,7 +257,7 @@ RSpec.describe EnterpriseEdition::BannerComponent, type: :component do
|
||||
expect(component).to have_text(expected_title)
|
||||
expect(component).to have_text(expected_description)
|
||||
|
||||
expect(component).to have_link("More information", href: "https://www.openproject.org/enterprise-edition")
|
||||
expect(component).to have_link("More information", href: "https://www.openproject.org/enterprise-edition?go_to_locale=mo")
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -74,7 +74,7 @@ RSpec.shared_examples_for "progress modal help links" do
|
||||
|
||||
expect(page)
|
||||
.to have_link("Learn more",
|
||||
href: OpenProject::Static::Links.links[:progress_tracking_docs][:href])
|
||||
href: OpenProject::Static::Links.url_for(:progress_tracking_docs))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -450,7 +450,7 @@ RSpec.describe OpenProject::JournalFormatter::Cause do
|
||||
end
|
||||
|
||||
it do
|
||||
href = OpenProject::Static::Links.links[:blog_article_progress_changes][:href]
|
||||
href = OpenProject::Static::Links.url_for(:blog_article_progress_changes)
|
||||
expect(cause).to render_html_variant(
|
||||
"<strong>OpenProject system update:</strong> Progress calculation automatically " \
|
||||
"<a href=\"#{href}\" target=\"_blank\">set to work-based mode and adjusted with version update</a>."
|
||||
@@ -474,7 +474,7 @@ RSpec.describe OpenProject::JournalFormatter::Cause do
|
||||
end
|
||||
|
||||
it do
|
||||
href = OpenProject::Static::Links.links[:blog_article_progress_changes][:href]
|
||||
href = OpenProject::Static::Links.url_for(:blog_article_progress_changes)
|
||||
expect(cause).to render_html_variant(
|
||||
"<strong>OpenProject system update:</strong> Progress calculation automatically " \
|
||||
"<a href=\"#{href}\" target=\"_blank\">adjusted with version update</a>."
|
||||
@@ -509,7 +509,7 @@ RSpec.describe OpenProject::JournalFormatter::Cause do
|
||||
end
|
||||
|
||||
it do
|
||||
href = OpenProject::Static::Links.links[:release_notes_14_0_1][:href]
|
||||
href = OpenProject::Static::Links.url_for(:release_notes_14_0_1)
|
||||
expect(cause).to render_html_variant(
|
||||
"<strong>OpenProject system update:</strong> Work and progress totals " \
|
||||
"automatically removed for non-parent work packages with " \
|
||||
|
||||
@@ -61,18 +61,123 @@ RSpec.describe OpenProject::Static::Links do
|
||||
end
|
||||
end
|
||||
|
||||
context "with non-docs URLs" do
|
||||
context "with website URL" do
|
||||
let(:args) { %i[website] }
|
||||
|
||||
it "does not add locale parameter to non-docs URLs" do
|
||||
expect(subject).to eq("https://www.openproject.org")
|
||||
it "adds locale parameter to website URL" do
|
||||
expect(subject).to eq("https://www.openproject.org?go_to_locale=en")
|
||||
end
|
||||
end
|
||||
|
||||
context "with other URLs" do
|
||||
let(:args) { %i[github] }
|
||||
|
||||
it "does not add a parameter" do
|
||||
expect(subject).to eq("https://github.com/opf/openproject")
|
||||
expect(subject).not_to include("go_to_locale=")
|
||||
end
|
||||
end
|
||||
|
||||
context "with additional URL parameters" do
|
||||
let(:args) { %i[website] }
|
||||
|
||||
it "adds custom URL parameters" do
|
||||
result = described_class.url_for(*args, url_params: { utm_source: "test", utm_medium: "spec" })
|
||||
expect(result).to include("utm_source=test")
|
||||
expect(result).to include("utm_medium=spec")
|
||||
end
|
||||
end
|
||||
|
||||
context "with non-existent path" do
|
||||
let(:args) { %i[non_existent_key] }
|
||||
|
||||
it "returns nil for non-existent paths" do
|
||||
expect(subject).to be_nil
|
||||
end
|
||||
end
|
||||
|
||||
context "with localize_url disabled" do
|
||||
let(:args) { %i[enterprise_features board_view] }
|
||||
|
||||
it "does not add locale parameter when localize_url is false" do
|
||||
result = described_class.url_for(*args, localize_url: false)
|
||||
expect(result).not_to include("go_to_locale=")
|
||||
expect(result).to eq("https://www.openproject.org/docs/user-guide/agile-boards/#action-boards-enterprise-add-on")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe ".docs_url?" do
|
||||
subject { described_class.docs_url?(url) }
|
||||
describe ".label_for" do
|
||||
subject { described_class.label_for(*args) }
|
||||
|
||||
let(:args) { %i[website] }
|
||||
|
||||
it "returns the translated label for the given path" do
|
||||
expect(subject).to eq(I18n.t("label_openproject_website"))
|
||||
end
|
||||
|
||||
context "with single key" do
|
||||
let(:args) { %i[shortcuts] }
|
||||
|
||||
it "returns the translated label for a single key" do
|
||||
expect(subject).to eq(I18n.t("homescreen.links.shortcuts"))
|
||||
end
|
||||
end
|
||||
|
||||
context "with non-existent path" do
|
||||
let(:args) { %i[non_existent_key] }
|
||||
|
||||
it "returns nil for non-existent paths" do
|
||||
expect(subject).to be_nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe ".cache_key" do
|
||||
subject { described_class.cache_key }
|
||||
|
||||
it "returns a cache key based on the links" do
|
||||
expect(subject).to be_a(String)
|
||||
expect(subject).not_to be_empty
|
||||
end
|
||||
|
||||
it "returns the same key for multiple calls" do
|
||||
first_call = described_class.cache_key
|
||||
second_call = described_class.cache_key
|
||||
expect(first_call).to eq(second_call)
|
||||
end
|
||||
end
|
||||
|
||||
describe ".has?" do
|
||||
subject { described_class.has?(key) }
|
||||
|
||||
context "with existing key" do
|
||||
let(:key) { :website }
|
||||
|
||||
it "returns true for existing keys" do
|
||||
expect(subject).to be true
|
||||
end
|
||||
end
|
||||
|
||||
context "with non-existing key" do
|
||||
let(:key) { :non_existent_key }
|
||||
|
||||
it "returns false for non-existing keys" do
|
||||
expect(subject).to be false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe ".website_url" do
|
||||
subject { described_class.website_url }
|
||||
|
||||
it "returns the website URL" do
|
||||
expect(subject).to eq("https://www.openproject.org")
|
||||
end
|
||||
end
|
||||
|
||||
describe ".website_link?" do
|
||||
subject { described_class.website_link?(url) }
|
||||
|
||||
context "with docs URLs" do
|
||||
let(:url) { "https://www.openproject.org/docs/user-guide/agile-boards/" }
|
||||
@@ -83,56 +188,67 @@ RSpec.describe OpenProject::Static::Links do
|
||||
end
|
||||
|
||||
context "with non-docs URLs" do
|
||||
let(:url) { "https://www.openproject.org/enterprise-edition" }
|
||||
let(:url) { "https://foo.example.com" }
|
||||
|
||||
it "returns false for URLs that do not start with the docs base URL" do
|
||||
expect(subject).to be false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe ".with_locale_param" do
|
||||
subject { described_class.with_locale_param(href) }
|
||||
context "with nil URL" do
|
||||
let(:url) { nil }
|
||||
|
||||
let(:href) { "https://www.openproject.org/docs/system-admin-guide/authentication/openid-providers/" }
|
||||
|
||||
before do
|
||||
allow(I18n).to receive(:locale).and_return(:en)
|
||||
end
|
||||
|
||||
it "adds go_to_locale parameter to the URL" do
|
||||
expect(subject).to include("go_to_locale=en")
|
||||
end
|
||||
|
||||
it "preserves the original URL structure" do
|
||||
expect(subject).to start_with(href)
|
||||
end
|
||||
|
||||
context "with URL that already has query parameters" do
|
||||
let(:href) { "https://www.openproject.org/docs/user-guide/agile-boards/?section=boards" }
|
||||
|
||||
it "adds go_to_locale parameter while preserving existing parameters" do
|
||||
expect(subject).to include("section=boards")
|
||||
expect(subject).to include("go_to_locale=en")
|
||||
it "returns false for nil URLs" do
|
||||
expect(subject).to be_falsy
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "with different locale" do
|
||||
describe ".help_link_overridden?" do
|
||||
subject { described_class.help_link_overridden? }
|
||||
|
||||
context "when help link is not overridden" do
|
||||
before do
|
||||
allow(I18n).to receive(:locale).and_return(:de)
|
||||
allow(OpenProject::Configuration).to receive(:force_help_link).and_return(nil)
|
||||
end
|
||||
|
||||
it "uses the current I18n locale" do
|
||||
expect(subject).to include("go_to_locale=de")
|
||||
it "returns false" do
|
||||
expect(subject).to be false
|
||||
end
|
||||
end
|
||||
|
||||
context "when help link is overridden" do
|
||||
before do
|
||||
allow(OpenProject::Configuration).to receive(:force_help_link).and_return("https://custom.help.com")
|
||||
end
|
||||
|
||||
it "returns true" do
|
||||
expect(subject).to be true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe ".docs_url" do
|
||||
subject { described_class.docs_url }
|
||||
describe ".help_link" do
|
||||
subject { described_class.help_link }
|
||||
|
||||
it "returns the base docs URL" do
|
||||
expect(subject).to eq("https://www.openproject.org/docs/")
|
||||
context "when help link is not overridden" do
|
||||
before do
|
||||
allow(OpenProject::Configuration).to receive(:force_help_link).and_return(nil)
|
||||
end
|
||||
|
||||
it "returns the default user guides link" do
|
||||
expect(subject).to eq("https://www.openproject.org/docs/user-guide/")
|
||||
end
|
||||
end
|
||||
|
||||
context "when help link is overridden" do
|
||||
before do
|
||||
allow(OpenProject::Configuration).to receive(:force_help_link).and_return("https://custom.help.com")
|
||||
end
|
||||
|
||||
it "returns the overridden help link" do
|
||||
expect(subject).to eq("https://custom.help.com")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
|
||||
# rubocop:disable RSpec/ContextWording
|
||||
RSpec.shared_context "support links" do
|
||||
let(:support_link_as_community) { "https://www.openproject.org/pricing/#support" }
|
||||
let(:support_link_as_enterprise) { "https://www.openproject.org/docs/enterprise-guide/support/" }
|
||||
let(:support_link_as_community) { "https://www.openproject.org/pricing/?go_to_locale=en#support" }
|
||||
let(:support_link_as_enterprise) { "https://www.openproject.org/docs/enterprise-guide/support/?go_to_locale=en" }
|
||||
end
|
||||
# rubocop:enable RSpec/ContextWording
|
||||
|
||||
Reference in New Issue
Block a user