summaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/plugins/gravatar/lib/gravatar.rb2
-rw-r--r--lib/redmine.rb5
-rw-r--r--lib/redmine/database.rb2
-rw-r--r--lib/redmine/diff.rb8
-rw-r--r--lib/redmine/field_format.rb4
-rw-r--r--lib/redmine/helpers/gantt.rb24
-rw-r--r--lib/redmine/i18n.rb19
-rw-r--r--lib/redmine/preparation.rb9
-rw-r--r--lib/redmine/quote_reply.rb4
-rw-r--r--lib/redmine/reaction.rb70
-rw-r--r--lib/redmine/wiki_formatting/common_mark/alerts_icons_filter.rb63
-rw-r--r--lib/redmine/wiki_formatting/common_mark/formatter.rb3
-rw-r--r--lib/tasks/icons.rake2
13 files changed, 167 insertions, 48 deletions
diff --git a/lib/plugins/gravatar/lib/gravatar.rb b/lib/plugins/gravatar/lib/gravatar.rb
index 4dc27db52..316a01b19 100644
--- a/lib/plugins/gravatar/lib/gravatar.rb
+++ b/lib/plugins/gravatar/lib/gravatar.rb
@@ -69,7 +69,7 @@ module GravatarHelper
options[:default] = CGI::escape(options[:default]) unless options[:default].nil?
gravatar_api_url(email_hash).tap do |url|
opts = []
- [:rating, :size, :default].each do |opt|
+ [:rating, :size, :default, :initials].each do |opt|
unless options[opt].nil?
value = h(options[opt])
opts << [opt, value].join('=')
diff --git a/lib/redmine.rb b/lib/redmine.rb
index 95b3b7f3f..78a1a6d8c 100644
--- a/lib/redmine.rb
+++ b/lib/redmine.rb
@@ -24,11 +24,6 @@ begin
rescue LoadError
# MiniMagick is not available
end
-begin
- require 'commonmarker' unless Object.const_defined?(:Commonmarker)
-rescue LoadError
- # CommonMarker is not available
-end
module Redmine
end
diff --git a/lib/redmine/database.rb b/lib/redmine/database.rb
index b3cbdc661..13c92b8a4 100644
--- a/lib/redmine/database.rb
+++ b/lib/redmine/database.rb
@@ -58,7 +58,7 @@ module Redmine
# Returns true if the database is MySQL
def mysql?
- /mysql/i.match?(ActiveRecord::Base.connection.adapter_name)
+ /mysql|trilogy/i.match?(ActiveRecord::Base.connection.adapter_name)
end
def mysql_version
diff --git a/lib/redmine/diff.rb b/lib/redmine/diff.rb
index 40c444a42..c925d463a 100644
--- a/lib/redmine/diff.rb
+++ b/lib/redmine/diff.rb
@@ -76,13 +76,9 @@ module Redmine
def line_to_html_raw(line, offsets)
if offsets
s = +''
- unless offsets.first == 0
- s << CGI.escapeHTML(line[0..offsets.first-1])
- end
+ s << CGI.escapeHTML(line[0..(offsets.first - 1)]) unless offsets.first == 0
s << '<span>' + CGI.escapeHTML(line[offsets.first..offsets.last]) + '</span>'
- unless offsets.last == -1
- s << CGI.escapeHTML(line[offsets.last+1..-1])
- end
+ s << CGI.escapeHTML(line[(offsets.last + 1)..-1]) unless offsets.last == -1
s
else
CGI.escapeHTML(line)
diff --git a/lib/redmine/field_format.rb b/lib/redmine/field_format.rb
index 3e87eeb38..39b21c874 100644
--- a/lib/redmine/field_format.rb
+++ b/lib/redmine/field_format.rb
@@ -1145,11 +1145,11 @@ module Redmine
end
def formatted_value(view, custom_field, value, customized=nil, html=false)
- text = "#{value}%"
if html
+ text = "#{value}%"
view.progress_bar(value.to_i, legend: (text if view.action_name == 'show'))
else
- text
+ value.to_s
end
end
end
diff --git a/lib/redmine/helpers/gantt.rb b/lib/redmine/helpers/gantt.rb
index 5854a15f2..523ae3188 100644
--- a/lib/redmine/helpers/gantt.rb
+++ b/lib/redmine/helpers/gantt.rb
@@ -198,12 +198,18 @@ module Redmine
# Returns the distinct versions of the issues that belong to +project+
def project_versions(project)
- project_issues(project).filter_map(&:fixed_version).uniq
+ @project_versions ||= {}
+ @project_versions[project&.id] ||= begin
+ ids = project_issues(project).filter_map(&:fixed_version_id).uniq
+ Version.where(id: ids).to_a
+ end
end
# Returns the issues that belong to +project+ and are assigned to +version+
def version_issues(project, version)
- project_issues(project).select {|issue| issue.fixed_version == version}
+ @version_issues ||= {}
+ @version_issues[[project&.id, version&.id]] ||=
+ project_issues(project).select {|issue| issue.fixed_version_id == version&.id}
end
def render(options={})
@@ -232,7 +238,7 @@ module Redmine
render_object_row(project, options)
increment_indent(options) do
# render issue that are not assigned to a version
- issues = project_issues(project).select {|i| i.fixed_version.nil?}
+ issues = project_issues(project).select {|i| i.fixed_version_id.nil?}
render_issues(issues, options)
# then render project versions and their issues
versions = project_versions(project)
@@ -748,7 +754,7 @@ module Redmine
html_class << (version.behind_schedule? ? 'version-behind-schedule' : '') << " "
html_class << (version.overdue? ? 'version-overdue' : '')
html_class << ' version-closed' unless version.open?
- if version.start_date && version.due_date && version.visible_fixed_issues.completed_percent
+ if version.due_date && version.start_date && version.visible_fixed_issues.completed_percent
progress_date = calc_progress_date(version.start_date,
version.due_date, version.visible_fixed_issues.completed_percent)
html_class << ' behind-start-date' if progress_date < self.date_from
@@ -778,10 +784,14 @@ module Redmine
tag_options[:id] = "issue-#{object.id}"
tag_options[:class] = "issue-subject hascontextmenu"
tag_options[:title] = object.subject
- children = object.leaf? ? [] : object.children & project_issues(object.project)
has_children =
- children.present? &&
- children.collect(&:fixed_version).uniq.intersect?([object.fixed_version])
+ if object.leaf?
+ false
+ else
+ children = object.children & project_issues(object.project)
+ fixed_version_id = object.fixed_version_id
+ children.any? {|child| child.fixed_version_id == fixed_version_id}
+ end
when Version
tag_options[:id] = "version-#{object.id}"
tag_options[:class] = "version-name"
diff --git a/lib/redmine/i18n.rb b/lib/redmine/i18n.rb
index a79b4fc68..0b31cb235 100644
--- a/lib/redmine/i18n.rb
+++ b/lib/redmine/i18n.rb
@@ -173,24 +173,5 @@ module Redmine
def current_language
::I18n.locale
end
-
- # Custom backend based on I18n::Backend::Simple with the following changes:
- # * available_locales are determined by looking at translation file names
- class Backend < ::I18n::Backend::Simple
- module Implementation
- # Get available locales from the translations filenames
- def available_locales
- @available_locales ||= begin
- redmine_locales = Dir[Rails.root / 'config' / 'locales' / '*.yml'].map { |f| File.basename(f, '.yml').to_sym }
- super & redmine_locales
- end
- end
- end
-
- # Adds custom pluralization rules
- include ::I18n::Backend::Pluralization
- # Adds fallback to default locale for untranslated strings
- include ::I18n::Backend::Fallbacks
- end
end
end
diff --git a/lib/redmine/preparation.rb b/lib/redmine/preparation.rb
index 822662e11..a7387f5dc 100644
--- a/lib/redmine/preparation.rb
+++ b/lib/redmine/preparation.rb
@@ -280,6 +280,11 @@ module Redmine
{:controller => 'auth_sources', :action => 'index'},
:icon => 'server-authentication',
:html => {:class => 'icon icon-server-authentication'}
+ menu.push :applications, {:controller => 'oauth2_applications', :action => 'index'},
+ :if => Proc.new { Setting.rest_api_enabled? },
+ :caption => :'doorkeeper.layouts.admin.nav.applications',
+ :icon => 'apps',
+ :html => {:class => 'icon icon-applications'}
menu.push :plugins, {:controller => 'admin', :action => 'plugins'},
:last => true,
:icon => 'plugins',
@@ -408,9 +413,7 @@ module Redmine
WikiFormatting.map do |format|
format.register :textile
- if Object.const_defined?(:Commonmarker)
- format.register :common_mark, label: 'CommonMark Markdown (GitHub Flavored)'
- end
+ format.register :common_mark, label: 'CommonMark Markdown (GitHub Flavored)'
end
ActionView::Template.register_template_handler :rsb, Views::ApiTemplateHandler
diff --git a/lib/redmine/quote_reply.rb b/lib/redmine/quote_reply.rb
index 05737c079..2bf41d405 100644
--- a/lib/redmine/quote_reply.rb
+++ b/lib/redmine/quote_reply.rb
@@ -27,11 +27,11 @@ module Redmine
def quote_reply(url, selector_for_content, icon_only: false)
quote_reply_function = "quoteReply('#{j url}', '#{j selector_for_content}', '#{j Setting.text_formatting}')"
- html_options = { class: 'icon icon-comment' }
+ html_options = { class: 'icon icon-quote' }
html_options[:title] = l(:button_quote) if icon_only
link_to_function(
- sprite_icon('comment', l(:button_quote), icon_only: icon_only),
+ sprite_icon('quote-filled', l(:button_quote), icon_only: icon_only, style: :filled),
quote_reply_function,
html_options
)
diff --git a/lib/redmine/reaction.rb b/lib/redmine/reaction.rb
new file mode 100644
index 000000000..09fb78ef8
--- /dev/null
+++ b/lib/redmine/reaction.rb
@@ -0,0 +1,70 @@
+# frozen_string_literal: true
+
+# Redmine - project management software
+# Copyright (C) 2006- Jean-Philippe Lang
+#
+# 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.
+
+module Redmine
+ module Reaction
+ # Types of objects that can have reactions
+ REACTABLE_TYPES = %w(Journal Issue Message News Comment)
+
+ # Returns true if the user can view the reaction of the object
+ def self.visible?(object, user = User.current)
+ Setting.reactions_enabled? && object.visible?(user)
+ end
+
+ # Returns true if the user can add/remove a reaction to/from the object
+ def self.editable?(object, user = User.current)
+ user.logged? && visible?(object, user) && object&.project&.active?
+ end
+
+ module Reactable
+ extend ActiveSupport::Concern
+
+ included do
+ has_many :reactions, as: :reactable, dependent: :delete_all
+
+ attr_writer :reaction_detail
+ end
+
+ class_methods do
+ # Preloads reaction details for a collection of objects
+ def preload_reaction_details(objects)
+ return unless Setting.reactions_enabled?
+
+ details = ::Reaction.build_detail_map_for(objects, User.current)
+
+ objects.each do |object|
+ object.reaction_detail = details.fetch(object.id) { ::Reaction::Detail.new }
+ end
+ end
+ end
+
+ def reaction_detail
+ # Loads and returns reaction details if they are not already loaded.
+ # This is intended for cases where explicit preloading is unnecessary,
+ # such as retrieving reactions for a single issue on its detail page.
+ load_reaction_detail unless defined?(@reaction_detail)
+ @reaction_detail
+ end
+
+ def load_reaction_detail
+ self.class.preload_reaction_details([self])
+ end
+ end
+ end
+end
diff --git a/lib/redmine/wiki_formatting/common_mark/alerts_icons_filter.rb b/lib/redmine/wiki_formatting/common_mark/alerts_icons_filter.rb
new file mode 100644
index 000000000..27429d778
--- /dev/null
+++ b/lib/redmine/wiki_formatting/common_mark/alerts_icons_filter.rb
@@ -0,0 +1,63 @@
+# frozen_string_literal: true
+
+# Redmine - project management software
+# Copyright (C) 2006- Jean-Philippe Lang
+#
+# 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.
+
+module Redmine
+ module WikiFormatting
+ module CommonMark
+ # Defines the mapping from alert type (from CSS class) to SVG icon name.
+ # These icon names must correspond to IDs in your SVG sprite sheet (e.g., icons.svg).
+ ALERT_TYPE_TO_ICON_NAME = {
+ 'note' => 'help',
+ 'tip' => 'bulb',
+ 'warning' => 'warning',
+ 'caution' => 'alert-circle',
+ 'important' => 'message-report',
+ }.freeze
+
+ class AlertsIconsFilter < HTML::Pipeline::Filter
+ def call
+ doc.search("p.markdown-alert-title").each do |node|
+ parent_node = node.parent
+ parent_class_attr = parent_node['class'] # e.g., "markdown-alert markdown-alert-note"
+ next unless parent_class_attr
+
+ # Extract the specific alert type (e.g., "note", "tip", "warning")
+ # from the parent div's classes.
+ match_data = parent_class_attr.match(/markdown-alert-(\w+)/)
+ next unless match_data && match_data[1] # Ensure a type is found
+
+ alert_type = match_data[1]
+
+ # Get the corresponding icon name from our map.
+ icon_name = ALERT_TYPE_TO_ICON_NAME[alert_type]
+ next unless icon_name # Skip if no specific icon is defined for this alert type
+
+ icon_html = ApplicationController.helpers.sprite_icon(icon_name, node.text)
+
+ if icon_html
+ # Replace the existing text node with the icon HTML and label (text).
+ node.children.first.replace(icon_html)
+ end
+ end
+ doc
+ end
+ end
+ end
+ end
+end
diff --git a/lib/redmine/wiki_formatting/common_mark/formatter.rb b/lib/redmine/wiki_formatting/common_mark/formatter.rb
index f2b9bca04..8b7a18394 100644
--- a/lib/redmine/wiki_formatting/common_mark/formatter.rb
+++ b/lib/redmine/wiki_formatting/common_mark/formatter.rb
@@ -58,7 +58,8 @@ module Redmine
SanitizationFilter,
SyntaxHighlightFilter,
FixupAutoLinksFilter,
- ExternalLinksFilter
+ ExternalLinksFilter,
+ AlertsIconsFilter
], PIPELINE_CONFIG
class Formatter
diff --git a/lib/tasks/icons.rake b/lib/tasks/icons.rake
index e50c450a1..269ef43e2 100644
--- a/lib/tasks/icons.rake
+++ b/lib/tasks/icons.rake
@@ -16,7 +16,7 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
unless Rails.env.production?
- ICON_RELEASE_VERSION = "v3.19.0"
+ ICON_RELEASE_VERSION = "v3.33.0"
ICON_DEFAULT_STYLE = "outline"
SOURCE = URI.parse("https://raw.githubusercontent.com/tabler/tabler-icons/#{ICON_RELEASE_VERSION}/icons")