Use redmine_plugin_kit for plugin loading
This commit is contained in:
parent
ec0379492c
commit
cdf18cdbb4
@ -5,8 +5,9 @@ Changelog
|
|||||||
+++++
|
+++++
|
||||||
|
|
||||||
- Mermaid 8.13.4 support
|
- Mermaid 8.13.4 support
|
||||||
- D3 7.1.1 support
|
- D3 7.2.0 support
|
||||||
- Ruby 2.6 is required
|
- Ruby 2.6 is required
|
||||||
|
- Use redmine_plugin_kit gem as loader
|
||||||
|
|
||||||
3.0.3
|
3.0.3
|
||||||
+++++
|
+++++
|
||||||
|
1
Gemfile
1
Gemfile
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
# Specify your gem's dependencies in additionals.gemspec
|
# Specify your gem's dependencies in additionals.gemspec
|
||||||
gemspec
|
gemspec
|
||||||
|
gem 'redmine_plugin_kit', path: '~/dev/redmine_plugin_kit'
|
||||||
|
|
||||||
group :development do
|
group :development do
|
||||||
# this is only used for development.
|
# this is only used for development.
|
||||||
|
13
Rakefile
13
Rakefile
@ -1,13 +0,0 @@
|
|||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
require 'bundler/gem_tasks'
|
|
||||||
require 'rake/testtask'
|
|
||||||
|
|
||||||
Rake::TestTask.new do |t|
|
|
||||||
t.libs << 'test'
|
|
||||||
files = FileList['test/**/*test.rb']
|
|
||||||
t.test_files = files
|
|
||||||
t.verbose = true
|
|
||||||
end
|
|
||||||
|
|
||||||
task default: :test
|
|
@ -20,8 +20,8 @@ Gem::Specification.new do |spec|
|
|||||||
spec.require_paths = ['lib']
|
spec.require_paths = ['lib']
|
||||||
spec.required_ruby_version = '>= 2.6'
|
spec.required_ruby_version = '>= 2.6'
|
||||||
|
|
||||||
spec.add_runtime_dependency 'deface', '1.8.1'
|
|
||||||
spec.add_runtime_dependency 'gemoji', '~> 3.0.0'
|
spec.add_runtime_dependency 'gemoji', '~> 3.0.0'
|
||||||
|
spec.add_runtime_dependency 'redmine_plugin_kit'
|
||||||
spec.add_runtime_dependency 'render_async'
|
spec.add_runtime_dependency 'render_async'
|
||||||
spec.add_runtime_dependency 'rss'
|
spec.add_runtime_dependency 'rss'
|
||||||
spec.add_runtime_dependency 'slim-rails'
|
spec.add_runtime_dependency 'slim-rails'
|
||||||
|
@ -2,13 +2,12 @@
|
|||||||
|
|
||||||
module AdditionalsChartjsHelper
|
module AdditionalsChartjsHelper
|
||||||
def chartjs_colorschemes_info_url
|
def chartjs_colorschemes_info_url
|
||||||
link_to(l(:label_chartjs_colorscheme_info),
|
link_to_external l(:label_chartjs_colorscheme_info),
|
||||||
'https://nagix.github.io/chartjs-plugin-colorschemes/colorchart.html',
|
'https://nagix.github.io/chartjs-plugin-colorschemes/colorchart.html'
|
||||||
class: 'external')
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def select_options_for_chartjs_colorscheme(selected)
|
def select_options_for_chartjs_colorscheme(selected)
|
||||||
data = AdditionalsLoader.yaml_config_load 'colorschemes.yml'
|
data = RedminePluginKit::Loader.new(plugin_id: 'additionals').yaml_config_load 'colorschemes.yml'
|
||||||
grouped_options_for_select data, selected
|
grouped_options_for_select data, selected
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -31,7 +31,7 @@ module AdditionalsSettingsHelper
|
|||||||
checked = if custom_value && !value_is_bool
|
checked = if custom_value && !value_is_bool
|
||||||
active_value
|
active_value
|
||||||
else
|
else
|
||||||
Additionals.true? active_value
|
RedminePluginKit.true? active_value
|
||||||
end
|
end
|
||||||
|
|
||||||
s = [label_tag(tag_name, label_title)]
|
s = [label_tag(tag_name, label_title)]
|
||||||
|
@ -16,7 +16,7 @@ module DashboardsHelper
|
|||||||
dashboard.enable_sidebar?
|
dashboard.enable_sidebar?
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
Additionals.true? params['enable_sidebar']
|
RedminePluginKit.true? params['enable_sidebar']
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -211,7 +211,7 @@ module DashboardsHelper
|
|||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
content = render_dashboard_block_content block, block_definition, dashboard, overwritten_settings
|
content = render_dashboard_block_content block, block_definition, dashboard, **overwritten_settings
|
||||||
return if content.blank?
|
return if content.blank?
|
||||||
|
|
||||||
if dashboard.editable?
|
if dashboard.editable?
|
||||||
@ -260,7 +260,7 @@ module DashboardsHelper
|
|||||||
|
|
||||||
def render_async_options(settings, async)
|
def render_async_options(settings, async)
|
||||||
options = {}
|
options = {}
|
||||||
if Additionals.true? settings[:auto_refresh]
|
if RedminePluginKit.true? settings[:auto_refresh]
|
||||||
options[:interval] = (async[:cache_expires_in] || DashboardContent::RENDER_ASYNC_CACHE_EXPIRES_IN) * 1000
|
options[:interval] = (async[:cache_expires_in] || DashboardContent::RENDER_ASYNC_CACHE_EXPIRES_IN) * 1000
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -381,7 +381,7 @@ module DashboardsHelper
|
|||||||
max_entries = (settings[:max_entries] || DashboardContent::DEFAULT_MAX_ENTRIES).to_i
|
max_entries = (settings[:max_entries] || DashboardContent::DEFAULT_MAX_ENTRIES).to_i
|
||||||
user = User.current
|
user = User.current
|
||||||
options = {}
|
options = {}
|
||||||
options[:author] = user if Additionals.true? settings[:me_only]
|
options[:author] = user if RedminePluginKit.true? settings[:me_only]
|
||||||
options[:project] = dashboard.content_project if dashboard.content_project.present?
|
options[:project] = dashboard.content_project if dashboard.content_project.present?
|
||||||
|
|
||||||
Redmine::Activity::Fetcher.new(user, options)
|
Redmine::Activity::Fetcher.new(user, options)
|
||||||
@ -435,7 +435,7 @@ module DashboardsHelper
|
|||||||
private
|
private
|
||||||
|
|
||||||
# Renders a single block content
|
# Renders a single block content
|
||||||
def render_dashboard_block_content(block, block_definition, dashboard, overwritten_settings = {})
|
def render_dashboard_block_content(block, block_definition, dashboard, **overwritten_settings)
|
||||||
settings = dashboard.layout_settings block
|
settings = dashboard.layout_settings block
|
||||||
settings = settings.merge overwritten_settings if overwritten_settings.present?
|
settings = settings.merge overwritten_settings if overwritten_settings.present?
|
||||||
|
|
||||||
|
@ -8,7 +8,7 @@ class AdditionalsFontAwesome
|
|||||||
|
|
||||||
class << self
|
class << self
|
||||||
def load_icons(type)
|
def load_icons(type)
|
||||||
data = AdditionalsLoader.yaml_config_load 'fontawesome_icons.yml'
|
data = RedminePluginKit::Loader.new(plugin_id: 'additionals').yaml_config_load 'fontawesome_icons.yml'
|
||||||
icons = {}
|
icons = {}
|
||||||
data.each do |key, values|
|
data.each do |key, values|
|
||||||
icons[key] = { unicode: values['unicode'], label: values['label'] } if values['styles'].include? convert_type2style(type)
|
icons[key] = { unicode: values['unicode'], label: values['label'] } if values['styles'].include? convert_type2style(type)
|
||||||
|
@ -8,7 +8,9 @@ class AdditionalsInfo
|
|||||||
value: system_info },
|
value: system_info },
|
||||||
system_uptime: { label: l(:label_uptime),
|
system_uptime: { label: l(:label_uptime),
|
||||||
value: system_uptime,
|
value: system_uptime,
|
||||||
api_value: system_uptime(format: :datetime) } }
|
api_value: system_uptime(format: :datetime) },
|
||||||
|
redmine_plugin_kit: { label: 'Redmine Plugin Kit',
|
||||||
|
value: RedminePluginKit::VERSION } }
|
||||||
end
|
end
|
||||||
|
|
||||||
def system_info
|
def system_info
|
||||||
|
@ -1,263 +0,0 @@
|
|||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
class AdditionalsLoader
|
|
||||||
class ExistingControllerPatchForHelper < StandardError; end
|
|
||||||
|
|
||||||
attr_accessor :plugin_id, :debug
|
|
||||||
|
|
||||||
DEFAULT_PLUGIN_ID = 'additionals'
|
|
||||||
|
|
||||||
class << self
|
|
||||||
def default_settings(plugin_id = DEFAULT_PLUGIN_ID)
|
|
||||||
cached_settings_name = "@default_settings_#{plugin_id}"
|
|
||||||
cached_settings = instance_variable_get cached_settings_name
|
|
||||||
if cached_settings.nil?
|
|
||||||
data = yaml_config_load 'settings.yml', with_erb: true, plugin_id: plugin_id
|
|
||||||
instance_variable_set cached_settings_name, data.symbolize_keys
|
|
||||||
else
|
|
||||||
cached_settings
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def yaml_config_load(yaml_file, plugin_id: DEFAULT_PLUGIN_ID, with_erb: false)
|
|
||||||
file_to_load = File.read File.join(plugin_dir(plugin_id), 'config', yaml_file)
|
|
||||||
file_to_load = ERB.new(file_to_load).result if with_erb
|
|
||||||
|
|
||||||
YAML.safe_load(file_to_load) || {}
|
|
||||||
end
|
|
||||||
|
|
||||||
def plugin_dir(plugin_id = DEFAULT_PLUGIN_ID)
|
|
||||||
if Gem.loaded_specs[plugin_id].nil?
|
|
||||||
File.join Redmine::Plugin.directory, plugin_id
|
|
||||||
else
|
|
||||||
Gem.loaded_specs[plugin_id].full_gem_path
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def to_prepare(*args, &block)
|
|
||||||
if Rails.version > '6.0'
|
|
||||||
# INFO: https://www.redmine.org/issues/36245
|
|
||||||
Rails.logger.info 'after_plugins_loaded hook should be used instead'
|
|
||||||
else
|
|
||||||
# ActiveSupport::Reloader.to_prepare(*args, &block)
|
|
||||||
Rails.configuration.to_prepare(*args, &block)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def persisting
|
|
||||||
Additionals.debug 'Loading persisting...'
|
|
||||||
yield
|
|
||||||
end
|
|
||||||
|
|
||||||
def after_initialize(&block)
|
|
||||||
Additionals.debug 'After initialize...'
|
|
||||||
Rails.application.config.after_initialize(&block)
|
|
||||||
end
|
|
||||||
|
|
||||||
def load_hooks!(plugin_id = DEFAULT_PLUGIN_ID)
|
|
||||||
target = plugin_id.camelize.constantize
|
|
||||||
target::Hooks
|
|
||||||
end
|
|
||||||
|
|
||||||
def deface_setup!
|
|
||||||
Rails.application.paths['app/overrides'] ||= []
|
|
||||||
Dir.glob(Rails.root.join('plugins/*/app/overrides')).each do |dir|
|
|
||||||
Rails.application.paths['app/overrides'] << dir unless Rails.application.paths['app/overrides'].include? dir
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# required multiple times because of this bug: https://www.redmine.org/issues/33290
|
|
||||||
def redmine_database_ready?(with_table = nil)
|
|
||||||
ActiveRecord::Base.connection
|
|
||||||
rescue ActiveRecord::NoDatabaseError
|
|
||||||
false
|
|
||||||
else
|
|
||||||
with_table.nil? || ActiveRecord::Base.connection.table_exists?(with_table)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def initialize(plugin_id: DEFAULT_PLUGIN_ID, debug: false)
|
|
||||||
self.plugin_id = plugin_id
|
|
||||||
self.debug = debug
|
|
||||||
|
|
||||||
apply_reset
|
|
||||||
end
|
|
||||||
|
|
||||||
def apply_reset
|
|
||||||
@patches = []
|
|
||||||
@helpers = []
|
|
||||||
@global_helpers = []
|
|
||||||
end
|
|
||||||
|
|
||||||
def plugin_dir
|
|
||||||
@plugin_dir ||= self.class.plugin_dir plugin_id
|
|
||||||
end
|
|
||||||
|
|
||||||
# use_app: false => :plugin_dir/lib/:plugin_id directory
|
|
||||||
def require_files(spec, use_app: false, reverse: false, ignore_autoload: false)
|
|
||||||
dir = if use_app
|
|
||||||
File.join plugin_dir, 'app', spec
|
|
||||||
else
|
|
||||||
File.join plugin_dir, 'lib', plugin_id, spec
|
|
||||||
end
|
|
||||||
|
|
||||||
files = Dir[dir].sort
|
|
||||||
|
|
||||||
files.reverse! if reverse
|
|
||||||
files.each do |f|
|
|
||||||
Rails.autoloaders.main.ignore << f if Rails.version > '6.0' && ignore_autoload
|
|
||||||
require f
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def incompatible?(plugins = [])
|
|
||||||
plugins.each do |plugin|
|
|
||||||
raise "\n\033[31m#{plugin_id} plugin cannot be used with #{plugin} plugin.\033[0m" if Redmine::Plugin.installed? plugin
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def load_macros!
|
|
||||||
require_files File.join('wiki_macros', '**/*_macro.rb')
|
|
||||||
end
|
|
||||||
|
|
||||||
def load_custom_field_format!(reverse: false)
|
|
||||||
require_files File.join('custom_field_formats', '**/*_format.rb'),
|
|
||||||
reverse: reverse,
|
|
||||||
ignore_autoload: true
|
|
||||||
end
|
|
||||||
|
|
||||||
def add_patch(patch)
|
|
||||||
if patch.is_a? Array
|
|
||||||
@patches += patch
|
|
||||||
else
|
|
||||||
@patches << patch
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def add_helper(helper)
|
|
||||||
if helper.is_a? Array
|
|
||||||
@helpers += helper
|
|
||||||
else
|
|
||||||
@helpers << helper
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def add_global_helper(helper)
|
|
||||||
if helper.is_a? Array
|
|
||||||
@global_helpers += helper
|
|
||||||
else
|
|
||||||
@global_helpers << helper
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def apply!
|
|
||||||
validate_apply
|
|
||||||
|
|
||||||
apply_patches!
|
|
||||||
apply_helpers!
|
|
||||||
apply_global_helpers!
|
|
||||||
|
|
||||||
# reset patches and helpers
|
|
||||||
apply_reset
|
|
||||||
|
|
||||||
true
|
|
||||||
end
|
|
||||||
|
|
||||||
private
|
|
||||||
|
|
||||||
def validate_apply
|
|
||||||
return if @helpers.none? || @patches.none?
|
|
||||||
|
|
||||||
controller_patches = @patches.select do |p|
|
|
||||||
if p.is_a? String
|
|
||||||
true unless p == p.chomp('Controller')
|
|
||||||
else
|
|
||||||
c = p[:target].to_s
|
|
||||||
true unless c == c.chomp('Controller')
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
@helpers.each do |h|
|
|
||||||
helper_controller = if h.is_a? String
|
|
||||||
"#{h}Controller"
|
|
||||||
else
|
|
||||||
c = h[:controller]
|
|
||||||
if c.is_a? String
|
|
||||||
"#{c}Controller"
|
|
||||||
else
|
|
||||||
c.to_s
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
if controller_patches.include? helper_controller
|
|
||||||
raise ExistingControllerPatchForHelper, "Do not add helper to #{helper_controller} if patch exists (#{plugin_id})"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def apply_patches!
|
|
||||||
patches = @patches.map do |p|
|
|
||||||
if p.is_a? String
|
|
||||||
{ target: p.constantize, patch: p }
|
|
||||||
else
|
|
||||||
patch = p[:patch] || p[:target].to_s
|
|
||||||
{ target: p[:target], patch: patch }
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
patches.uniq!
|
|
||||||
Additionals.debug "patches for #{plugin_id}: #{patches.inspect}" if debug
|
|
||||||
|
|
||||||
patches.each do |patch|
|
|
||||||
patch_module = if patch[:patch].is_a? String
|
|
||||||
patch_dir = "#{plugin_dir}/lib/#{plugin_id}/patches"
|
|
||||||
require "#{patch_dir}/#{patch[:patch].underscore}_patch"
|
|
||||||
"#{plugin_id.camelize}::Patches::#{patch[:patch]}Patch".constantize
|
|
||||||
else
|
|
||||||
# if module specified (if not string), use it
|
|
||||||
patch[:patch]
|
|
||||||
end
|
|
||||||
|
|
||||||
target = patch[:target]
|
|
||||||
target.include patch_module unless target.included_modules.include? patch_module
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def apply_helpers!
|
|
||||||
helpers = @helpers.map do |h|
|
|
||||||
if h.is_a? String
|
|
||||||
{ controller: "#{h}Controller".constantize, helper: "#{plugin_id.camelize}#{h}Helper".constantize }
|
|
||||||
else
|
|
||||||
c = h[:controller].is_a?(String) ? "#{h[:controller]}Controller".constantize : h[:controller]
|
|
||||||
helper = if h[:helper]
|
|
||||||
h[:helper]
|
|
||||||
else
|
|
||||||
helper_name = if h[:controller].is_a? String
|
|
||||||
h[:controller]
|
|
||||||
else
|
|
||||||
h[:controller].to_s.chomp 'Controller'
|
|
||||||
end
|
|
||||||
"#{plugin_id.camelize}#{helper_name}Helper".constantize
|
|
||||||
end
|
|
||||||
{ controller: c, helper: helper }
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
helpers.uniq!
|
|
||||||
Additionals.debug "helpers for #{plugin_id}: #{helpers.inspect}" if debug
|
|
||||||
|
|
||||||
helpers.each do |h|
|
|
||||||
target = h[:controller]
|
|
||||||
target.send :helper, h[:helper]
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def apply_global_helpers!
|
|
||||||
global_helpers = @global_helpers.uniq
|
|
||||||
Additionals.debug "global helpers for #{plugin_id}: #{global_helpers.inspect}" if debug
|
|
||||||
|
|
||||||
global_helpers.each do |h|
|
|
||||||
ActionView::Base.include h
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
@ -307,7 +307,7 @@ class Dashboard < ActiveRecord::Base
|
|||||||
config = { dashboard_id: id,
|
config = { dashboard_id: id,
|
||||||
block: block }
|
block: block }
|
||||||
|
|
||||||
if Additionals.false? options[:skip_user_id]
|
if RedminePluginKit.false? options[:skip_user_id]
|
||||||
settings[:user_id] = User.current.id
|
settings[:user_id] = User.current.id
|
||||||
settings[:user_is_admin] = User.current.admin?
|
settings[:user_is_admin] = User.current.admin?
|
||||||
end
|
end
|
||||||
|
@ -12,6 +12,5 @@
|
|||||||
- if Additionals.setting? :open_external_urls
|
- if Additionals.setting? :open_external_urls
|
||||||
javascript:
|
javascript:
|
||||||
$(function() {
|
$(function() {
|
||||||
$('a.external').attr({ 'target': '_blank',
|
openExternalUrlsInTab();
|
||||||
'rel': 'noopener noreferrer'});
|
|
||||||
});
|
});
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
- dashboard_async_cache dashboard, block, async, settings do
|
- dashboard_async_cache dashboard, block, async, settings do
|
||||||
|
|
||||||
- events_by_day = activity_dashboard_data settings, dashboard
|
- events_by_day = activity_dashboard_data settings, dashboard
|
||||||
- title = Additionals.true?(settings[:me_only]) ? l(:label_my_activity) : l(:label_activity)
|
- title = RedminePluginKit.true?(settings[:me_only]) ? l(:label_my_activity) : l(:label_activity)
|
||||||
h3 = link_to title, activity_path(user_id: User.current,
|
h3 = link_to title, activity_path(user_id: User.current,
|
||||||
from: events_by_day.keys.first)
|
from: events_by_day.keys.first)
|
||||||
|
|
||||||
|
@ -15,3 +15,9 @@
|
|||||||
p.nodata = l :label_no_data
|
p.nodata = l :label_no_data
|
||||||
- else
|
- else
|
||||||
p.nodata = l :label_invalid_feed_data
|
p.nodata = l :label_invalid_feed_data
|
||||||
|
|
||||||
|
- if Additionals.setting? :open_external_urls
|
||||||
|
javascript:
|
||||||
|
$(function() {
|
||||||
|
openExternalUrlsInTab();
|
||||||
|
});
|
||||||
|
@ -10,7 +10,11 @@ h3 = block_definition[:label]
|
|||||||
span.label
|
span.label
|
||||||
= l :field_homepage
|
= l :field_homepage
|
||||||
' :
|
' :
|
||||||
= link_to_if uri_with_safe_scheme?(@project.homepage), @project.homepage, @project.homepage, class: 'external'
|
- if uri_with_safe_scheme? @project.homepage
|
||||||
|
= link_to_url @project.homepage
|
||||||
|
- else
|
||||||
|
= @project.homepage
|
||||||
|
|
||||||
- render_custom_field_values @project do |custom_field, formatted|
|
- render_custom_field_values @project do |custom_field, formatted|
|
||||||
li class="#{custom_field.css_classes}"
|
li class="#{custom_field.css_classes}"
|
||||||
span.label
|
span.label
|
||||||
|
@ -31,3 +31,9 @@
|
|||||||
p.nodata = l :label_no_data
|
p.nodata = l :label_no_data
|
||||||
- else
|
- else
|
||||||
p.nodata = l :label_no_data
|
p.nodata = l :label_no_data
|
||||||
|
|
||||||
|
- if Additionals.setting? :open_external_urls
|
||||||
|
javascript:
|
||||||
|
$(function() {
|
||||||
|
openExternalUrlsInTab();
|
||||||
|
});
|
||||||
|
@ -15,6 +15,13 @@ function setClipboardJS(element){
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* exported openExternalUrlsInTab */
|
||||||
|
function openExternalUrlsInTab() {
|
||||||
|
$('a.external').attr({
|
||||||
|
'target': '_blank',
|
||||||
|
'rel': 'noopener noreferrer'});
|
||||||
|
}
|
||||||
|
|
||||||
/* exported formatNameWithIcon */
|
/* exported formatNameWithIcon */
|
||||||
function formatNameWithIcon(opt) {
|
function formatNameWithIcon(opt) {
|
||||||
if (opt.loading) return opt.name;
|
if (opt.loading) return opt.name;
|
||||||
|
4
assets/javascripts/d3.min.js
vendored
4
assets/javascripts/d3.min.js
vendored
File diff suppressed because one or more lines are too long
@ -178,7 +178,7 @@ It provides :
|
|||||||
* `Chart.js Plugin colorschemes 0.4.0 <https://github.com/nagix/chartjs-plugin-colorschemes>`_
|
* `Chart.js Plugin colorschemes 0.4.0 <https://github.com/nagix/chartjs-plugin-colorschemes>`_
|
||||||
* `Chart.js Plugin datalabels 0.7.0 <https://github.com/chartjs/chartjs-plugin-datalabels>`_
|
* `Chart.js Plugin datalabels 0.7.0 <https://github.com/chartjs/chartjs-plugin-datalabels>`_
|
||||||
* `clipboardJS 2.0.8 <https://clipboardjs.com/>`_
|
* `clipboardJS 2.0.8 <https://clipboardjs.com/>`_
|
||||||
* `d3 7.1.1 <https://d3js.org/>`_
|
* `d3 7.2.0 <https://d3js.org/>`_
|
||||||
* `d3plus v2.0.0-alpha.30 <https://d3plus.org/>`_
|
* `d3plus v2.0.0-alpha.30 <https://d3plus.org/>`_
|
||||||
* `FontAwesome 5.15.4 <https://fontawesome.com/>`_
|
* `FontAwesome 5.15.4 <https://fontawesome.com/>`_
|
||||||
* `mermaid 8.13.4 <https://github.com/mermaid-js/mermaid>`_
|
* `mermaid 8.13.4 <https://github.com/mermaid-js/mermaid>`_
|
||||||
|
14
init.rb
14
init.rb
@ -1,6 +1,7 @@
|
|||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
require 'additionals/plugin_version'
|
require 'additionals/plugin_version'
|
||||||
|
loader = RedminePluginKit::Loader.new plugin_id: 'additionals'
|
||||||
|
|
||||||
Redmine::Plugin.register :additionals do
|
Redmine::Plugin.register :additionals do
|
||||||
name 'Additionals'
|
name 'Additionals'
|
||||||
@ -11,7 +12,7 @@ Redmine::Plugin.register :additionals do
|
|||||||
url 'https://github.com/alphanodes/additionals'
|
url 'https://github.com/alphanodes/additionals'
|
||||||
directory __dir__
|
directory __dir__
|
||||||
|
|
||||||
default_settings = AdditionalsLoader.default_settings
|
default_settings = loader.default_settings
|
||||||
5.times do |i|
|
5.times do |i|
|
||||||
default_settings["custom_menu#{i}_name"] = ''
|
default_settings["custom_menu#{i}_name"] = ''
|
||||||
default_settings["custom_menu#{i}_url"] = ''
|
default_settings["custom_menu#{i}_url"] = ''
|
||||||
@ -51,22 +52,19 @@ Redmine::Plugin.register :additionals do
|
|||||||
menu :admin_menu, :additionals, { controller: 'settings', action: 'plugin', id: 'additionals' }, caption: :label_additionals
|
menu :admin_menu, :additionals, { controller: 'settings', action: 'plugin', id: 'additionals' }, caption: :label_additionals
|
||||||
end
|
end
|
||||||
|
|
||||||
AdditionalsLoader.persisting do
|
RedminePluginKit::Loader.persisting do
|
||||||
Redmine::AccessControl.include Additionals::Patches::AccessControlPatch
|
Redmine::AccessControl.include Additionals::Patches::AccessControlPatch
|
||||||
Redmine::AccessControl.singleton_class.prepend Additionals::Patches::AccessControlClassPatch
|
Redmine::AccessControl.singleton_class.prepend Additionals::Patches::AccessControlClassPatch
|
||||||
|
|
||||||
# Deface support
|
|
||||||
AdditionalsLoader.deface_setup!
|
|
||||||
|
|
||||||
# Hooks
|
# Hooks
|
||||||
AdditionalsLoader.load_hooks!
|
loader.load_model_hooks!
|
||||||
end
|
end
|
||||||
|
|
||||||
AdditionalsLoader.after_initialize do
|
RedminePluginKit::Loader.after_initialize do
|
||||||
# @TODO: this should be moved to AdditionalsFontAwesome and use an instance of it
|
# @TODO: this should be moved to AdditionalsFontAwesome and use an instance of it
|
||||||
FONTAWESOME_ICONS = { fab: AdditionalsFontAwesome.load_icons(:fab), # rubocop: disable Lint/ConstantDefinitionInBlock
|
FONTAWESOME_ICONS = { fab: AdditionalsFontAwesome.load_icons(:fab), # rubocop: disable Lint/ConstantDefinitionInBlock
|
||||||
far: AdditionalsFontAwesome.load_icons(:far),
|
far: AdditionalsFontAwesome.load_icons(:far),
|
||||||
fas: AdditionalsFontAwesome.load_icons(:fas) }.freeze
|
fas: AdditionalsFontAwesome.load_icons(:fas) }.freeze
|
||||||
end
|
end
|
||||||
|
|
||||||
AdditionalsLoader.to_prepare { Additionals.setup } if Rails.version < '6.0'
|
RedminePluginKit::Loader.to_prepare { Additionals.setup!(loader) } if Rails.version < '6.0'
|
||||||
|
@ -7,93 +7,9 @@ module Additionals
|
|||||||
GOTO_LIST = " \xc2\xbb"
|
GOTO_LIST = " \xc2\xbb"
|
||||||
LIST_SEPARATOR = "#{GOTO_LIST} "
|
LIST_SEPARATOR = "#{GOTO_LIST} "
|
||||||
|
|
||||||
|
include RedminePluginKit::PluginBase
|
||||||
|
|
||||||
class << self
|
class << self
|
||||||
def setup
|
|
||||||
RenderAsync.configuration.jquery = true
|
|
||||||
|
|
||||||
loader = AdditionalsLoader.new
|
|
||||||
|
|
||||||
loader.incompatible? %w[redmine_editauthor
|
|
||||||
redmine_changeauthor
|
|
||||||
redmine_auto_watch]
|
|
||||||
|
|
||||||
loader.add_patch %w[ApplicationController
|
|
||||||
AutoCompletesController
|
|
||||||
Issue
|
|
||||||
IssuePriority
|
|
||||||
TimeEntry
|
|
||||||
Project
|
|
||||||
Wiki
|
|
||||||
ProjectsController
|
|
||||||
WelcomeController
|
|
||||||
ReportsController
|
|
||||||
Principal
|
|
||||||
Query
|
|
||||||
QueryFilter
|
|
||||||
Role
|
|
||||||
User
|
|
||||||
UserPreference]
|
|
||||||
|
|
||||||
loader.add_helper %w[Issues
|
|
||||||
Settings
|
|
||||||
Wiki
|
|
||||||
CustomFields]
|
|
||||||
|
|
||||||
loader.add_global_helper [Additionals::Helpers,
|
|
||||||
AdditionalsFontawesomeHelper,
|
|
||||||
AdditionalsMenuHelper,
|
|
||||||
AdditionalsSelect2Helper]
|
|
||||||
|
|
||||||
Redmine::WikiFormatting.format_names.each do |format|
|
|
||||||
case format
|
|
||||||
when 'markdown'
|
|
||||||
loader.add_patch [{ target: Redmine::WikiFormatting::Markdown::HTML, patch: 'FormatterMarkdown' },
|
|
||||||
{ target: Redmine::WikiFormatting::Markdown::Helper, patch: 'FormattingHelper' }]
|
|
||||||
when 'textile'
|
|
||||||
loader.add_patch [{ target: Redmine::WikiFormatting::Textile::Formatter, patch: 'FormatterTextile' },
|
|
||||||
{ target: Redmine::WikiFormatting::Textile::Helper, patch: 'FormattingHelper' }]
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# Apply patches and helper
|
|
||||||
loader.apply!
|
|
||||||
|
|
||||||
# Macros
|
|
||||||
loader.load_macros!
|
|
||||||
end
|
|
||||||
|
|
||||||
# support with default setting as fall back
|
|
||||||
def setting(value)
|
|
||||||
if settings.key? value
|
|
||||||
settings[value]
|
|
||||||
else
|
|
||||||
AdditionalsLoader.default_settings[value]
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def setting?(value)
|
|
||||||
true? setting(value)
|
|
||||||
end
|
|
||||||
|
|
||||||
def true?(value)
|
|
||||||
return false if value.is_a? FalseClass
|
|
||||||
return true if value.is_a?(TrueClass) || value.to_i == 1 || value.to_s.casecmp('true').zero?
|
|
||||||
|
|
||||||
false
|
|
||||||
end
|
|
||||||
|
|
||||||
# false if false or nil
|
|
||||||
def false?(value)
|
|
||||||
!true?(value)
|
|
||||||
end
|
|
||||||
|
|
||||||
def debug(message = 'running')
|
|
||||||
return if Rails.env.production?
|
|
||||||
|
|
||||||
msg = message.is_a?(String) ? message : message.inspect
|
|
||||||
Rails.logger.debug { "#{Time.current.strftime '%H:%M:%S'} DEBUG [#{caller_locations(1..1).first.label}]: #{msg}" }
|
|
||||||
end
|
|
||||||
|
|
||||||
def class_prefix(klass)
|
def class_prefix(klass)
|
||||||
klass_name = klass.is_a?(String) ? klass : klass.name
|
klass_name = klass.is_a?(String) ? klass : klass.name
|
||||||
klass_name.underscore.tr '/', '_'
|
klass_name.underscore.tr '/', '_'
|
||||||
@ -154,16 +70,70 @@ module Additionals
|
|||||||
ids.take limit
|
ids.take limit
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def debug(message = 'running')
|
||||||
|
RedminePluginKit::Debug.log message
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def settings
|
def setup
|
||||||
Setting[:plugin_additionals]
|
RenderAsync.configuration.jquery = true
|
||||||
|
|
||||||
|
loader.incompatible? %w[redmine_editauthor
|
||||||
|
redmine_changeauthor
|
||||||
|
redmine_auto_watch]
|
||||||
|
|
||||||
|
loader.add_patch %w[ApplicationController
|
||||||
|
AutoCompletesController
|
||||||
|
Issue
|
||||||
|
IssuePriority
|
||||||
|
TimeEntry
|
||||||
|
Project
|
||||||
|
Wiki
|
||||||
|
ProjectsController
|
||||||
|
WelcomeController
|
||||||
|
ReportsController
|
||||||
|
Principal
|
||||||
|
Query
|
||||||
|
QueryFilter
|
||||||
|
Role
|
||||||
|
User
|
||||||
|
UserPreference]
|
||||||
|
|
||||||
|
loader.add_helper %w[Issues
|
||||||
|
Settings
|
||||||
|
Wiki
|
||||||
|
CustomFields]
|
||||||
|
|
||||||
|
loader.add_global_helper [Additionals::Helpers,
|
||||||
|
AdditionalsFontawesomeHelper,
|
||||||
|
AdditionalsMenuHelper,
|
||||||
|
AdditionalsSelect2Helper]
|
||||||
|
|
||||||
|
Redmine::WikiFormatting.format_names.each do |format|
|
||||||
|
case format
|
||||||
|
when 'markdown'
|
||||||
|
loader.add_patch [{ target: Redmine::WikiFormatting::Markdown::HTML, patch: 'FormatterMarkdown' },
|
||||||
|
{ target: Redmine::WikiFormatting::Markdown::Helper, patch: 'FormattingHelper' }]
|
||||||
|
when 'textile'
|
||||||
|
loader.add_patch [{ target: Redmine::WikiFormatting::Textile::Formatter, patch: 'FormatterTextile' },
|
||||||
|
{ target: Redmine::WikiFormatting::Textile::Helper, patch: 'FormattingHelper' }]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Apply patches and helper
|
||||||
|
loader.apply!
|
||||||
|
|
||||||
|
# Macros
|
||||||
|
loader.load_macros!
|
||||||
|
|
||||||
|
# Load view hooks
|
||||||
|
loader.load_view_hooks!
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# Run the classic redmine plugin initializer after rails boot
|
# Run the classic redmine plugin initializer after rails boot
|
||||||
class Plugin < ::Rails::Engine
|
class Plugin < ::Rails::Engine
|
||||||
require 'deface'
|
|
||||||
require 'emoji'
|
require 'emoji'
|
||||||
require 'render_async'
|
require 'render_async'
|
||||||
require 'rss'
|
require 'rss'
|
||||||
@ -179,7 +149,7 @@ module Additionals
|
|||||||
|
|
||||||
# gem is used as redmine plugin
|
# gem is used as redmine plugin
|
||||||
require File.expand_path '../init', __dir__
|
require File.expand_path '../init', __dir__
|
||||||
Additionals.setup if Rails.version < '6.0'
|
Additionals.setup! if Rails.version < '6.0'
|
||||||
Additionals::Gemify.install_assets plugin_id
|
Additionals::Gemify.install_assets plugin_id
|
||||||
Additionals::Gemify.create_plugin_hint plugin_id
|
Additionals::Gemify.create_plugin_hint plugin_id
|
||||||
end
|
end
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require 'emoji'
|
||||||
module Additionals
|
module Additionals
|
||||||
module Formatter
|
module Formatter
|
||||||
SMILEYS = { 'smiley' => ':-?\)', # :)
|
SMILEYS = { 'smiley' => ':-?\)', # :)
|
||||||
|
@ -42,30 +42,6 @@ module Additionals
|
|||||||
l :label_live_search_hints, value: all_fields
|
l :label_live_search_hints, value: all_fields
|
||||||
end
|
end
|
||||||
|
|
||||||
def link_to_external(name, link, **options)
|
|
||||||
options[:class] ||= 'external'
|
|
||||||
options[:class] = "#{options[:class]} external" if options[:class].exclude? 'external'
|
|
||||||
|
|
||||||
options[:rel] ||= 'noopener'
|
|
||||||
options[:target] ||= '_blank'
|
|
||||||
|
|
||||||
link_to name, link, options
|
|
||||||
end
|
|
||||||
|
|
||||||
def link_to_url(url, **options)
|
|
||||||
return if url.blank?
|
|
||||||
|
|
||||||
parts = url.split '://'
|
|
||||||
name = if parts.count.positive?
|
|
||||||
parts.shift
|
|
||||||
parts.join
|
|
||||||
else
|
|
||||||
url
|
|
||||||
end
|
|
||||||
|
|
||||||
link_to_external name, url, **options
|
|
||||||
end
|
|
||||||
|
|
||||||
def additionals_list_title(name:, obj: nil, obj_link: nil, query: nil)
|
def additionals_list_title(name:, obj: nil, obj_link: nil, query: nil)
|
||||||
title = []
|
title = []
|
||||||
case obj
|
case obj
|
||||||
@ -194,7 +170,7 @@ module Additionals
|
|||||||
end
|
end
|
||||||
|
|
||||||
def format_yes(value, lowercase: false)
|
def format_yes(value, lowercase: false)
|
||||||
if Additionals.true? value
|
if RedminePluginKit.true? value
|
||||||
lowercase ? l(:general_text_yes) : l(:general_text_Yes)
|
lowercase ? l(:general_text_yes) : l(:general_text_Yes)
|
||||||
else
|
else
|
||||||
lowercase ? l(:general_text_no) : l(:general_text_No)
|
lowercase ? l(:general_text_no) : l(:general_text_No)
|
||||||
|
13
lib/additionals/hooks/model_hook.rb
Normal file
13
lib/additionals/hooks/model_hook.rb
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
module Additionals
|
||||||
|
module Hooks
|
||||||
|
class ModelHook < Redmine::Hook::Listener
|
||||||
|
def after_plugins_loaded(_context = {})
|
||||||
|
return if Rails.version < '6.0'
|
||||||
|
|
||||||
|
Additionals.setup!
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
module Additionals
|
module Additionals
|
||||||
module Hooks
|
module Hooks
|
||||||
class AdditionalsHookListener < Redmine::Hook::ViewListener
|
class ViewHook < Redmine::Hook::ViewListener
|
||||||
include IssuesHelper
|
include IssuesHelper
|
||||||
include AdditionalsIssuesHelper
|
include AdditionalsIssuesHelper
|
||||||
|
|
||||||
@ -24,10 +24,6 @@ module Additionals
|
|||||||
|
|
||||||
render_on :view_projects_issue_settings, partial: 'projects/additionals_settings_issues'
|
render_on :view_projects_issue_settings, partial: 'projects/additionals_settings_issues'
|
||||||
|
|
||||||
def after_plugins_loaded(_context = {})
|
|
||||||
Additionals.setup if Rails.version > '6.0'
|
|
||||||
end
|
|
||||||
|
|
||||||
def helper_issues_show_detail_after_setting(context = {})
|
def helper_issues_show_detail_after_setting(context = {})
|
||||||
detail = context[:detail]
|
detail = context[:detail]
|
||||||
return unless detail.prop_key == 'author_id'
|
return unless detail.prop_key == 'author_id'
|
@ -11,7 +11,7 @@ module Additionals
|
|||||||
end
|
end
|
||||||
|
|
||||||
def disabled_project_modules
|
def disabled_project_modules
|
||||||
@database_ready = (AdditionalsLoader.redmine_database_ready? Setting.table_name) unless defined? @database_ready
|
@database_ready = (RedminePluginKit::Loader.redmine_database_ready? Setting.table_name) unless defined? @database_ready
|
||||||
return [] unless @database_ready
|
return [] unless @database_ready
|
||||||
|
|
||||||
mods = Additionals.setting(:disabled_modules).to_a.reject(&:blank?)
|
mods = Additionals.setting(:disabled_modules).to_a.reject(&:blank?)
|
||||||
|
@ -44,9 +44,8 @@ module Additionals
|
|||||||
raise '<edit_link> is not a Google document.' unless options[:edit_link].start_with? 'https://docs.google.com/'
|
raise '<edit_link> is not a Google document.' unless options[:edit_link].start_with? 'https://docs.google.com/'
|
||||||
|
|
||||||
s << tag.br
|
s << tag.br
|
||||||
s << link_to(font_awesome_icon('fab_google-drive', post_text: :label_open_in_google_docs),
|
s << link_to_external(font_awesome_icon('fab_google-drive', post_text: :label_open_in_google_docs),
|
||||||
options[:edit_link],
|
options[:edit_link])
|
||||||
class: 'external')
|
|
||||||
end
|
end
|
||||||
|
|
||||||
safe_join s
|
safe_join s
|
||||||
|
@ -35,7 +35,7 @@ module Additionals
|
|||||||
src: src,
|
src: src,
|
||||||
frameborder: 0,
|
frameborder: 0,
|
||||||
allowfullscreen: 'true')]
|
allowfullscreen: 'true')]
|
||||||
s << link_to(l(:label_open_in_new_windows), src, class: 'external') if Additionals.true? options[:with_link]
|
s << link_to(l(:label_open_in_new_windows), src, class: 'external') if RedminePluginKit.true? options[:with_link]
|
||||||
|
|
||||||
safe_join s
|
safe_join s
|
||||||
elsif Setting.protocol == 'https'
|
elsif Setting.protocol == 'https'
|
||||||
|
@ -39,7 +39,7 @@ module Additionals
|
|||||||
raise 'The correct usage is {{meteoblue(<location>[, days=x, color=BOOL])}}' if args.empty?
|
raise 'The correct usage is {{meteoblue(<location>[, days=x, color=BOOL])}}' if args.empty?
|
||||||
|
|
||||||
options[:days] = 4 if options[:days].blank?
|
options[:days] = 4 if options[:days].blank?
|
||||||
options[:coloured] = if Additionals.false? options[:color]
|
options[:coloured] = if RedminePluginKit.false? options[:color]
|
||||||
'monochrome'
|
'monochrome'
|
||||||
else
|
else
|
||||||
'coloured'
|
'coloured'
|
||||||
@ -79,7 +79,7 @@ module Additionals
|
|||||||
|
|
||||||
def self.meteoblue_flag(options, name, default = tue)
|
def self.meteoblue_flag(options, name, default = tue)
|
||||||
flag = +"#{name}="
|
flag = +"#{name}="
|
||||||
flag << if Additionals.true?(options[name]) || default
|
flag << if RedminePluginKit.true?(options[name]) || default
|
||||||
'1'
|
'1'
|
||||||
else
|
else
|
||||||
'0'
|
'0'
|
||||||
|
@ -16,21 +16,21 @@ module Additionals
|
|||||||
|
|
||||||
case name[0..1]
|
case name[0..1]
|
||||||
when 'r/'
|
when 'r/'
|
||||||
link_to font_awesome_icon('fab_reddit', post_text: name),
|
link_to_external font_awesome_icon('fab_reddit', post_text: name),
|
||||||
"https://www.reddit.com/#{name}",
|
"https://www.reddit.com/#{name}",
|
||||||
class: 'external reddit',
|
class: 'reddit',
|
||||||
title: l(:label_reddit_subject)
|
title: l(:label_reddit_subject)
|
||||||
when 'u/'
|
when 'u/'
|
||||||
link_to font_awesome_icon('fab_reddit-square', post_text: name),
|
link_to_external font_awesome_icon('fab_reddit-square', post_text: name),
|
||||||
"https://www.reddit.com/username/#{name[2..]}",
|
"https://www.reddit.com/username/#{name[2..]}",
|
||||||
class: 'external reddit',
|
class: 'reddit',
|
||||||
title: l(:label_reddit_user_account)
|
title: l(:label_reddit_user_account)
|
||||||
else
|
else
|
||||||
name = "r/#{name}"
|
name = "r/#{name}"
|
||||||
link_to font_awesome_icon('fab_reddit', post_text: name),
|
link_to_external font_awesome_icon('fab_reddit', post_text: name),
|
||||||
"https://www.reddit.com/#{name}",
|
"https://www.reddit.com/#{name}",
|
||||||
class: 'external reddit',
|
class: 'reddit',
|
||||||
title: l(:label_reddit_subject)
|
title: l(:label_reddit_subject)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -34,10 +34,10 @@ module Additionals
|
|||||||
link = "https://www.redmine.org/issues/#{raw_link}"
|
link = "https://www.redmine.org/issues/#{raw_link}"
|
||||||
end
|
end
|
||||||
|
|
||||||
link_options = { class: 'external redmine-link' }
|
link_options = { class: 'redmine-link' }
|
||||||
link_options[:title] = options[:title].presence || l(:label_redmine_org_issue)
|
link_options[:title] = options[:title].presence || l(:label_redmine_org_issue)
|
||||||
|
|
||||||
link_to "##{link_name}", link, link_options
|
link_to_external "##{link_name}", link, **link_options
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -15,20 +15,20 @@ module Additionals
|
|||||||
name = args[0].strip
|
name = args[0].strip
|
||||||
case name[0]
|
case name[0]
|
||||||
when '@'
|
when '@'
|
||||||
link_to(font_awesome_icon('fab_twitter', post_text: name),
|
link_to_external font_awesome_icon('fab_twitter', post_text: name),
|
||||||
"https://twitter.com/#{name[1..]}",
|
"https://twitter.com/#{name[1..]}",
|
||||||
class: 'external twitter',
|
class: 'twitter',
|
||||||
title: l(:label_twitter_account))
|
title: l(:label_twitter_account)
|
||||||
when '#'
|
when '#'
|
||||||
link_to(font_awesome_icon('fab_twitter-square', post_text: name),
|
link_to_external font_awesome_icon('fab_twitter-square', post_text: name),
|
||||||
"https://twitter.com/hashtag/#{name[1..]}",
|
"https://twitter.com/hashtag/#{name[1..]}",
|
||||||
class: 'external twitter',
|
class: 'twitter',
|
||||||
title: l(:label_twitter_hashtag))
|
title: l(:label_twitter_hashtag)
|
||||||
else
|
else
|
||||||
link_to(font_awesome_icon('fab_twitter', post_text: " @#{name}"),
|
link_to_external font_awesome_icon('fab_twitter', post_text: " @#{name}"),
|
||||||
"https://twitter.com/#{name}",
|
"https://twitter.com/#{name}",
|
||||||
class: 'external twitter',
|
class: 'twitter',
|
||||||
title: l(:label_twitter_account))
|
title: l(:label_twitter_account)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -27,7 +27,7 @@ module Additionals
|
|||||||
raise 'The correct usage is {{vimeo(<video key>[, width=x, height=y])}}' if args.empty?
|
raise 'The correct usage is {{vimeo(<video key>[, width=x, height=y])}}' if args.empty?
|
||||||
|
|
||||||
v = args[0]
|
v = args[0]
|
||||||
src = if Additionals.true? options[:autoplay]
|
src = if RedminePluginKit.true? options[:autoplay]
|
||||||
"//player.vimeo.com/video/#{v}?autoplay=1"
|
"//player.vimeo.com/video/#{v}?autoplay=1"
|
||||||
else
|
else
|
||||||
"//player.vimeo.com/video/#{v}"
|
"//player.vimeo.com/video/#{v}"
|
||||||
|
@ -27,7 +27,7 @@ module Additionals
|
|||||||
raise 'The correct usage is {{youtube(<video key>[, width=x, height=y])}}' if args.empty?
|
raise 'The correct usage is {{youtube(<video key>[, width=x, height=y])}}' if args.empty?
|
||||||
|
|
||||||
v = args[0]
|
v = args[0]
|
||||||
src = if Additionals.true? options[:autoplay]
|
src = if RedminePluginKit.true? options[:autoplay]
|
||||||
"//www.youtube.com/embed/#{v}?autoplay=1"
|
"//www.youtube.com/embed/#{v}?autoplay=1"
|
||||||
else
|
else
|
||||||
"//www.youtube-nocookie.com/embed/#{v}"
|
"//www.youtube-nocookie.com/embed/#{v}"
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"dependencies": {},
|
"dependencies": {},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"eslint": "^7.0.0",
|
"eslint": "^8.0.0",
|
||||||
"stylelint": "^14.0.0"
|
"stylelint": "^14.0.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,36 +14,6 @@ class AdditionalsTest < Additionals::TestCase
|
|||||||
prepare_tests
|
prepare_tests
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_true
|
|
||||||
assert Additionals.true? 1
|
|
||||||
assert Additionals.true? true
|
|
||||||
assert Additionals.true? 'true'
|
|
||||||
assert Additionals.true? 'True'
|
|
||||||
|
|
||||||
assert_not Additionals.true?(-1)
|
|
||||||
assert_not Additionals.true? 0
|
|
||||||
assert_not Additionals.true? '0'
|
|
||||||
assert_not Additionals.true? 1000
|
|
||||||
assert_not Additionals.true? false
|
|
||||||
assert_not Additionals.true? 'false'
|
|
||||||
assert_not Additionals.true? 'False'
|
|
||||||
assert_not Additionals.true? 'yes'
|
|
||||||
assert_not Additionals.true? ''
|
|
||||||
assert_not Additionals.true? nil
|
|
||||||
assert_not Additionals.true? 'unknown'
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_false
|
|
||||||
assert Additionals.false? false
|
|
||||||
assert Additionals.false? nil
|
|
||||||
assert Additionals.false? 'false'
|
|
||||||
assert Additionals.false? 0
|
|
||||||
|
|
||||||
assert_not Additionals.false? 1
|
|
||||||
assert_not Additionals.false? 'true'
|
|
||||||
assert_not Additionals.false? 'True'
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_settings
|
def test_settings
|
||||||
assert_raises NoMethodError do
|
assert_raises NoMethodError do
|
||||||
Additionals.settings[:open_external_urls]
|
Additionals.settings[:open_external_urls]
|
||||||
|
@ -4,6 +4,7 @@ require File.expand_path '../../../test_helper', __FILE__
|
|||||||
|
|
||||||
class GlobalHelperTest < ActionView::TestCase
|
class GlobalHelperTest < ActionView::TestCase
|
||||||
include Additionals::Helpers
|
include Additionals::Helpers
|
||||||
|
include RedminePluginKit::Helpers::GlobalHelper
|
||||||
include AdditionalsFontawesomeHelper
|
include AdditionalsFontawesomeHelper
|
||||||
include AdditionalsMenuHelper
|
include AdditionalsMenuHelper
|
||||||
include CustomFieldsHelper
|
include CustomFieldsHelper
|
||||||
|
@ -2,37 +2,41 @@
|
|||||||
|
|
||||||
require File.expand_path '../../test_helper', __FILE__
|
require File.expand_path '../../test_helper', __FILE__
|
||||||
|
|
||||||
class AdditionalsLoaderTest < Additionals::TestCase
|
class RedminePluginKitLoaderTest < Additionals::TestCase
|
||||||
|
def setup
|
||||||
|
@plugin_id = 'additionals'
|
||||||
|
end
|
||||||
|
|
||||||
def test_add_patch
|
def test_add_patch
|
||||||
loader = AdditionalsLoader.new
|
loader = RedminePluginKit::Loader.new plugin_id: @plugin_id
|
||||||
loader.add_patch 'Issue'
|
loader.add_patch 'Issue'
|
||||||
|
|
||||||
assert loader.apply!
|
assert loader.apply!
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_add_patch_as_hash
|
def test_add_patch_as_hash
|
||||||
loader = AdditionalsLoader.new
|
loader = RedminePluginKit::Loader.new plugin_id: @plugin_id
|
||||||
loader.add_patch({ target: Issue, patch: 'Issue' })
|
loader.add_patch({ target: Issue, patch: 'Issue' })
|
||||||
|
|
||||||
assert loader.apply!
|
assert loader.apply!
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_add_patch_as_hash_without_patch
|
def test_add_patch_as_hash_without_patch
|
||||||
loader = AdditionalsLoader.new
|
loader = RedminePluginKit::Loader.new plugin_id: @plugin_id
|
||||||
loader.add_patch({ target: Issue })
|
loader.add_patch({ target: Issue })
|
||||||
|
|
||||||
assert loader.apply!
|
assert loader.apply!
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_add_multiple_patches
|
def test_add_multiple_patches
|
||||||
loader = AdditionalsLoader.new
|
loader = RedminePluginKit::Loader.new plugin_id: @plugin_id
|
||||||
loader.add_patch %w[Issue User]
|
loader.add_patch %w[Issue User]
|
||||||
|
|
||||||
assert loader.apply!
|
assert loader.apply!
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_add_invalid_patch
|
def test_add_invalid_patch
|
||||||
loader = AdditionalsLoader.new
|
loader = RedminePluginKit::Loader.new plugin_id: @plugin_id
|
||||||
loader.add_patch 'Issue2'
|
loader.add_patch 'Issue2'
|
||||||
|
|
||||||
assert_raises NameError do
|
assert_raises NameError do
|
||||||
@ -41,55 +45,42 @@ class AdditionalsLoaderTest < Additionals::TestCase
|
|||||||
end
|
end
|
||||||
|
|
||||||
def test_add_helper
|
def test_add_helper
|
||||||
loader = AdditionalsLoader.new
|
loader = RedminePluginKit::Loader.new plugin_id: @plugin_id
|
||||||
loader.add_helper 'Settings'
|
loader.add_helper 'Settings'
|
||||||
|
|
||||||
assert loader.apply!
|
assert loader.apply!
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_add_helper_as_hash
|
def test_add_helper_as_hash
|
||||||
loader = AdditionalsLoader.new
|
loader = RedminePluginKit::Loader.new plugin_id: @plugin_id
|
||||||
loader.add_helper({ controller: SettingsController, helper: SettingsHelper })
|
loader.add_helper({ controller: SettingsController, helper: SettingsHelper })
|
||||||
|
|
||||||
assert loader.apply!
|
assert loader.apply!
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_add_helper_as_hash_as_string
|
def test_add_helper_as_hash_as_string
|
||||||
loader = AdditionalsLoader.new
|
loader = RedminePluginKit::Loader.new plugin_id: @plugin_id
|
||||||
loader.add_helper({ controller: 'Settings', helper: 'Settings' })
|
loader.add_helper({ controller: 'Settings', helper: 'Settings' })
|
||||||
|
|
||||||
assert loader.apply!
|
assert loader.apply!
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_add_helper_as_hash_controller_only
|
def test_add_helper_as_hash_controller_only
|
||||||
loader = AdditionalsLoader.new
|
loader = RedminePluginKit::Loader.new plugin_id: @plugin_id
|
||||||
loader.add_helper({ controller: SettingsController })
|
loader.add_helper({ controller: SettingsController })
|
||||||
|
|
||||||
assert loader.apply!
|
assert loader.apply!
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_add_helper_as_hash_controller_only_string
|
def test_add_helper_as_hash_controller_only_string
|
||||||
loader = AdditionalsLoader.new
|
loader = RedminePluginKit::Loader.new plugin_id: @plugin_id
|
||||||
loader.add_helper({ controller: 'Settings' })
|
loader.add_helper({ controller: 'Settings' })
|
||||||
|
|
||||||
assert loader.apply!
|
assert loader.apply!
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_load_macros
|
|
||||||
loader = AdditionalsLoader.new
|
|
||||||
macros = loader.load_macros!
|
|
||||||
|
|
||||||
assert macros.count.positive?
|
|
||||||
assert(macros.detect { |macro| macro.include? 'fa_macro' })
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_load_hooks
|
|
||||||
hooks = AdditionalsLoader.load_hooks!
|
|
||||||
assert hooks.is_a? Module
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_require_files_for_lib
|
def test_require_files_for_lib
|
||||||
loader = AdditionalsLoader.new
|
loader = RedminePluginKit::Loader.new plugin_id: @plugin_id
|
||||||
|
|
||||||
spec = File.join 'wiki_macros', '**/*_macro.rb'
|
spec = File.join 'wiki_macros', '**/*_macro.rb'
|
||||||
files = loader.require_files spec
|
files = loader.require_files spec
|
||||||
@ -99,7 +90,7 @@ class AdditionalsLoaderTest < Additionals::TestCase
|
|||||||
end
|
end
|
||||||
|
|
||||||
def test_require_files_for_app
|
def test_require_files_for_app
|
||||||
loader = AdditionalsLoader.new
|
loader = RedminePluginKit::Loader.new plugin_id: @plugin_id
|
||||||
|
|
||||||
spec = File.join 'helpers', '**/additionals_*.rb'
|
spec = File.join 'helpers', '**/additionals_*.rb'
|
||||||
files = loader.require_files spec, use_app: true
|
files = loader.require_files spec, use_app: true
|
||||||
@ -109,12 +100,12 @@ class AdditionalsLoaderTest < Additionals::TestCase
|
|||||||
end
|
end
|
||||||
|
|
||||||
def test_apply_without_data
|
def test_apply_without_data
|
||||||
loader = AdditionalsLoader.new
|
loader = RedminePluginKit::Loader.new plugin_id: @plugin_id
|
||||||
assert loader.apply!
|
assert loader.apply!
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_apply
|
def test_apply
|
||||||
loader = AdditionalsLoader.new
|
loader = RedminePluginKit::Loader.new plugin_id: @plugin_id
|
||||||
loader.add_helper 'Settings'
|
loader.add_helper 'Settings'
|
||||||
loader.add_patch 'Issue'
|
loader.add_patch 'Issue'
|
||||||
loader.add_global_helper Additionals::Helpers
|
loader.add_global_helper Additionals::Helpers
|
||||||
@ -122,22 +113,40 @@ class AdditionalsLoaderTest < Additionals::TestCase
|
|||||||
end
|
end
|
||||||
|
|
||||||
def test_do_not_allow_helper_if_controller_patch_exists
|
def test_do_not_allow_helper_if_controller_patch_exists
|
||||||
loader = AdditionalsLoader.new
|
loader = RedminePluginKit::Loader.new plugin_id: @plugin_id
|
||||||
loader.add_patch 'ProjectsController'
|
loader.add_patch 'ProjectsController'
|
||||||
loader.add_helper 'Projects'
|
loader.add_helper 'Projects'
|
||||||
|
|
||||||
assert_raises AdditionalsLoader::ExistingControllerPatchForHelper do
|
assert_raises RedminePluginKit::Loader::ExistingControllerPatchForHelper do
|
||||||
assert loader.apply!
|
assert loader.apply!
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_do_not_allow_helper_if_controller_patch_exists_as_hash
|
def test_do_not_allow_helper_if_controller_patch_exists_as_hash
|
||||||
loader = AdditionalsLoader.new
|
loader = RedminePluginKit::Loader.new plugin_id: @plugin_id
|
||||||
loader.add_patch 'ProjectsController'
|
loader.add_patch 'ProjectsController'
|
||||||
loader.add_helper({ controller: ProjectsController, helper: 'Settings' })
|
loader.add_helper({ controller: ProjectsController, helper: 'Settings' })
|
||||||
|
|
||||||
assert_raises AdditionalsLoader::ExistingControllerPatchForHelper do
|
assert_raises RedminePluginKit::Loader::ExistingControllerPatchForHelper do
|
||||||
assert loader.apply!
|
assert loader.apply!
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_load_model_hooks
|
||||||
|
hooks = RedminePluginKit::Loader.new(plugin_id: @plugin_id).load_model_hooks!
|
||||||
|
assert hooks.is_a? Module
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_load_hooks
|
||||||
|
hooks = RedminePluginKit::Loader.new(plugin_id: @plugin_id).load_view_hooks!
|
||||||
|
assert hooks.is_a? Module
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_load_macros
|
||||||
|
loader = RedminePluginKit::Loader.new plugin_id: @plugin_id
|
||||||
|
macros = loader.load_macros!
|
||||||
|
|
||||||
|
assert macros.count.positive?
|
||||||
|
assert(macros.detect { |macro| macro.include? 'fa_macro' })
|
||||||
|
end
|
||||||
end
|
end
|
Loading…
Reference in New Issue
Block a user