diff options
Diffstat (limited to 'lib/redmine')
-rw-r--r-- | lib/redmine/database.rb | 2 | ||||
-rw-r--r-- | lib/redmine/diff.rb | 8 | ||||
-rw-r--r-- | lib/redmine/field_format.rb | 4 | ||||
-rw-r--r-- | lib/redmine/helpers/gantt.rb | 24 | ||||
-rw-r--r-- | lib/redmine/i18n.rb | 19 | ||||
-rw-r--r-- | lib/redmine/preparation.rb | 9 | ||||
-rw-r--r-- | lib/redmine/quote_reply.rb | 4 | ||||
-rw-r--r-- | lib/redmine/reaction.rb | 70 | ||||
-rw-r--r-- | lib/redmine/wiki_formatting/common_mark/alerts_icons_filter.rb | 63 | ||||
-rw-r--r-- | lib/redmine/wiki_formatting/common_mark/formatter.rb | 3 |
10 files changed, 165 insertions, 41 deletions
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 |