From 9380721ea5ed24e260ab158ff48dd28fee11f679 Mon Sep 17 00:00:00 2001
From: Akiko Takano
Date: Wed, 1 Jan 2020 21:31:45 +0900
Subject: [PATCH 01/30] Add column to store related (sample) link for the
template.
---
...20200101204020_add_related_link_to_issue_templates.rb | 9 +++++++++
...1204220_add_related_link_to_global_issue_templates.rb | 9 +++++++++
2 files changed, 18 insertions(+)
create mode 100644 db/migrate/20200101204020_add_related_link_to_issue_templates.rb
create mode 100644 db/migrate/20200101204220_add_related_link_to_global_issue_templates.rb
diff --git a/db/migrate/20200101204020_add_related_link_to_issue_templates.rb b/db/migrate/20200101204020_add_related_link_to_issue_templates.rb
new file mode 100644
index 00000000..76abcbae
--- /dev/null
+++ b/db/migrate/20200101204020_add_related_link_to_issue_templates.rb
@@ -0,0 +1,9 @@
+class AddRelatedLinkToIssueTemplates < ActiveRecord::Migration[5.2]
+ def self.up
+ add_column :issue_templates, :related_link, :text
+ end
+
+ def self.down
+ remove_column :issue_templates, :related_link
+ end
+end
diff --git a/db/migrate/20200101204220_add_related_link_to_global_issue_templates.rb b/db/migrate/20200101204220_add_related_link_to_global_issue_templates.rb
new file mode 100644
index 00000000..7b1e32c8
--- /dev/null
+++ b/db/migrate/20200101204220_add_related_link_to_global_issue_templates.rb
@@ -0,0 +1,9 @@
+class AddRelatedLinkToGlobalIssueTemplates < ActiveRecord::Migration[5.2]
+ def self.up
+ add_column :global_issue_templates, :related_link, :text
+ end
+
+ def self.down
+ remove_column :global_issue_templates, :related_link
+ end
+end
From 5246148df50ef331eb287c712cbadf82b39fea52 Mon Sep 17 00:00:00 2001
From: Akiko Takano
Date: Wed, 1 Jan 2020 22:35:50 +0900
Subject: [PATCH 02/30] Add basic validation and spec for new column.
---
.rubocop_todo.yml | 10 ++-------
app/models/concerns/issue_template/common.rb | 1 +
app/models/global_issue_template.rb | 3 ++-
app/models/issue_template.rb | 14 ++++++++++--
...020_add_related_link_to_issue_templates.rb | 2 ++
..._related_link_to_global_issue_templates.rb | 2 ++
spec/models/global_issue_template_spec.rb | 22 +++++++++++++++++++
spec/models/issue_template_spec.rb | 21 +++++++++++++++++-
8 files changed, 63 insertions(+), 12 deletions(-)
create mode 100644 spec/models/global_issue_template_spec.rb
diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml
index 8d0b95ee..40d9dfd9 100644
--- a/.rubocop_todo.yml
+++ b/.rubocop_todo.yml
@@ -13,13 +13,13 @@ Metrics/AbcSize:
# Offense count: 1
# Configuration parameters: CountComments.
Metrics/ClassLength:
- Max: 200
+ Max: 200
Exclude:
- 'spec/**/*'
- 'test/**/*'
# "Line is too long"を無効
-Metrics/LineLength:
+Layout/LineLength:
Enabled: false
# Offense count: 1
@@ -51,9 +51,3 @@ EndOfLine:
Metrics/ModuleLength:
Max: 120
-# NOTE: Follow Redmine's model definition
-Rails/ApplicationRecord:
- Enabled: false
-
-Rails/InverseOf:
- Enabled: false
diff --git a/app/models/concerns/issue_template/common.rb b/app/models/concerns/issue_template/common.rb
index 19159e65..b69b643b 100644
--- a/app/models/concerns/issue_template/common.rb
+++ b/app/models/concerns/issue_template/common.rb
@@ -17,6 +17,7 @@ module Common
validates :title, presence: true
validates :tracker, presence: true
+ validates :related_link, format: { with: URI::DEFAULT_PARSER.make_regexp }, allow_blank: true
scope :enabled, -> { where(enabled: true) }
scope :sorted, -> { order(:position) }
diff --git a/app/models/global_issue_template.rb b/app/models/global_issue_template.rb
index eaadc4c6..3c05f606 100644
--- a/app/models/global_issue_template.rb
+++ b/app/models/global_issue_template.rb
@@ -16,7 +16,8 @@ class GlobalIssueTemplate < ActiveRecord::Base
'project_ids',
'position',
'author_id',
- 'checklist_json'
+ 'checklist_json',
+ 'related_link'
# for intermediate table assosciations
scope :search_by_project, lambda { |project_id|
diff --git a/app/models/issue_template.rb b/app/models/issue_template.rb
index 42355dc5..898d436a 100644
--- a/app/models/issue_template.rb
+++ b/app/models/issue_template.rb
@@ -7,8 +7,18 @@ class IssueTemplate < ActiveRecord::Base
acts_as_positioned scope: %i[project_id tracker_id]
# author and project should be stable.
- safe_attributes 'title', 'description', 'tracker_id', 'note', 'enabled', 'issue_title', 'is_default',
- 'enabled_sharing', 'visible_children', 'position', 'checklist_json'
+ safe_attributes 'title',
+ 'description',
+ 'tracker_id',
+ 'note',
+ 'enabled',
+ 'issue_title',
+ 'is_default',
+ 'enabled_sharing',
+ 'visible_children',
+ 'position',
+ 'checklist_json',
+ 'related_link'
scope :enabled_sharing, -> { where(enabled_sharing: true) }
scope :search_by_project, lambda { |prolect_id|
diff --git a/db/migrate/20200101204020_add_related_link_to_issue_templates.rb b/db/migrate/20200101204020_add_related_link_to_issue_templates.rb
index 76abcbae..034ffccf 100644
--- a/db/migrate/20200101204020_add_related_link_to_issue_templates.rb
+++ b/db/migrate/20200101204020_add_related_link_to_issue_templates.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class AddRelatedLinkToIssueTemplates < ActiveRecord::Migration[5.2]
def self.up
add_column :issue_templates, :related_link, :text
diff --git a/db/migrate/20200101204220_add_related_link_to_global_issue_templates.rb b/db/migrate/20200101204220_add_related_link_to_global_issue_templates.rb
index 7b1e32c8..9ae6b09a 100644
--- a/db/migrate/20200101204220_add_related_link_to_global_issue_templates.rb
+++ b/db/migrate/20200101204220_add_related_link_to_global_issue_templates.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class AddRelatedLinkToGlobalIssueTemplates < ActiveRecord::Migration[5.2]
def self.up
add_column :global_issue_templates, :related_link, :text
diff --git a/spec/models/global_issue_template_spec.rb b/spec/models/global_issue_template_spec.rb
new file mode 100644
index 00000000..bc014ebc
--- /dev/null
+++ b/spec/models/global_issue_template_spec.rb
@@ -0,0 +1,22 @@
+# frozen_string_literal: true
+
+require_relative '../spec_helper'
+
+describe GlobalIssueTemplate do
+ describe '#valid?' do
+ let(:instance) { GlobalIssueTemplate.new(tracker_id: tracker.id, title: 'sample') }
+ let(:tracker) { FactoryBot.create(:tracker, :with_default_status) }
+ subject { instance.valid? }
+
+ it 'related_link in invalid format' do
+ instance.related_link = 'non url format string'
+ is_expected.to be_falsey
+ expect(instance.errors.messages.key?(:related_link)).to be_truthy
+ end
+
+ it 'related_link in valid format' do
+ instance.related_link = 'https://valid.example.com/links.html'
+ is_expected.to be_truthy
+ end
+ end
+end
diff --git a/spec/models/issue_template_spec.rb b/spec/models/issue_template_spec.rb
index 6e670dc8..0b092e05 100644
--- a/spec/models/issue_template_spec.rb
+++ b/spec/models/issue_template_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require_relative '../spec_helper'
describe IssueTemplate do
@@ -12,7 +14,8 @@
describe 'scope .orphaned' do
subject { IssueTemplate.orphaned.count }
before do
- issue_template.update_attribute(:tracker_id, 0)
+ # Remove related tracker
+ issue_template.tracker.delete
end
it { is_expected.to eq 1 }
end
@@ -51,4 +54,20 @@
end
end
end
+
+ describe '#valid?' do
+ let(:instance) { described_class.new(tracker_id: tracker.id, project_id: project.id, title: 'sample') }
+ subject { instance.valid? }
+
+ it 'related_link in invalid format' do
+ instance.related_link = 'non url format string'
+ is_expected.to be_falsey
+ expect(instance.errors.messages.key?(:related_link)).to be_truthy
+ end
+
+ it 'related_link in valid format' do
+ instance.related_link = 'https://valid.example.com/links.html'
+ is_expected.to be_truthy
+ end
+ end
end
From b1d6d641634a219877c2fd75a5df3efac4c7a73a Mon Sep 17 00:00:00 2001
From: Akiko Takano
Date: Fri, 3 Jan 2020 12:30:48 +0900
Subject: [PATCH 03/30] Update related files and translations.
---
.rubocop.yml | 3 +++
.rubocop_todo.yml | 1 -
assets/stylesheets/issue_templates.css | 4 ++++
config/locales/en.yml | 4 ++++
config/locales/ja.yml | 4 ++++
.../global_issue_templates_controller_spec.rb | 11 +++++++++++
6 files changed, 26 insertions(+), 1 deletion(-)
diff --git a/.rubocop.yml b/.rubocop.yml
index 803a6275..b389cd4c 100644
--- a/.rubocop.yml
+++ b/.rubocop.yml
@@ -1,3 +1,6 @@
inherit_from: .rubocop_todo.yml
AllCops:
TargetRubyVersion: 2.3
+ Exclude:
+ - 'db/**/*'
+
diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml
index 40d9dfd9..eeacf4ca 100644
--- a/.rubocop_todo.yml
+++ b/.rubocop_todo.yml
@@ -50,4 +50,3 @@ EndOfLine:
Metrics/ModuleLength:
Max: 120
-
diff --git a/assets/stylesheets/issue_templates.css b/assets/stylesheets/issue_templates.css
index 33f1a8a2..058daa5d 100644
--- a/assets/stylesheets/issue_templates.css
+++ b/assets/stylesheets/issue_templates.css
@@ -94,6 +94,10 @@ option.global {
background: url("../images/issue_templates.png") no-repeat 3px center;
}
+.icon-hint {
+ background: url("../images/ticket.png") no-repeat 3px center;
+}
+
a.template_tooltip {
background-image: url("../images/preview.png");
background-repeat: no-repeat;
diff --git a/config/locales/en.yml b/config/locales/en.yml
index eb4fb9ed..17815fb8 100644
--- a/config/locales/en.yml
+++ b/config/locales/en.yml
@@ -74,3 +74,7 @@ en:
please_select_at_least_one_role: "Please select at least one role."
issue_templates_settings: Issue Templates Setting
issue_templates_optional_settings: Templates Optional Settings
+ issue_template_related_link: Related Link
+ issue_template_link_title: Related Link Title
+ label_related_link_help_message: "If there are some example pages or sample issues which using issue template, please specify the link. So operator can see them as an usage or example for template."
+ label_link_title_help_message: "You can customize the title of the related link. (Default: Related Link)"
diff --git a/config/locales/ja.yml b/config/locales/ja.yml
index aa3d2e88..0df2d430 100644
--- a/config/locales/ja.yml
+++ b/config/locales/ja.yml
@@ -75,3 +75,7 @@ ja:
please_select_at_least_one_role: 1つ以上のロールを指定してください。
issue_templates_settings: チケットテンプレート設定
issue_templates_optional_settings: テンプレートオプション設定
+ issue_template_related_link: 関連リンク
+ issue_template_link_title: 関連リンクのタイトル
+ label_related_link_help_message: "テンプレートの利用例や、説明のページがあれば、関連リンクを設定できます。"
+ label_link_title_help_message: "関連リンクのタイトルは任意で設定できます(デフォルト: 関連リンク)"
diff --git a/spec/controllers/global_issue_templates_controller_spec.rb b/spec/controllers/global_issue_templates_controller_spec.rb
index 64342129..97937560 100644
--- a/spec/controllers/global_issue_templates_controller_spec.rb
+++ b/spec/controllers/global_issue_templates_controller_spec.rb
@@ -71,6 +71,17 @@
expect(global_issue_template.projects.count).to eq projects.count
end
end
+
+ context 'POST with invalid url' do
+ let(:project_ids) { [] }
+ include_examples 'Right response', 302
+ before do
+ create_params.merge!(related_link: 'bad format url')
+ end
+ it do
+ expect(global_issue_template.present?).to be_truthy
+ end
+ end
end
# PATCH GlobalIssueTemplatesController#edit
From 0b849704e2ae386459e570c93e23f23802ba33d4 Mon Sep 17 00:00:00 2001
From: Akiko Takano
Date: Fri, 3 Jan 2020 12:54:18 +0900
Subject: [PATCH 04/30] Add link_title and attribute.
---
app/controllers/global_issue_templates_controller.rb | 4 +++-
app/controllers/issue_templates_controller.rb | 5 ++++-
app/models/concerns/issue_template/common.rb | 1 +
app/models/global_issue_template.rb | 11 +++++++----
app/models/issue_template.rb | 9 ++++++---
...0200102204815_add_link_title_to_issue_templates.rb | 11 +++++++++++
...205044_add_link_title_to_global_issue_templates.rb | 11 +++++++++++
7 files changed, 43 insertions(+), 9 deletions(-)
create mode 100644 db/migrate/20200102204815_add_link_title_to_issue_templates.rb
create mode 100644 db/migrate/20200102205044_add_link_title_to_global_issue_templates.rb
diff --git a/app/controllers/global_issue_templates_controller.rb b/app/controllers/global_issue_templates_controller.rb
index 11d4904d..b5994995 100644
--- a/app/controllers/global_issue_templates_controller.rb
+++ b/app/controllers/global_issue_templates_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
# noinspection RubocopInspection
class GlobalIssueTemplatesController < ApplicationController
layout 'base'
@@ -106,7 +108,7 @@ def save_and_flash(message, action_on_failure)
def template_params
params.require(:global_issue_template)
.permit(:title, :tracker_id, :issue_title, :description, :note, :is_default, :enabled,
- :author_id, :position, project_ids: [], checklists: [])
+ :author_id, :position, :related_link, :link_title, project_ids: [], checklists: [])
end
def render_form_params
diff --git a/app/controllers/issue_templates_controller.rb b/app/controllers/issue_templates_controller.rb
index ef220463..8b6d0c91 100644
--- a/app/controllers/issue_templates_controller.rb
+++ b/app/controllers/issue_templates_controller.rb
@@ -1,4 +1,5 @@
# frozen_string_literal: true
+
# noinspection ALL
class IssueTemplatesController < ApplicationController
layout 'base'
@@ -194,7 +195,9 @@ def inherit_templates
def template_params
params.require(:issue_template).permit(:tracker_id, :title, :note, :issue_title, :description, :is_default,
- :enabled, :author_id, :position, :enabled_sharing, checklists: [])
+ :enabled, :author_id, :position, :enabled_sharing,
+ :related_link, :link_title,
+ checklists: [])
end
def templates_exist?
diff --git a/app/models/concerns/issue_template/common.rb b/app/models/concerns/issue_template/common.rb
index b69b643b..d8605e0f 100644
--- a/app/models/concerns/issue_template/common.rb
+++ b/app/models/concerns/issue_template/common.rb
@@ -73,6 +73,7 @@ def template_json
def generate_json
result = attributes
+ result[:link_title] = link_title.presence || I18n.t(:issue_template_related_link, default: 'Related Link')
result[:checklist] = checklist
result.except('checklist_json')
end
diff --git a/app/models/global_issue_template.rb b/app/models/global_issue_template.rb
index 3c05f606..37f8f7c0 100644
--- a/app/models/global_issue_template.rb
+++ b/app/models/global_issue_template.rb
@@ -1,10 +1,12 @@
+# frozen_string_literal: true
+
class GlobalIssueTemplate < ActiveRecord::Base
include Redmine::SafeAttributes
include Concerns::IssueTemplate::Common
- validates_uniqueness_of :title, scope: :tracker_id
+ validates :title, uniqueness: { scope: :tracker_id }
has_and_belongs_to_many :projects
- acts_as_positioned :scope => [:tracker_id]
+ acts_as_positioned scope: [:tracker_id]
safe_attributes 'title',
'description',
@@ -17,7 +19,8 @@ class GlobalIssueTemplate < ActiveRecord::Base
'position',
'author_id',
'checklist_json',
- 'related_link'
+ 'related_link',
+ 'link_title'
# for intermediate table assosciations
scope :search_by_project, lambda { |project_id|
@@ -25,7 +28,7 @@ class GlobalIssueTemplate < ActiveRecord::Base
}
module Config
- JSON_OBJECT_NAME = 'global_issue_template'.freeze
+ JSON_OBJECT_NAME = 'global_issue_template'
end
Config.freeze
diff --git a/app/models/issue_template.rb b/app/models/issue_template.rb
index 898d436a..8e7bdc31 100644
--- a/app/models/issue_template.rb
+++ b/app/models/issue_template.rb
@@ -1,9 +1,11 @@
+# frozen_string_literal: true
+
class IssueTemplate < ActiveRecord::Base
include Redmine::SafeAttributes
include Concerns::IssueTemplate::Common
belongs_to :project
validates :project_id, presence: true
- validates_uniqueness_of :title, scope: :project_id
+ validates :title, uniqueness: { scope: :project_id }
acts_as_positioned scope: %i[project_id tracker_id]
# author and project should be stable.
@@ -18,7 +20,8 @@ class IssueTemplate < ActiveRecord::Base
'visible_children',
'position',
'checklist_json',
- 'related_link'
+ 'related_link',
+ 'link_title'
scope :enabled_sharing, -> { where(enabled_sharing: true) }
scope :search_by_project, lambda { |prolect_id|
@@ -26,7 +29,7 @@ class IssueTemplate < ActiveRecord::Base
}
module Config
- JSON_OBJECT_NAME = 'issue_template'.freeze
+ JSON_OBJECT_NAME = 'issue_template'
end
Config.freeze
diff --git a/db/migrate/20200102204815_add_link_title_to_issue_templates.rb b/db/migrate/20200102204815_add_link_title_to_issue_templates.rb
new file mode 100644
index 00000000..97539e9b
--- /dev/null
+++ b/db/migrate/20200102204815_add_link_title_to_issue_templates.rb
@@ -0,0 +1,11 @@
+# frozen_string_literal: true
+
+class AddLinkTitleToIssueTemplates < ActiveRecord::Migration[5.2]
+ def self.up
+ add_column :issue_templates, :link_title, :text
+ end
+
+ def self.down
+ remove_column :issue_templates, :link_title
+ end
+end
diff --git a/db/migrate/20200102205044_add_link_title_to_global_issue_templates.rb b/db/migrate/20200102205044_add_link_title_to_global_issue_templates.rb
new file mode 100644
index 00000000..c5a34e8e
--- /dev/null
+++ b/db/migrate/20200102205044_add_link_title_to_global_issue_templates.rb
@@ -0,0 +1,11 @@
+# frozen_string_literal: true
+
+class AddLinkTitleToGlobalIssueTemplates < ActiveRecord::Migration[5.2]
+ def self.up
+ add_column :global_issue_templates, :link_title, :text
+ end
+
+ def self.down
+ remove_column :global_issue_templates, :link_title
+ end
+end
From 26fab1ddc3330b46e86ab05a6cef155d35559c75 Mon Sep 17 00:00:00 2001
From: Akiko Takano
Date: Fri, 3 Jan 2020 13:28:01 +0900
Subject: [PATCH 05/30] Add form to input related_link and link_title.
---
.../global_issue_templates/_form.html.erb | 29 +++++++++++++++++--
app/views/issue_templates/_form.html.erb | 29 +++++++++++++++++++
app/views/issue_templates/show.html.erb | 4 +++
3 files changed, 59 insertions(+), 3 deletions(-)
diff --git a/app/views/global_issue_templates/_form.html.erb b/app/views/global_issue_templates/_form.html.erb
index 0f5dbfbe..789ad152 100644
--- a/app/views/global_issue_templates/_form.html.erb
+++ b/app/views/global_issue_templates/_form.html.erb
@@ -57,6 +57,27 @@
label: l(:issue_template_note), style: 'overflow:auto;' %>
+ <%= f.text_field :related_link, type: 'url',
+ size: 70, label: l(:issue_template_related_link, default: 'Related link') %>
+
+ <%= l(:help_for_this_field) %>
+
+
+
+
+ <%= f.text_field :link_title, size: 70, label: l(:issue_template_link_title, default: 'Link title') %>
+
+ <%= l(:help_for_this_field) %>
+
+
+
+
<%= f.check_box :is_default, label: l(:field_is_default) %>
<%= l(:label_isdefault_help_message) %>
-
- <%= l(:label_isdefault_help_message) %>
+
+ <%= l(:label_related_link_help_message, default: 'If there are some example pages or sample issues which using issue template, please specify the link. So operator can see them as an usage or example for template.') %>
+
+
+ <%= l(:label_link_title_help_message, default: 'If there are some example pages or sample issues which using issue template, please specify the link. So operator can see them as an usage or example for template.') %>
<%= l(:label_enabled_help_message) %>
-
diff --git a/app/views/issue_templates/_form.html.erb b/app/views/issue_templates/_form.html.erb
index 6cbebcc4..a3af9b48 100644
--- a/app/views/issue_templates/_form.html.erb
+++ b/app/views/issue_templates/_form.html.erb
@@ -62,6 +62,27 @@
label: l(:issue_template_note) %>
+
<%= f.text_field :related_link, type: 'url',
+ size: 70, label: l(:issue_template_related_link, default: 'Related link') %>
+
+ <%= l(:help_for_this_field) %>
+
+
+
+
+
<%= f.text_field :link_title, size: 70, label: l(:issue_template_link_title, default: 'Link title') %>
+
+ <%= l(:help_for_this_field) %>
+
+
+
+
<%= f.check_box :is_default, label: l(:field_is_default) %>
+
+ <%= l(:label_related_link_help_message, default: 'If there are some example pages or sample issues which using issue template, please specify the link. So operator can see them as an usage or example for template.') %>
+
+
+
+ <%= l(:label_link_title_help_message, default: 'If there are some example pages or sample issues which using issue template, please specify the link. So operator can see them as an usage or example for template.') %>
+
+
<%= l(:label_isdefault_help_message) %>
diff --git a/app/views/issue_templates/show.html.erb b/app/views/issue_templates/show.html.erb
index d23d963f..6b3ba7f8 100644
--- a/app/views/issue_templates/show.html.erb
+++ b/app/views/issue_templates/show.html.erb
@@ -92,6 +92,10 @@
<%= issue_template.note.blank? ? l(:label_none) : issue_template.note %>
+
<%= l(:issue_template_related_link, default: 'Related Link') %>
+ <%= issue_template.related_link.blank? ? l(:label_none) : issue_template.related_link %>
+
+
<%= l(:field_is_default) %>
<%= checked_image issue_template.is_default? %>
From 4895e9b8458cdc1fe2a242f74370191345cfa8c1 Mon Sep 17 00:00:00 2001
From: Akiko Takano
Date: Fri, 3 Jan 2020 14:32:03 +0900
Subject: [PATCH 06/30] Enabled to show related link when selecting pulldown.
Also the preview content includes the related link at index.html.
---
.../global_issue_templates/index.html.erb | 5 +++
.../_issue_select_form.html.erb | 1 +
.../issue_templates/_list_templates.html.erb | 15 +++++++++
app/views/issue_templates/index.html.erb | 32 +++++++++++++++++--
assets/javascripts/issue_templates.js | 10 ++++++
5 files changed, 61 insertions(+), 2 deletions(-)
diff --git a/app/views/global_issue_templates/index.html.erb b/app/views/global_issue_templates/index.html.erb
index 2764f180..57d3a01e 100644
--- a/app/views/global_issue_templates/index.html.erb
+++ b/app/views/global_issue_templates/index.html.erb
@@ -50,6 +50,11 @@
<%= issue_template.title %>
<%= textilizable(issue_template.description) %>
+ <% if issue_template.related_link.present? %>
+
+ <%= link_to issue_template.link_title.present? ? issue_template.link_title : l(:issue_template_related_link, default: 'Related link'),
+ issue_template.related_link, target: '_blank', rel: 'nofollow noopener', class: 'external' %>
+ <% end %>
diff --git a/app/views/issue_templates/_issue_select_form.html.erb b/app/views/issue_templates/_issue_select_form.html.erb
index de56c7f8..27b598f1 100644
--- a/app/views/issue_templates/_issue_select_form.html.erb
+++ b/app/views/issue_templates/_issue_select_form.html.erb
@@ -7,6 +7,7 @@
---
+
<%=h l(:display_and_filter_issue_templates_in_dialog, default: 'Filter Templates') %>
diff --git a/app/views/issue_templates/_list_templates.html.erb b/app/views/issue_templates/_list_templates.html.erb
index a1160a91..a57f9170 100644
--- a/app/views/issue_templates/_list_templates.html.erb
+++ b/app/views/issue_templates/_list_templates.html.erb
@@ -22,6 +22,11 @@
<%= template.title %>
<%= textilizable(template.description) %>
+ <% if template.related_link.present? %>
+
+ <%= link_to template.link_title.present? ? template.link_title : l(:issue_template_related_link, default: 'Related link'),
+ template.related_link, target: '_blank', rel: 'nofollow noopener', class: 'external' %>
+ <% end %>
@@ -46,6 +51,11 @@
<%= template.title %>
<%= textilizable(template.description) %>
+ <% if template.related_link.present? %>
+
+ <%= link_to template.link_title.present? ? template.link_title : l(:issue_template_related_link, default: 'Related link'),
+ template.related_link, target: '_blank', rel: 'nofollow noopener', class: 'external' %>
+ <% end %>
@@ -70,6 +80,11 @@
<%= template.issue_title %>
<%= textilizable(template.description) %>
+ <% if template.related_link.present? %>
+
+ <%= link_to template.link_title.present? ? template.link_title : l(:issue_template_related_link, default: 'Related link'),
+ template.related_link, target: '_blank', rel: 'nofollow noopener', class: 'external' %>
+ <% end %>
diff --git a/app/views/issue_templates/index.html.erb b/app/views/issue_templates/index.html.erb
index cdc8da1d..356d8480 100644
--- a/app/views/issue_templates/index.html.erb
+++ b/app/views/issue_templates/index.html.erb
@@ -61,6 +61,11 @@
<%= issue_template.title %>
<%= textilizable(issue_template.description) %>
+ <% if issue_template.related_link.present? %>
+
+ <%= link_to issue_template.link_title.present? ? issue_template.link_title : l(:issue_template_related_link, default: 'Related link'),
+ issue_template.related_link, target: '_blank', rel: 'nofollow noopener', class: 'external' %>
+ <% end %>
@@ -129,6 +134,11 @@
<%=h issue_template.title %>
<%=h textilizable(issue_template.description) %>
+ <% if issue_template.related_link.present? %>
+
+ <%= link_to issue_template.link_title.present? ? issue_template.link_title : l(:issue_template_related_link, default: 'Related link'),
+ issue_template.related_link, target: '_blank', rel: 'nofollow noopener', class: 'external' %>
+ <% end %>
@@ -140,7 +150,13 @@
- <%=h textilizable(issue_template.description) %>
+ <%=h textilizable(issue_template.description) %>
+
+ <%= link_to_if issue_template.related_link.present?,
+ issue_template.link_title.present? ? issue_template.link_title : l(:issue_template_related_link, default: 'Related link'),
+ issue_template.related_link, target: '_blank', rel: 'nofollow noopener', class: 'external' %>
+
+
<% end %>
@@ -201,6 +217,11 @@
<%=h issue_template.title %>
<%=h textilizable(issue_template.description) %>
+ <% if issue_template.related_link.present? %>
+
+ <%= link_to issue_template.link_title.present? ? issue_template.link_title : l(:issue_template_related_link, default: 'Related link'),
+ issue_template.related_link, target: '_blank', rel: 'nofollow noopener', class: 'external' %>
+ <% end %>
@@ -219,7 +240,14 @@
- <%=h textilizable(issue_template.description) %>
+ <%=h textilizable(issue_template.description) %>
+ <% if issue_template.related_link.present? %>
+
+ <%= link_to issue_template.link_title.present? ? issue_template.link_title : l(:issue_template_related_link, default: 'Related link'),
+ issue_template.related_link, target: '_blank', rel: 'nofollow noopener', class: 'external' %>
+ <% end %>
+
+
<% end %>
diff --git a/assets/javascripts/issue_templates.js b/assets/javascripts/issue_templates.js
index 6c9355cc..c2a2a889 100644
--- a/assets/javascripts/issue_templates.js
+++ b/assets/javascripts/issue_templates.js
@@ -136,6 +136,16 @@ ISSUE_TEMPLATE.prototype = {
if ($('#original_subject').text().length > 0 || $('#original_description').text().length > 0) {
$('#revert_template').removeClass('disabled');
}
+
+ if (obj.related_link !== '') {
+ let related_link = $('#issue_template_related_link');
+ related_link.attr('href', obj.related_link);
+ related_link.css('display', 'inline');
+ related_link.text(obj.link_title);
+ } else {
+ let related_link = $('#issue_template_related_link');
+ related_link.css('display', 'none');
+ }
}
}
});
From b1b8270c0a8b07c725bbe7ccecb4a927cb9d8b5d Mon Sep 17 00:00:00 2001
From: Akiko Takano
Date: Fri, 3 Jan 2020 14:35:12 +0900
Subject: [PATCH 07/30] Update test code.
---
.../global_issue_templates_controller_spec.rb | 35 ++++++++++++++++---
.../issue_templates_controller_spec.rb | 4 +--
spec/features/issue_template_popup_spec.rb | 10 +++++-
3 files changed, 42 insertions(+), 7 deletions(-)
diff --git a/spec/controllers/global_issue_templates_controller_spec.rb b/spec/controllers/global_issue_templates_controller_spec.rb
index 97937560..35321119 100644
--- a/spec/controllers/global_issue_templates_controller_spec.rb
+++ b/spec/controllers/global_issue_templates_controller_spec.rb
@@ -74,12 +74,39 @@
context 'POST with invalid url' do
let(:project_ids) { [] }
- include_examples 'Right response', 302
- before do
- create_params.merge!(related_link: 'bad format url')
+ let(:create_params) do
+ { global_issue_template:
+ { title: 'Global Template newtitle for creation test',
+ note: 'Global note for creation test',
+ description: 'Global Template description for creation test',
+ tracker_id: tracker.id,
+ enabled: 1,
+ author_id: user.id,
+ project_ids: project_ids }.merge(related_link: 'bad format url') }
end
+
+ include_examples 'Right response', 200
it do
- expect(global_issue_template.present?).to be_truthy
+ expect(global_issue_template.present?).to be_falsy
+ end
+
+ context 'POST with valid url' do
+ let(:project_ids) { [] }
+ let(:create_params) do
+ { global_issue_template:
+ { title: 'Global Template newtitle for creation test',
+ note: 'Global note for creation test',
+ description: 'Global Template description for creation test',
+ tracker_id: tracker.id,
+ enabled: 1,
+ author_id: user.id,
+ project_ids: project_ids }.merge(related_link: 'http://example.com/sample/index.html') }
+ end
+
+ include_examples 'Right response', 302
+ it do
+ expect(global_issue_template.present?).to be_truthy
+ end
end
end
end
diff --git a/spec/controllers/issue_templates_controller_spec.rb b/spec/controllers/issue_templates_controller_spec.rb
index 4ed05a4b..e7b05a21 100644
--- a/spec/controllers/issue_templates_controller_spec.rb
+++ b/spec/controllers/issue_templates_controller_spec.rb
@@ -137,10 +137,10 @@
include_examples 'Right response', 200
#
# TODO: This example should be request spec.
- #it 'Render new form filled with copied template values' do
+ # it 'Render new form filled with copied template values' do
# issue_template = assigns(:issue_template)
# expect(issue_template.id).to be_nil
# expect(issue_template.title).to eq "copy_of_#{original_template.title}"
- #end
+ # end
end
end
diff --git a/spec/features/issue_template_popup_spec.rb b/spec/features/issue_template_popup_spec.rb
index 17561db6..9c0c5627 100644
--- a/spec/features/issue_template_popup_spec.rb
+++ b/spec/features/issue_template_popup_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require_relative '../spec_helper'
require_relative '../rails_helper'
require_relative '../support/login_helper'
@@ -26,8 +28,11 @@
given(:first_template) { IssueTemplate.first }
given(:second_template) { IssueTemplate.second }
+ given(:related_link) { page.find('#issue_template_related_link') }
+
background do
- FactoryBot.create_list(:issue_template, 2, project_id: project.id, tracker_id: tracker.id)
+ FactoryBot.create_list(:issue_template, 2, project_id: project.id, tracker_id: tracker.id,
+ related_link: 'http://example.com/template/wiki#usage')
project.trackers << tracker
assign_template_priv(role, add_permission: :show_issue_templates)
@@ -50,6 +55,9 @@
expect(issue_description.value).not_to eq ''
expect(issue_description.value).to eq first_template.description
expect(issue_subject.value).to eq first_template.issue_title
+
+ expect(related_link.text).to eq 'Related Link'
+ expect(related_link['href']).to eq 'http://example.com/template/wiki#usage'
end
context 'Has default template' do
From 4dc1db68deb6f00043072200d3af92a2f0d33e6d Mon Sep 17 00:00:00 2001
From: Akiko Takano
Date: Fri, 3 Jan 2020 21:48:32 +0900
Subject: [PATCH 08/30] Add migration: ready for supporting built-in fields.
---
...3213630_add_builtin_fields_json_to_issue_templates.rb | 9 +++++++++
1 file changed, 9 insertions(+)
create mode 100644 db/migrate/20200103213630_add_builtin_fields_json_to_issue_templates.rb
diff --git a/db/migrate/20200103213630_add_builtin_fields_json_to_issue_templates.rb b/db/migrate/20200103213630_add_builtin_fields_json_to_issue_templates.rb
new file mode 100644
index 00000000..b224ec69
--- /dev/null
+++ b/db/migrate/20200103213630_add_builtin_fields_json_to_issue_templates.rb
@@ -0,0 +1,9 @@
+class AddBuiltinFieldsJsonToIssueTemplates < ActiveRecord::Migration[5.2]
+ def self.up
+ add_column :issue_templates, :builtin_fields_json, :text
+ end
+
+ def self.down
+ remove_column :issue_templates, :builtin_fields_json
+ end
+end
From 44c467fd510ae7160de193e2084fa98e30631a49 Mon Sep 17 00:00:00 2001
From: Akiko Takano
Date: Sat, 4 Jan 2020 23:16:33 +0900
Subject: [PATCH 09/30] Enabled to store values through serialize.
---
app/models/concerns/issue_template/common.rb | 2 +
assets/javascripts/issue_templates.js | 712 ++++++++++---------
2 files changed, 366 insertions(+), 348 deletions(-)
diff --git a/app/models/concerns/issue_template/common.rb b/app/models/concerns/issue_template/common.rb
index d8605e0f..ab501372 100644
--- a/app/models/concerns/issue_template/common.rb
+++ b/app/models/concerns/issue_template/common.rb
@@ -42,6 +42,8 @@ module Common
after_destroy do |template|
logger.info("[Destroy] #{self.class}: #{template.inspect}")
end
+
+ serialize :builtin_fields_json, Hash
end
#
diff --git a/assets/javascripts/issue_templates.js b/assets/javascripts/issue_templates.js
index c2a2a889..507d0454 100644
--- a/assets/javascripts/issue_templates.js
+++ b/assets/javascripts/issue_templates.js
@@ -4,386 +4,402 @@
*/
// For namespace setting.
-var ISSUE_TEMPLATE = ISSUE_TEMPLATE || function () {};
+var ISSUE_TEMPLATE = ISSUE_TEMPLATE || function () {}
ISSUE_TEMPLATE.prototype = {
- eraseSubjectAndDescription: function () {
- $('#issue_description').val('');
- $('#issue_subject').val('');
-
- try {
- if (CKEDITOR.instances.issue_description)
- CKEDITOR.instances.issue_description.setData('');
- } catch (e) {
- // do nothing.
- }
- },
- openDialog: function (url, title) {
- // Open dialog (modal window) to display selectable templates list.
- $.ajax({
- url: url,
- success: function (data) {
- $("#filtered_templates_list").html(data);
- $("#issue_template_dialog").dialog({
- modal: true,
- dialogClass: "modal overflow_dialog",
- draggable: true,
- title: title,
- minWidth: 400,
- width: 'auto',
- maxWidth: 'auto'
- });
- }
+ eraseSubjectAndDescription: function () {
+ $('#issue_description').val('')
+ $('#issue_subject').val('')
+
+ try {
+ if (CKEDITOR.instances.issue_description)
+ CKEDITOR.instances.issue_description.setData('')
+ } catch (e) {
+ // do nothing.
+ }
+ },
+ openDialog: function (url, title) {
+ // Open dialog (modal window) to display selectable templates list.
+ $.ajax({
+ url: url,
+ success: function (data) {
+ $("#filtered_templates_list").html(data);
+ $("#issue_template_dialog").dialog({
+ modal: true,
+ dialogClass: "modal overflow_dialog",
+ draggable: true,
+ title: title,
+ minWidth: 400,
+ width: 'auto',
+ maxWidth: 'auto'
});
- },
- revertAppliedTemplate: function () {
+ }
+ });
+ },
+ revertAppliedTemplate: function () {
+ var issue_subject = $('#issue_subject');
+ var issue_description = $('#issue_description');
+ var old_subject = $('#original_subject');
+ var old_description = $('#original_description');
+ var templateNS = this;
+
+ issue_subject.val(templateNS.unescapeHTML(old_subject.text()));
+ issue_description.val(templateNS.unescapeHTML(old_description.text()));
+
+ try {
+ if (CKEDITOR.instances.issue_description)
+ CKEDITOR.instances.issue_description.setData(templateNS.unescapeHTML(old_description.text()));
+ } catch (e) {
+ // do nothing.
+ }
+ old_description.text = '';
+ old_description.text = '';
+ $('#revert_template').addClass('disabled');
+ },
+ load_template: function (target_url, confirm_msg, should_replaced,
+ confirm_to_replace, confirmation, general_text_Yes, general_text_No) {
+ var selected_template = $('#issue_template');
+ var ns = this;
+ if (selected_template.val() !== '') {
+ var template_type = '';
+ if (selected_template.find('option:selected').hasClass('global')) {
+ template_type = 'global';
+ }
+ $.ajax({
+ url: target_url,
+ async: true,
+ type: 'post',
+ data: $.param({
+ template_id: selected_template.val(),
+ template_type: template_type
+ })
+ }).done(function (data) {
+ // NOTE: Workaround for GiHub Issue, to prevent overwrite with default template
+ // when operator submits new issue form without required field and returns
+ // with error message. If flash message #errorExplanation exists, not overwrited.
+ // (https://github.com/akiko-pusu/redmine_issue_templates/issues/50)
+ if ($('#errorExplanation')[0]) return;
+
+ var oldSubj = '';
+ var oldVal = '';
var issue_subject = $('#issue_subject');
var issue_description = $('#issue_description');
- var old_subject = $('#original_subject');
- var old_description = $('#original_description');
- var templateNS = this;
-
- issue_subject.val(templateNS.unescapeHTML(old_subject.text()));
- issue_description.val(templateNS.unescapeHTML(old_description.text()));
-
- try {
- if (CKEDITOR.instances.issue_description)
- CKEDITOR.instances.issue_description.setData(templateNS.unescapeHTML(old_description.text()));
- } catch (e) {
- // do nothing.
+
+ var template = JSON.parse(data);
+
+ if (issue_description.val() !== '' && should_replaced === 'false') {
+ oldVal = issue_description.val() + '\n\n';
}
- old_description.text = '';
- old_description.text = '';
- $('#revert_template').addClass('disabled');
- },
- load_template: function (target_url, confirm_msg, should_replaced,
- confirm_to_replace, confirmation, general_text_Yes, general_text_No) {
- var selected_template = $('#issue_template');
- var ns = this;
- if (selected_template.val() !== '') {
- var template_type = '';
- if (selected_template.find('option:selected').hasClass('global')) {
- template_type = 'global';
- }
- $.ajax({
- url: target_url,
- async: true,
- type: 'post',
- data: $.param({
- template_id: selected_template.val(),
- template_type: template_type
- })
- }).done(function (data) {
- // NOTE: Workaround for GiHub Issue, to prevent overwrite with default template
- // when operator submits new issue form without required field and returns
- // with error message. If flash message #errorExplanation exists, not overwrited.
- // (https://github.com/akiko-pusu/redmine_issue_templates/issues/50)
- if ($('#errorExplanation')[0]) return;
-
- var oldSubj = '';
- var oldVal = '';
- var issue_subject = $('#issue_subject');
- var issue_description = $('#issue_description');
-
- var template = JSON.parse(data);
-
- if (issue_description.val() !== '' && should_replaced === 'false') {
- oldVal = issue_description.val() + '\n\n';
- }
- if (issue_subject.val() !== '' && should_replaced === 'false') {
- oldSubj = issue_subject.val() + ' ';
- }
- $('#original_subject').text(ns.escapeHTML(issue_subject.val()));
- $('#original_description').text(ns.escapeHTML(issue_description.val()));
-
- for (var issue_template in template) {
- if ({}.hasOwnProperty.call(template, issue_template)) {
-
- var obj = template[issue_template];
- obj.description = (obj.description === null) ? '' : obj.description;
- obj.issue_title = (obj.issue_title === null) ? '' : obj.issue_title;
-
- if (confirm_to_replace !== true && should_replaced === 'true' && (issue_description.val() !== '' || issue_subject.val() !== '')) {
- if (oldVal !== obj.description || oldSubj !== obj.issue_title) {
- var hide_confirm_flag = ns.hideOverwiteConfirm();
- if (hide_confirm_flag == false) {
- ns.confirmToReplace(target_url, confirm_msg, should_replaced, confirmation, general_text_Yes, general_text_No);
- return;
- }
- }
- }
-
- issue_description.attr('original_description', $('
').text(issue_description.val()).html());
- issue_subject.attr('original_title', $('
').text(issue_subject.val()).html());
-
- if (oldVal.replace(/(?:\r\n|\r|\n)/g, '').trim() != obj.description.replace(/(?:\r\n|\r|\n)/g, '').trim())
- issue_description.val(oldVal + obj.description);
- if (oldSubj.trim() != obj.issue_title.trim())
- issue_subject.val(oldSubj + obj.issue_title);
-
- try {
- if (CKEDITOR.instances.issue_description)
- CKEDITOR.instances.issue_description.setData(oldVal + template[issue_template].description);
- } catch (e) {
- // do nothing.
- }
- // show message just after default template loaded.
- if (confirm_msg)
- ns.show_loaded_message(confirm_msg, issue_description);
- ns.addCheckList(obj);
-
- if ($('#original_subject').text().length > 0 || $('#original_description').text().length > 0) {
- $('#revert_template').removeClass('disabled');
- }
-
- if (obj.related_link !== '') {
- let related_link = $('#issue_template_related_link');
- related_link.attr('href', obj.related_link);
- related_link.css('display', 'inline');
- related_link.text(obj.link_title);
- } else {
- let related_link = $('#issue_template_related_link');
- related_link.css('display', 'none');
- }
- }
- }
- });
+ if (issue_subject.val() !== '' && should_replaced === 'false') {
+ oldSubj = issue_subject.val() + ' ';
}
- },
- confirmToReplace: function (target_url, confirm_msg, should_replaced,
- confirmation, general_text_Yes, general_text_No) {
- var ns = this;
- $("#issue_template_confirm_to_replace_dialog").dialog({
- modal: true,
- dialogClass: "modal overflow_dialog",
- draggable: true,
- title: confirmation,
- width: 400,
- buttons: [{
- text: general_text_Yes,
- click: function () {
- $(this).dialog("close");
- ns.load_template(target_url, confirm_msg, should_replaced, true, confirmation, general_text_Yes, general_text_No)
- }
- },
- {
- text: general_text_No,
- click: function () {
- $(this).dialog("close");
- }
+ $('#original_subject').text(ns.escapeHTML(issue_subject.val()));
+ $('#original_description').text(ns.escapeHTML(issue_description.val()));
+
+ for (var issue_template in template) {
+ if ({}.hasOwnProperty.call(template, issue_template)) {
+
+ var obj = template[issue_template];
+ obj.description = (obj.description === null) ? '' : obj.description;
+ obj.issue_title = (obj.issue_title === null) ? '' : obj.issue_title;
+
+ if (confirm_to_replace !== true && should_replaced === 'true' && (issue_description.val() !== '' || issue_subject.val() !== '')) {
+ if (oldVal !== obj.description || oldSubj !== obj.issue_title) {
+ var hide_confirm_flag = ns.hideOverwiteConfirm();
+ if (hide_confirm_flag == false) {
+ ns.confirmToReplace(target_url, confirm_msg, should_replaced, confirmation, general_text_Yes, general_text_No);
+ return;
}
- ]
+ }
+ }
+
+ issue_description.attr('original_description', $('
').text(issue_description.val()).html());
+ issue_subject.attr('original_title', $('
').text(issue_subject.val()).html());
+
+ if (oldVal.replace(/(?:\r\n|\r|\n)/g, '').trim() != obj.description.replace(/(?:\r\n|\r|\n)/g, '').trim())
+ issue_description.val(oldVal + obj.description);
+ if (oldSubj.trim() != obj.issue_title.trim())
+ issue_subject.val(oldSubj + obj.issue_title);
+
+ try {
+ if (CKEDITOR.instances.issue_description)
+ CKEDITOR.instances.issue_description.setData(oldVal + template[issue_template].description);
+ } catch (e) {
+ // do nothing.
+ }
+ // show message just after default template loaded.
+ if (confirm_msg)
+ ns.show_loaded_message(confirm_msg, issue_description);
+ ns.addCheckList(obj);
+
+ if ($('#original_subject').text().length > 0 || $('#original_description').text().length > 0) {
+ $('#revert_template').removeClass('disabled');
+ }
+
+ if (obj.related_link !== '') {
+ let related_link = $('#issue_template_related_link');
+ related_link.attr('href', obj.related_link);
+ related_link.css('display', 'inline');
+ related_link.text(obj.link_title);
+ } else {
+ let related_link = $('#issue_template_related_link');
+ related_link.css('display', 'none');
+ }
+
+ ns.builtin_fields(obj)
+ }
+ }
+ });
+ }
+ },
+ confirmToReplace: function (target_url, confirm_msg, should_replaced,
+ confirmation, general_text_Yes, general_text_No) {
+ var ns = this;
+ $("#issue_template_confirm_to_replace_dialog").dialog({
+ modal: true,
+ dialogClass: "modal overflow_dialog",
+ draggable: true,
+ title: confirmation,
+ width: 400,
+ buttons: [{
+ text: general_text_Yes,
+ click: function () {
+ $(this).dialog("close");
+ ns.load_template(target_url, confirm_msg, should_replaced, true, confirmation, general_text_Yes, general_text_No)
+ }
+ },
+ {
+ text: general_text_No,
+ click: function () {
+ $(this).dialog("close");
+ }
+ }
+ ]
+ });
+ },
+ show_loaded_message: function (confirm_msg, target) {
+ var template_status_area = $('#template_status-area');
+ template_status_area.insertBefore(target);
+ template_status_area.issueTemplate('flash_message', {
+ text: confirm_msg,
+ how: 'append'
+ });
+ },
+ set_pulldown: function (tracker, target_url) {
+ var allow_overwrite = $('#allow_overwrite_description').prop('checked');
+ $.ajax({
+ url: target_url,
+ async: true,
+ type: 'post',
+ data: $.param({
+ issue_tracker_id: tracker
+ })
+ }).done(function (data) {
+ $('#issue_template').html(data);
+ $('#allow_overwrite_description').attr('checked', allow_overwrite);
+ });
+ },
+ addCheckList: function (obj) {
+ var list = obj.checklist;
+ if (list === undefined) return false;
+ if ($('#checklist_form').length === 0) return;
+
+ // remove exists checklist items
+ var oldList = $('span.checklist-item.show:visible span.checklist-show-only.checklist-remove > a.icon.icon-del');
+ oldList.each(function () {
+ oldList.click();
+ });
+
+ for (var i = 0; i < list.length; i++) {
+ $('span.checklist-new.checklist-edit-box > input.edit-box').val(list[i]);
+ $("span.checklist-item.new > span.icon.icon-add.save-new-by-button").click();
+ }
+ },
+ escapeHTML: function (val) {
+ return $('').text(val).html();
+ },
+ unescapeHTML: function (val) {
+ return $('
').html(val).text();
+ },
+ replaceCkeContent: function () {
+ return CKEDITOR.instances.issue_description.setData($('#issue_description').val());
+ },
+ hideOverwiteConfirm: function () {
+ var cookie_array = [];
+ if (document.cookie != '') {
+ var tmp = document.cookie.split('; ');
+ for (var i = 0; i < tmp.length; i++) {
+ var data = tmp[i].split('=');
+ cookie_array[data[0]] = decodeURIComponent(data[1]);
+ }
+ }
+ var confirmation_cookie = cookie_array['issue_template_confirm_to_replace_hide_dialog'];
+ if (confirmation_cookie == undefined || parseInt(confirmation_cookie) == 0) {
+ return false;
+ }
+ return true;
+ },
+ // support built-in field update
+ builtin_fields: function (issue_template) {
+ let builtin_fields_json = issue_template.builtin_fields_json
+ if (builtin_fields_json === undefined) return false
+ Object.keys(builtin_fields_json).forEach(function (key) {
+ let value = builtin_fields_json[key]
+ let element = $('#' + key)
+ if (element.prop('tagName').toLowerCase() === 'select') {
+ $('#' + key + ' option:contains(' + value + ')').attr('selected', 'selected')
+ } else {
+ element.val(value)
+ }
+ })
+ }
+};
+
+// jQuery plugin for issue template
+(function ($) {
+ var methods = {
+ init: function (options) {},
+ updateTemplateSelect: function (options) {
+ options = $.extend({
+ target: '#issue_template',
+ template_id: 'data-issue-template-id'
+ }, options);
+ return $(this).each(function () {
+ $(this).click(function () {
+ var obj = $(options.target);
+ var id = $(this).attr(options.template_id);
+ obj.attr("selected", false);
+ // has template-global class?
+ if ($(this).hasClass('template-global')) {
+ obj.find('option[value="' + id + '"][class="global"]').prop('selected', true);
+ } else {
+ obj.val(id);
+ }
+ obj.trigger('change');
});
+ });
},
- show_loaded_message: function (confirm_msg, target) {
- var template_status_area = $('#template_status-area');
- template_status_area.insertBefore(target);
- template_status_area.issueTemplate('flash_message', {
- text: confirm_msg,
- how: 'append'
+ displayTooltip: function (options) {
+ options = $.extend({
+ tooltip_body_id: 'data-tooltip-content',
+ tooltip_target_id: 'data-tooltip-area'
+ }, options);
+ return $(this).each(function () {
+ $(this).hover(function () {
+ var content = $(this).attr(options.tooltip_body_id);
+ var target = $(this).attr(options.tooltip_target_id);
+ var obj = $(content);
+ if (obj.length)
+ $(target).html(obj);
+ obj.toggle();
});
+ });
},
- set_pulldown: function (tracker, target_url) {
- var allow_overwrite = $('#allow_overwrite_description').prop('checked');
- $.ajax({
- url: target_url,
- async: true,
- type: 'post',
- data: $.param({
- issue_tracker_id: tracker
- })
- }).done(function (data) {
- $('#issue_template').html(data);
- $('#allow_overwrite_description').attr('checked', allow_overwrite);
+ expandHelp: function (options) {
+ options = $.extend({
+ attr_name: 'data-template-help-target'
+ }, options);
+ return $(this).each(function () {
+ $(this).click(function () {
+ var target = $(this).attr(options.attr_name);
+ var obj = $(target);
+ if (obj.length)
+ obj.toggle();
});
+ });
},
- addCheckList: function (obj) {
- var list = obj.checklist;
- if (list === undefined) return false;
- if ($('#checklist_form').length === 0) return;
-
- // remove exists checklist items
- var oldList = $('span.checklist-item.show:visible span.checklist-show-only.checklist-remove > a.icon.icon-del');
- oldList.each(function () {
- oldList.click();
+ flash_message: function (options) {
+ // default
+ options = $.extend({
+ text: 'Done',
+ time: 3000,
+ how: 'before',
+ class_name: ''
+ }, options);
+
+ return $(this).each(function () {
+ if ($(this).parent().find('.flash_message').get(0)) return;
+
+ var message = $('
', {
+ 'class': 'flash_message ' + options.class_name,
+ html: options.text
+ // display with fade in
+ }).hide().fadeIn('fast');
+
+ $(this)[options.how](message);
+ //delay and fadeout
+ message.delay(options.time).fadeOut('normal', function () {
+ $(this).remove();
});
- for (var i = 0; i < list.length; i++) {
- $('span.checklist-new.checklist-edit-box > input.edit-box').val(list[i]);
- $("span.checklist-item.new > span.icon.icon-add.save-new-by-button").click();
- }
- },
- escapeHTML: function (val) {
- return $('
').text(val).html();
- },
- unescapeHTML: function (val) {
- return $('
').html(val).text();
- },
- replaceCkeContent: function () {
- return CKEDITOR.instances.issue_description.setData($('#issue_description').val());
+ });
},
- hideOverwiteConfirm: function () {
- var cookie_array = [];
- if (document.cookie != '') {
- var tmp = document.cookie.split('; ');
- for (var i = 0; i < tmp.length; i++) {
- var data = tmp[i].split('=');
- cookie_array[data[0]] = decodeURIComponent(data[1]);
- }
- }
- var confirmation_cookie = cookie_array['issue_template_confirm_to_replace_hide_dialog'];
- if (confirmation_cookie == undefined || parseInt(confirmation_cookie) == 0) {
+ disabled_link: function (options) {
+ options = $.extend({}, options);
+ return $(this).each(function () {
+ $(this).click(function (event) {
+ title = event.target.title;
+ if (title.length && event.target.hasAttribute('disabled')) {
+ event.stopPropagation();
+ alert(title);
return false;
- }
- return true;
+ }
+ });
+ });
}
-};
+ };
-// jQuery plugin for issue template
-(function ($) {
- var methods = {
- init: function (options) {},
- updateTemplateSelect: function (options) {
- options = $.extend({
- target: '#issue_template',
- template_id: 'data-issue-template-id'
- }, options);
- return $(this).each(function () {
- $(this).click(function () {
- var obj = $(options.target);
- var id = $(this).attr(options.template_id);
- obj.attr("selected", false);
- // has template-global class?
- if ($(this).hasClass('template-global')) {
- obj.find('option[value="' + id + '"][class="global"]').prop('selected', true);
- } else {
- obj.val(id);
- }
- obj.trigger('change');
- });
- });
- },
- displayTooltip: function (options) {
- options = $.extend({
- tooltip_body_id: 'data-tooltip-content',
- tooltip_target_id: 'data-tooltip-area'
- }, options);
- return $(this).each(function () {
- $(this).hover(function () {
- var content = $(this).attr(options.tooltip_body_id);
- var target = $(this).attr(options.tooltip_target_id);
- var obj = $(content);
- if (obj.length)
- $(target).html(obj);
- obj.toggle();
- });
- });
- },
- expandHelp: function (options) {
- options = $.extend({
- attr_name: 'data-template-help-target'
- }, options);
- return $(this).each(function () {
- $(this).click(function () {
- var target = $(this).attr(options.attr_name);
- var obj = $(target);
- if (obj.length)
- obj.toggle();
- });
- });
- },
- flash_message: function (options) {
- // default
- options = $.extend({
- text: 'Done',
- time: 3000,
- how: 'before',
- class_name: ''
- }, options);
-
- return $(this).each(function () {
- if ($(this).parent().find('.flash_message').get(0)) return;
-
- var message = $('
', {
- 'class': 'flash_message ' + options.class_name,
- html: options.text
- // display with fade in
- }).hide().fadeIn('fast');
-
- $(this)[options.how](message);
- //delay and fadeout
- message.delay(options.time).fadeOut('normal', function () {
- $(this).remove();
- });
-
- });
- },
- disabled_link: function (options) {
- options = $.extend({}, options);
- return $(this).each(function () {
- $(this).click(function (event) {
- title = event.target.title;
- if (title.length && event.target.hasAttribute('disabled')) {
- event.stopPropagation();
- alert(title);
- return false;
- }
- });
- });
- }
- };
+ $.fn.issueTemplate = function (method) {
- $.fn.issueTemplate = function (method) {
-
- // Method dispatch logic
- if (methods[method]) {
- return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
- } else if (typeof method === 'object' || !method) {
- return methods.init.apply(this, arguments);
- } else {
- $.error('Method ' + method + ' does not exist on jQuery.issueTemplate');
- }
- };
+ // Method dispatch logic
+ if (methods[method]) {
+ return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
+ } else if (typeof method === 'object' || !method) {
+ return methods.init.apply(this, arguments);
+ } else {
+ $.error('Method ' + method + ' does not exist on jQuery.issueTemplate');
+ }
+ };
})(jQuery);
$(function () {
- // set plugin
- $('a.template-help').issueTemplate('displayTooltip');
- $('a.template-help.collapsible').issueTemplate('expandHelp');
- $('a.template-help.collapsible').click(function () {
- $(this).toggleClass('collapsed');
- });
-
- $('a.template-disabled-link').issueTemplate('disabled_link');
-
- // display orphaned template list
- $('#orphaned_template_link').on({
- 'ajax:success': (function (_this) {
- return function (e, data) {
- $('#orphaned_templates').toggle();
- return $('#orphaned_templates').html(data);
- };
- })(this)
- });
+ // set plugin
+ $('a.template-help').issueTemplate('displayTooltip');
+ $('a.template-help.collapsible').issueTemplate('expandHelp');
+ $('a.template-help.collapsible').click(function () {
+ $(this).toggleClass('collapsed');
+ });
+
+ $('a.template-disabled-link').issueTemplate('disabled_link');
+
+ // display orphaned template list
+ $('#orphaned_template_link').on({
+ 'ajax:success': (function (_this) {
+ return function (e, data) {
+ $('#orphaned_templates').toggle();
+ return $('#orphaned_templates').html(data);
+ };
+ })(this)
+ });
});
// for IE11 compatibility (IE11 does not support native Element.closest)
// Ref. https://developer.mozilla.org/en-US/docs/Web/API/Element/closest#Polyfill
// Ref. https://github.com/akiko-pusu/redmine_issue_templates/issues/270
if (!Element.prototype.matches) {
- Element.prototype.matches = Element.prototype.msMatchesSelector ||
- Element.prototype.webkitMatchesSelector;
+ Element.prototype.matches = Element.prototype.msMatchesSelector ||
+ Element.prototype.webkitMatchesSelector;
}
if (!Element.prototype.closest) {
- Element.prototype.closest = function(s) {
- var el = this;
-
- do {
- if (el.matches(s)) return el;
- el = el.parentElement || el.parentNode;
- } while (el !== null && el.nodeType === 1);
- return null;
- };
+ Element.prototype.closest = function(s) {
+ var el = this;
+
+ do {
+ if (el.matches(s)) return el;
+ el = el.parentElement || el.parentNode;
+ } while (el !== null && el.nodeType === 1);
+ return null;
+ };
}
From 8ddb018b474fba5f7556020fd66a4d494a9876ad Mon Sep 17 00:00:00 2001
From: Akiko Takano
Date: Sun, 5 Jan 2020 09:57:08 +0900
Subject: [PATCH 10/30] Change not to use jQuery but to use ES6.
---
app/views/common/_nodata.html.erb | 2 +-
app/views/common/_orphaned.html.erb | 20 +-
app/views/common/_template_links.html.erb | 10 +-
.../global_issue_templates/_form.html.erb | 197 ++++----
.../global_issue_templates/index.html.erb | 38 +-
app/views/global_issue_templates/new.html.erb | 4 +-
.../global_issue_templates/show.html.erb | 6 +-
app/views/issue_templates/_form.html.erb | 186 ++++---
.../_issue_select_form.html.erb | 246 ++++-----
.../issue_templates/_list_templates.api.rsb | 2 +-
.../issue_templates/_list_templates.html.erb | 56 +-
app/views/issue_templates/_note_form.html.erb | 104 ++--
.../_template_pulldown.html.erb | 52 +-
app/views/issue_templates/index.html.erb | 90 ++--
app/views/issue_templates/new.html.erb | 10 +-
app/views/issue_templates/show.html.erb | 32 +-
.../issue_templates_settings/index.html.erb | 34 +-
app/views/note_templates/_form.html.erb | 48 +-
.../_list_note_templates.html.erb | 21 +-
app/views/note_templates/index.html.erb | 40 +-
app/views/note_templates/new.html.erb | 8 +-
app/views/note_templates/show.html.erb | 28 +-
.../_redmine_issue_templates.html.erb | 22 +-
assets/javascripts/issue_templates.js | 478 +++++++++---------
assets/stylesheets/issue_templates.css | 4 +
spec/features/issue_template_spec.rb | 6 +-
26 files changed, 914 insertions(+), 830 deletions(-)
diff --git a/app/views/common/_nodata.html.erb b/app/views/common/_nodata.html.erb
index e0e0316b..eaaa378a 100644
--- a/app/views/common/_nodata.html.erb
+++ b/app/views/common/_nodata.html.erb
@@ -1,5 +1,5 @@
<% if trackers.blank? %>
-
+
<%= simple_format(l(:text_no_tracker_enabled)) %>
<% end %>
\ No newline at end of file
diff --git a/app/views/common/_orphaned.html.erb b/app/views/common/_orphaned.html.erb
index 68645a85..675ffc34 100644
--- a/app/views/common/_orphaned.html.erb
+++ b/app/views/common/_orphaned.html.erb
@@ -1,5 +1,5 @@
<%= l(:orphaned_template) %>
-
+
#
@@ -12,7 +12,7 @@
<% orphaned_templates.each do |issue_template| %>
-
+ issue_template issue'>
<%= link_to h(issue_template.id),
{ controller: controller.controller_name, action: 'show',
@@ -27,21 +27,21 @@
{ title: "#{html_escape(issue_template.note) }"} %>
-
<%= "ID: #{issue_template.tracker_id}" %>
<%=h issue_template.author %>
- <%= format_time(issue_template.updated_on)%>
+ <%= format_time(issue_template.updated_on) %>
-
-
- <%= textilizable(issue_template.description) %>
+
+
+ <%= textilizable(issue_template.description) %>
<% end %>
diff --git a/app/views/common/_template_links.html.erb b/app/views/common/_template_links.html.erb
index bb679bb0..b93373df 100644
--- a/app/views/common/_template_links.html.erb
+++ b/app/views/common/_template_links.html.erb
@@ -1,6 +1,6 @@
-
-
+
+
<%= l(:issue_template) %>:
<%= link_to(l(:label_list_templates),
{ controller: 'issue_templates',
@@ -10,7 +10,7 @@
{ controller: 'issue_templates', action: 'new', project_id: @project },
class: 'icon icon-add') %>
-
+
<%= l(:note_template) %>:
<%= link_to(l(:label_list_templates),
{ controller: 'note_templates',
@@ -21,7 +21,7 @@
class: 'icon icon-add') %>
-
+
<%= l(:issue_templates_optional_settings, default: 'Templates Optional Settings') %>:
<%= link_to_if_authorized(l(:label_settings, default: 'Settings'),
{ controller: 'issue_templates_settings', action: 'index', project_id: @project },
diff --git a/app/views/global_issue_templates/_form.html.erb b/app/views/global_issue_templates/_form.html.erb
index 789ad152..71e7673f 100644
--- a/app/views/global_issue_templates/_form.html.erb
+++ b/app/views/global_issue_templates/_form.html.erb
@@ -1,50 +1,50 @@
<%= error_messages_for 'global_issue_template' %>
-
+
<%= f.text_field :title, required: true, size: 80, label: l(:issue_template_name) %>
-
- <%= l(:label_applied_for_issue) %>
+
+ <%= l(:label_applied_for_issue) %>
<% if issue_template.tracker.blank? %>
- <%= f.select :tracker_id, trackers.collect { |t| [t.name, t.id] }, {required: true},
+ <%= f.select :tracker_id, trackers.collect { |t| [t.name, t.id] }, { required: true },
required: true, label: l(:label_tracker) %>
<%= h issue_template.tracker.present? ? issue_template.tracker.name :
l(:orphaned_template, default: 'Orphaned template from tracker') %>
<% else %>
- <%= f.select :tracker_id, trackers.collect { |t| [t.name, t.id] }, {required: true},
+ <%= f.select :tracker_id, trackers.collect { |t| [t.name, t.id] }, { required: true },
required: true, label: l(:label_tracker), selected: issue_template.tracker.id %>
<% end %>
<%= f.text_field :issue_title, required: false, size: 80, label: l(:issue_title) %>
-
+
<%= l(:help_for_this_field) %>
-
+
<%= f.text_area :description, cols: 78, rows: 12,
required: true,
- label: l(:issue_description), class: 'wiki-edit', style: 'overflow:auto;' %>
+ label: l(:issue_description), class: 'wiki-edit', style: 'overflow: auto;' %>
<% if checklist_enabled %>
-
+
Checklist
-
-
+
+
<% issue_template.checklist.each_with_index do |content, i| %>
-
-
+
+
<%= content %>
-
+
-
+
<% end %>
@@ -59,74 +59,74 @@
<%= f.text_field :related_link, type: 'url',
size: 70, label: l(:issue_template_related_link, default: 'Related link') %>
-
+
<%= l(:help_for_this_field) %>
-
+
<%= f.text_field :link_title, size: 70, label: l(:issue_template_link_title, default: 'Link title') %>
-
+
<%= l(:help_for_this_field) %>
-
+
<%= f.check_box :is_default, label: l(:field_is_default) %>
-
+
<%= l(:help_for_this_field) %>
-
+
<%= f.check_box :enabled, label: l(:label_enabled) %>
-
+
<%= l(:help_for_this_field) %>
-
+
<%= wikitoolbar_for 'global_issue_template_description' %>
-
+
-
+
<%= l(:help_for_issue_title) %>
-
+
<%= l(:label_isdefault_help_message) %>
-
+
<%= l(:label_related_link_help_message, default: 'If there are some example pages or sample issues which using issue template, please specify the link. So operator can see them as an usage or example for template.') %>
-
+
<%= l(:label_link_title_help_message, default: 'If there are some example pages or sample issues which using issue template, please specify the link. So operator can see them as an usage or example for template.') %>
-
+
<%= l(:label_enabled_help_message) %>
-
+
<% if apply_all_projects %>
-
-
+
+
<%= l(:note_apply_global_template_to_all_projects_setting_enabled) %>
(
@@ -136,12 +136,12 @@
<% end %>
<% if projects.any? %>
-
-
+ '>
+
<%= l(:project_list_associated_this_template, {applied: issue_template.projects.length, all: projects.length}) %>
-
+
<%= check_all_links 'global_issue_template_project_ids' %>
<%= l(:label_project_plural) %>
<%= render_project_nested_lists(projects) do |p|
@@ -158,51 +158,60 @@
<%= submit_tag l(issue_template.new_record? ? :button_create : :button_save) %>
-<%= link_to l(:button_cancel), {action: 'index'}, data: {confirm: l(:text_are_you_sure)} %>
+<%= link_to l(:button_cancel), { action: 'index' }, data: { confirm: l(:text_are_you_sure) } %>
+
+
diff --git a/app/views/global_issue_templates/index.html.erb b/app/views/global_issue_templates/index.html.erb
index 57d3a01e..b7b6a063 100644
--- a/app/views/global_issue_templates/index.html.erb
+++ b/app/views/global_issue_templates/index.html.erb
@@ -1,24 +1,24 @@
-
<%=h "#{l(:global_issue_templates)}" %>
-<%= render partial: "common/nodata", locals: { trackers: trackers } %>
-
+
<%=h "#{l(:global_issue_templates)}" %>
+<%= render partial: 'common/nodata', locals: { trackers: trackers } %>
+
<%= link_to(l(:label_new_templates),
{ controller: 'global_issue_templates', action: 'new' }, class: 'icon icon-add') %>
<%= link_to(l(:label_settings),
{ controller: 'settings', action: 'plugin', id: 'redmine_issue_templates' },
class: 'issue_template icon plugins') %>
-
+
<% if template_map.blank? %>
-
+
<%= l(:no_issue_templates_for_this_redmine) %>
<% end %>
<% template_map.each_key do |tracker| %>
-
-
<%= tracker.name %>
+
+
<%= tracker.name %>
-
+
#
@@ -34,10 +34,10 @@
<% template_map[tracker].sorted.each do |issue_template| %>
-
+ issue_template issue'>
<%= link_to h(issue_template.id), { controller: 'global_issue_templates',
id: issue_template.id, action: 'show' },
- { title: issue_template.title} %>
+ { title: issue_template.title } %>
<%= link_to h(issue_template.title), { controller: 'global_issue_templates',
@@ -45,10 +45,10 @@
{ title: "#{html_escape(issue_template.note)}" } %>
-