Merge branch 'szzh' of http://repository.trustie.net/xianbo/trustie2 into szzh
|
@ -13,3 +13,4 @@
|
||||||
/Gemfile.lock
|
/Gemfile.lock
|
||||||
/db/schema.rb
|
/db/schema.rb
|
||||||
/Gemfile.lock
|
/Gemfile.lock
|
||||||
|
/lib/plugins/acts_as_versioned/test/debug.log
|
||||||
|
|
|
@ -120,7 +120,7 @@ class AttachmentsController < ApplicationController
|
||||||
end
|
end
|
||||||
if @attachment.container
|
if @attachment.container
|
||||||
# Make sure association callbacks are called
|
# Make sure association callbacks are called
|
||||||
@attachment.container.attachments.delete(@attachment)
|
@attachment.container.def attachments.delete(@attachment)
|
||||||
else
|
else
|
||||||
@attachment.destroy
|
@attachment.destroy
|
||||||
end
|
end
|
||||||
|
|
|
@ -568,7 +568,7 @@ class RepositoriesController < ApplicationController
|
||||||
project = Project.find(params[:id])
|
project = Project.find(params[:id])
|
||||||
if !User.current.member_of?(project)
|
if !User.current.member_of?(project)
|
||||||
if project.hidden_repo
|
if project.hidden_repo
|
||||||
render_403
|
#render_403
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
rescue ActiveRecord::RecordNotFound
|
rescue ActiveRecord::RecordNotFound
|
||||||
|
|
52
db/schema.rb
|
@ -174,6 +174,58 @@ ActiveRecord::Schema.define(:version => 20140618020535) do
|
||||||
|
|
||||||
add_index "changesets_issues", ["changeset_id", "issue_id"], :name => "changesets_issues_ids", :unique => true
|
add_index "changesets_issues", ["changeset_id", "issue_id"], :name => "changesets_issues_ids", :unique => true
|
||||||
|
|
||||||
|
create_table "code_review_assignments", :force => true do |t|
|
||||||
|
t.integer "issue_id"
|
||||||
|
t.integer "change_id"
|
||||||
|
t.integer "attachment_id"
|
||||||
|
t.string "file_path"
|
||||||
|
t.string "rev"
|
||||||
|
t.string "rev_to"
|
||||||
|
t.string "action_type"
|
||||||
|
t.integer "changeset_id"
|
||||||
|
end
|
||||||
|
|
||||||
|
create_table "code_review_project_settings", :force => true do |t|
|
||||||
|
t.integer "project_id"
|
||||||
|
t.integer "tracker_id"
|
||||||
|
t.datetime "created_at"
|
||||||
|
t.datetime "updated_at"
|
||||||
|
t.integer "updated_by"
|
||||||
|
t.boolean "hide_code_review_tab", :default => false
|
||||||
|
t.integer "auto_relation", :default => 1
|
||||||
|
t.integer "assignment_tracker_id"
|
||||||
|
t.text "auto_assign"
|
||||||
|
t.integer "lock_version", :default => 0, :null => false
|
||||||
|
t.boolean "tracker_in_review_dialog", :default => false
|
||||||
|
end
|
||||||
|
|
||||||
|
create_table "code_review_user_settings", :force => true do |t|
|
||||||
|
t.integer "user_id", :default => 0, :null => false
|
||||||
|
t.integer "mail_notification", :default => 0, :null => false
|
||||||
|
t.datetime "created_at"
|
||||||
|
t.datetime "updated_at"
|
||||||
|
end
|
||||||
|
|
||||||
|
create_table "code_reviews", :force => true do |t|
|
||||||
|
t.integer "project_id"
|
||||||
|
t.integer "change_id"
|
||||||
|
t.datetime "created_at"
|
||||||
|
t.datetime "updated_at"
|
||||||
|
t.integer "line"
|
||||||
|
t.integer "updated_by_id"
|
||||||
|
t.integer "lock_version", :default => 0, :null => false
|
||||||
|
t.integer "status_changed_from"
|
||||||
|
t.integer "status_changed_to"
|
||||||
|
t.integer "issue_id"
|
||||||
|
t.string "action_type"
|
||||||
|
t.string "file_path"
|
||||||
|
t.string "rev"
|
||||||
|
t.string "rev_to"
|
||||||
|
t.integer "attachment_id"
|
||||||
|
t.integer "file_count", :default => 0, :null => false
|
||||||
|
t.boolean "diff_all"
|
||||||
|
end
|
||||||
|
|
||||||
create_table "comments", :force => true do |t|
|
create_table "comments", :force => true do |t|
|
||||||
t.string "commented_type", :limit => 30, :default => "", :null => false
|
t.string "commented_type", :limit => 30, :default => "", :null => false
|
||||||
t.integer "commented_id", :default => 0, :null => false
|
t.integer "commented_id", :default => 0, :null => false
|
||||||
|
|
|
@ -0,0 +1,136 @@
|
||||||
|
# Redmine - project management software
|
||||||
|
# Copyright (C) 2006-2014 Jean-Philippe Lang
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or
|
||||||
|
# modify it under the terms of the GNU General Public License
|
||||||
|
# as published by the Free Software Foundation; either version 2
|
||||||
|
# of the License, or (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program; if not, write to the Free Software
|
||||||
|
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
|
||||||
|
require 'cgi'
|
||||||
|
|
||||||
|
module Redmine
|
||||||
|
module WikiFormatting
|
||||||
|
module Markdown
|
||||||
|
class HTML < Redcarpet::Render::HTML
|
||||||
|
include ActionView::Helpers::TagHelper
|
||||||
|
|
||||||
|
def link(link, title, content)
|
||||||
|
css = nil
|
||||||
|
unless link && link.starts_with?('/')
|
||||||
|
css = 'external'
|
||||||
|
end
|
||||||
|
content_tag('a', content.html_safe, :href => link, :title => title, :class => css)
|
||||||
|
end
|
||||||
|
|
||||||
|
def block_code(code, language)
|
||||||
|
if language.present?
|
||||||
|
"<pre><code class=\"#{CGI.escapeHTML language} syntaxhl\">" +
|
||||||
|
Redmine::SyntaxHighlighting.highlight_by_language(code, language) +
|
||||||
|
"</code></pre>"
|
||||||
|
else
|
||||||
|
"<pre>" + CGI.escapeHTML(code) + "</pre>"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class Formatter
|
||||||
|
def initialize(text)
|
||||||
|
@text = text
|
||||||
|
end
|
||||||
|
|
||||||
|
def to_html(*args)
|
||||||
|
html = formatter.render(@text)
|
||||||
|
# restore wiki links eg. [[Foo]]
|
||||||
|
html.gsub!(%r{\[<a href="(.*?)">(.*?)</a>\]}) do
|
||||||
|
"[[#{$2}]]"
|
||||||
|
end
|
||||||
|
# restore Redmine links with double-quotes, eg. version:"1.0"
|
||||||
|
html.gsub!(/(\w):"(.+?)"/) do
|
||||||
|
"#{$1}:\"#{$2}\""
|
||||||
|
end
|
||||||
|
html
|
||||||
|
end
|
||||||
|
|
||||||
|
def get_section(index)
|
||||||
|
section = extract_sections(index)[1]
|
||||||
|
hash = Digest::MD5.hexdigest(section)
|
||||||
|
return section, hash
|
||||||
|
end
|
||||||
|
|
||||||
|
def update_section(index, update, hash=nil)
|
||||||
|
t = extract_sections(index)
|
||||||
|
if hash.present? && hash != Digest::MD5.hexdigest(t[1])
|
||||||
|
raise Redmine::WikiFormatting::StaleSectionError
|
||||||
|
end
|
||||||
|
t[1] = update unless t[1].blank?
|
||||||
|
t.reject(&:blank?).join "\n\n"
|
||||||
|
end
|
||||||
|
|
||||||
|
def extract_sections(index)
|
||||||
|
sections = ['', '', '']
|
||||||
|
offset = 0
|
||||||
|
i = 0
|
||||||
|
l = 1
|
||||||
|
inside_pre = false
|
||||||
|
@text.split(/(^(?:.+\r?\n\r?(?:\=+|\-+)|#+.+|~~~.*)\s*$)/).each do |part|
|
||||||
|
level = nil
|
||||||
|
if part =~ /\A~{3,}(\S+)?\s*$/
|
||||||
|
if $1
|
||||||
|
if !inside_pre
|
||||||
|
inside_pre = true
|
||||||
|
end
|
||||||
|
else
|
||||||
|
inside_pre = !inside_pre
|
||||||
|
end
|
||||||
|
elsif inside_pre
|
||||||
|
# nop
|
||||||
|
elsif part =~ /\A(#+).+/
|
||||||
|
level = $1.size
|
||||||
|
elsif part =~ /\A.+\r?\n\r?(\=+|\-+)\s*$/
|
||||||
|
level = $1.include?('=') ? 1 : 2
|
||||||
|
end
|
||||||
|
if level
|
||||||
|
i += 1
|
||||||
|
if offset == 0 && i == index
|
||||||
|
# entering the requested section
|
||||||
|
offset = 1
|
||||||
|
l = level
|
||||||
|
elsif offset == 1 && i > index && level <= l
|
||||||
|
# leaving the requested section
|
||||||
|
offset = 2
|
||||||
|
end
|
||||||
|
end
|
||||||
|
sections[offset] << part
|
||||||
|
end
|
||||||
|
sections.map(&:strip)
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def formatter
|
||||||
|
@@formatter ||= Redcarpet::Markdown.new(
|
||||||
|
Redmine::WikiFormatting::Markdown::HTML.new(
|
||||||
|
:filter_html => true,
|
||||||
|
:hard_wrap => true
|
||||||
|
),
|
||||||
|
:autolink => true,
|
||||||
|
:fenced_code_blocks => true,
|
||||||
|
:space_after_headers => true,
|
||||||
|
:tables => true,
|
||||||
|
:strikethrough => true,
|
||||||
|
:superscript => true
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,45 @@
|
||||||
|
# Redmine - project management software
|
||||||
|
# Copyright (C) 2006-2014 Jean-Philippe Lang
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or
|
||||||
|
# modify it under the terms of the GNU General Public License
|
||||||
|
# as published by the Free Software Foundation; either version 2
|
||||||
|
# of the License, or (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program; if not, write to the Free Software
|
||||||
|
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
|
||||||
|
module Redmine
|
||||||
|
module WikiFormatting
|
||||||
|
module Markdown
|
||||||
|
module Helper
|
||||||
|
def wikitoolbar_for(field_id)
|
||||||
|
heads_for_wiki_formatter
|
||||||
|
javascript_tag("var wikiToolbar = new jsToolBar(document.getElementById('#{field_id}')); wikiToolbar.draw();")
|
||||||
|
end
|
||||||
|
|
||||||
|
def initial_page_content(page)
|
||||||
|
"# #{@page.pretty_title}"
|
||||||
|
end
|
||||||
|
|
||||||
|
def heads_for_wiki_formatter
|
||||||
|
unless @heads_for_wiki_formatter_included
|
||||||
|
content_for :header_tags do
|
||||||
|
javascript_include_tag('jstoolbar/jstoolbar') +
|
||||||
|
javascript_include_tag('jstoolbar/markdown') +
|
||||||
|
javascript_include_tag("jstoolbar/lang/jstoolbar-#{current_language.to_s.downcase}") +
|
||||||
|
stylesheet_link_tag('jstoolbar')
|
||||||
|
end
|
||||||
|
@heads_for_wiki_formatter_included = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,339 @@
|
||||||
|
GNU GENERAL PUBLIC LICENSE
|
||||||
|
Version 2, June 1991
|
||||||
|
|
||||||
|
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
|
||||||
|
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
Everyone is permitted to copy and distribute verbatim copies
|
||||||
|
of this license document, but changing it is not allowed.
|
||||||
|
|
||||||
|
Preamble
|
||||||
|
|
||||||
|
The licenses for most software are designed to take away your
|
||||||
|
freedom to share and change it. By contrast, the GNU General Public
|
||||||
|
License is intended to guarantee your freedom to share and change free
|
||||||
|
software--to make sure the software is free for all its users. This
|
||||||
|
General Public License applies to most of the Free Software
|
||||||
|
Foundation's software and to any other program whose authors commit to
|
||||||
|
using it. (Some other Free Software Foundation software is covered by
|
||||||
|
the GNU Lesser General Public License instead.) You can apply it to
|
||||||
|
your programs, too.
|
||||||
|
|
||||||
|
When we speak of free software, we are referring to freedom, not
|
||||||
|
price. Our General Public Licenses are designed to make sure that you
|
||||||
|
have the freedom to distribute copies of free software (and charge for
|
||||||
|
this service if you wish), that you receive source code or can get it
|
||||||
|
if you want it, that you can change the software or use pieces of it
|
||||||
|
in new free programs; and that you know you can do these things.
|
||||||
|
|
||||||
|
To protect your rights, we need to make restrictions that forbid
|
||||||
|
anyone to deny you these rights or to ask you to surrender the rights.
|
||||||
|
These restrictions translate to certain responsibilities for you if you
|
||||||
|
distribute copies of the software, or if you modify it.
|
||||||
|
|
||||||
|
For example, if you distribute copies of such a program, whether
|
||||||
|
gratis or for a fee, you must give the recipients all the rights that
|
||||||
|
you have. You must make sure that they, too, receive or can get the
|
||||||
|
source code. And you must show them these terms so they know their
|
||||||
|
rights.
|
||||||
|
|
||||||
|
We protect your rights with two steps: (1) copyright the software, and
|
||||||
|
(2) offer you this license which gives you legal permission to copy,
|
||||||
|
distribute and/or modify the software.
|
||||||
|
|
||||||
|
Also, for each author's protection and ours, we want to make certain
|
||||||
|
that everyone understands that there is no warranty for this free
|
||||||
|
software. If the software is modified by someone else and passed on, we
|
||||||
|
want its recipients to know that what they have is not the original, so
|
||||||
|
that any problems introduced by others will not reflect on the original
|
||||||
|
authors' reputations.
|
||||||
|
|
||||||
|
Finally, any free program is threatened constantly by software
|
||||||
|
patents. We wish to avoid the danger that redistributors of a free
|
||||||
|
program will individually obtain patent licenses, in effect making the
|
||||||
|
program proprietary. To prevent this, we have made it clear that any
|
||||||
|
patent must be licensed for everyone's free use or not licensed at all.
|
||||||
|
|
||||||
|
The precise terms and conditions for copying, distribution and
|
||||||
|
modification follow.
|
||||||
|
|
||||||
|
GNU GENERAL PUBLIC LICENSE
|
||||||
|
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||||
|
|
||||||
|
0. This License applies to any program or other work which contains
|
||||||
|
a notice placed by the copyright holder saying it may be distributed
|
||||||
|
under the terms of this General Public License. The "Program", below,
|
||||||
|
refers to any such program or work, and a "work based on the Program"
|
||||||
|
means either the Program or any derivative work under copyright law:
|
||||||
|
that is to say, a work containing the Program or a portion of it,
|
||||||
|
either verbatim or with modifications and/or translated into another
|
||||||
|
language. (Hereinafter, translation is included without limitation in
|
||||||
|
the term "modification".) Each licensee is addressed as "you".
|
||||||
|
|
||||||
|
Activities other than copying, distribution and modification are not
|
||||||
|
covered by this License; they are outside its scope. The act of
|
||||||
|
running the Program is not restricted, and the output from the Program
|
||||||
|
is covered only if its contents constitute a work based on the
|
||||||
|
Program (independent of having been made by running the Program).
|
||||||
|
Whether that is true depends on what the Program does.
|
||||||
|
|
||||||
|
1. You may copy and distribute verbatim copies of the Program's
|
||||||
|
source code as you receive it, in any medium, provided that you
|
||||||
|
conspicuously and appropriately publish on each copy an appropriate
|
||||||
|
copyright notice and disclaimer of warranty; keep intact all the
|
||||||
|
notices that refer to this License and to the absence of any warranty;
|
||||||
|
and give any other recipients of the Program a copy of this License
|
||||||
|
along with the Program.
|
||||||
|
|
||||||
|
You may charge a fee for the physical act of transferring a copy, and
|
||||||
|
you may at your option offer warranty protection in exchange for a fee.
|
||||||
|
|
||||||
|
2. You may modify your copy or copies of the Program or any portion
|
||||||
|
of it, thus forming a work based on the Program, and copy and
|
||||||
|
distribute such modifications or work under the terms of Section 1
|
||||||
|
above, provided that you also meet all of these conditions:
|
||||||
|
|
||||||
|
a) You must cause the modified files to carry prominent notices
|
||||||
|
stating that you changed the files and the date of any change.
|
||||||
|
|
||||||
|
b) You must cause any work that you distribute or publish, that in
|
||||||
|
whole or in part contains or is derived from the Program or any
|
||||||
|
part thereof, to be licensed as a whole at no charge to all third
|
||||||
|
parties under the terms of this License.
|
||||||
|
|
||||||
|
c) If the modified program normally reads commands interactively
|
||||||
|
when run, you must cause it, when started running for such
|
||||||
|
interactive use in the most ordinary way, to print or display an
|
||||||
|
announcement including an appropriate copyright notice and a
|
||||||
|
notice that there is no warranty (or else, saying that you provide
|
||||||
|
a warranty) and that users may redistribute the program under
|
||||||
|
these conditions, and telling the user how to view a copy of this
|
||||||
|
License. (Exception: if the Program itself is interactive but
|
||||||
|
does not normally print such an announcement, your work based on
|
||||||
|
the Program is not required to print an announcement.)
|
||||||
|
|
||||||
|
These requirements apply to the modified work as a whole. If
|
||||||
|
identifiable sections of that work are not derived from the Program,
|
||||||
|
and can be reasonably considered independent and separate works in
|
||||||
|
themselves, then this License, and its terms, do not apply to those
|
||||||
|
sections when you distribute them as separate works. But when you
|
||||||
|
distribute the same sections as part of a whole which is a work based
|
||||||
|
on the Program, the distribution of the whole must be on the terms of
|
||||||
|
this License, whose permissions for other licensees extend to the
|
||||||
|
entire whole, and thus to each and every part regardless of who wrote it.
|
||||||
|
|
||||||
|
Thus, it is not the intent of this section to claim rights or contest
|
||||||
|
your rights to work written entirely by you; rather, the intent is to
|
||||||
|
exercise the right to control the distribution of derivative or
|
||||||
|
collective works based on the Program.
|
||||||
|
|
||||||
|
In addition, mere aggregation of another work not based on the Program
|
||||||
|
with the Program (or with a work based on the Program) on a volume of
|
||||||
|
a storage or distribution medium does not bring the other work under
|
||||||
|
the scope of this License.
|
||||||
|
|
||||||
|
3. You may copy and distribute the Program (or a work based on it,
|
||||||
|
under Section 2) in object code or executable form under the terms of
|
||||||
|
Sections 1 and 2 above provided that you also do one of the following:
|
||||||
|
|
||||||
|
a) Accompany it with the complete corresponding machine-readable
|
||||||
|
source code, which must be distributed under the terms of Sections
|
||||||
|
1 and 2 above on a medium customarily used for software interchange; or,
|
||||||
|
|
||||||
|
b) Accompany it with a written offer, valid for at least three
|
||||||
|
years, to give any third party, for a charge no more than your
|
||||||
|
cost of physically performing source distribution, a complete
|
||||||
|
machine-readable copy of the corresponding source code, to be
|
||||||
|
distributed under the terms of Sections 1 and 2 above on a medium
|
||||||
|
customarily used for software interchange; or,
|
||||||
|
|
||||||
|
c) Accompany it with the information you received as to the offer
|
||||||
|
to distribute corresponding source code. (This alternative is
|
||||||
|
allowed only for noncommercial distribution and only if you
|
||||||
|
received the program in object code or executable form with such
|
||||||
|
an offer, in accord with Subsection b above.)
|
||||||
|
|
||||||
|
The source code for a work means the preferred form of the work for
|
||||||
|
making modifications to it. For an executable work, complete source
|
||||||
|
code means all the source code for all modules it contains, plus any
|
||||||
|
associated interface definition files, plus the scripts used to
|
||||||
|
control compilation and installation of the executable. However, as a
|
||||||
|
special exception, the source code distributed need not include
|
||||||
|
anything that is normally distributed (in either source or binary
|
||||||
|
form) with the major components (compiler, kernel, and so on) of the
|
||||||
|
operating system on which the executable runs, unless that component
|
||||||
|
itself accompanies the executable.
|
||||||
|
|
||||||
|
If distribution of executable or object code is made by offering
|
||||||
|
access to copy from a designated place, then offering equivalent
|
||||||
|
access to copy the source code from the same place counts as
|
||||||
|
distribution of the source code, even though third parties are not
|
||||||
|
compelled to copy the source along with the object code.
|
||||||
|
|
||||||
|
4. You may not copy, modify, sublicense, or distribute the Program
|
||||||
|
except as expressly provided under this License. Any attempt
|
||||||
|
otherwise to copy, modify, sublicense or distribute the Program is
|
||||||
|
void, and will automatically terminate your rights under this License.
|
||||||
|
However, parties who have received copies, or rights, from you under
|
||||||
|
this License will not have their licenses terminated so long as such
|
||||||
|
parties remain in full compliance.
|
||||||
|
|
||||||
|
5. You are not required to accept this License, since you have not
|
||||||
|
signed it. However, nothing else grants you permission to modify or
|
||||||
|
distribute the Program or its derivative works. These actions are
|
||||||
|
prohibited by law if you do not accept this License. Therefore, by
|
||||||
|
modifying or distributing the Program (or any work based on the
|
||||||
|
Program), you indicate your acceptance of this License to do so, and
|
||||||
|
all its terms and conditions for copying, distributing or modifying
|
||||||
|
the Program or works based on it.
|
||||||
|
|
||||||
|
6. Each time you redistribute the Program (or any work based on the
|
||||||
|
Program), the recipient automatically receives a license from the
|
||||||
|
original licensor to copy, distribute or modify the Program subject to
|
||||||
|
these terms and conditions. You may not impose any further
|
||||||
|
restrictions on the recipients' exercise of the rights granted herein.
|
||||||
|
You are not responsible for enforcing compliance by third parties to
|
||||||
|
this License.
|
||||||
|
|
||||||
|
7. If, as a consequence of a court judgment or allegation of patent
|
||||||
|
infringement or for any other reason (not limited to patent issues),
|
||||||
|
conditions are imposed on you (whether by court order, agreement or
|
||||||
|
otherwise) that contradict the conditions of this License, they do not
|
||||||
|
excuse you from the conditions of this License. If you cannot
|
||||||
|
distribute so as to satisfy simultaneously your obligations under this
|
||||||
|
License and any other pertinent obligations, then as a consequence you
|
||||||
|
may not distribute the Program at all. For example, if a patent
|
||||||
|
license would not permit royalty-free redistribution of the Program by
|
||||||
|
all those who receive copies directly or indirectly through you, then
|
||||||
|
the only way you could satisfy both it and this License would be to
|
||||||
|
refrain entirely from distribution of the Program.
|
||||||
|
|
||||||
|
If any portion of this section is held invalid or unenforceable under
|
||||||
|
any particular circumstance, the balance of the section is intended to
|
||||||
|
apply and the section as a whole is intended to apply in other
|
||||||
|
circumstances.
|
||||||
|
|
||||||
|
It is not the purpose of this section to induce you to infringe any
|
||||||
|
patents or other property right claims or to contest validity of any
|
||||||
|
such claims; this section has the sole purpose of protecting the
|
||||||
|
integrity of the free software distribution system, which is
|
||||||
|
implemented by public license practices. Many people have made
|
||||||
|
generous contributions to the wide range of software distributed
|
||||||
|
through that system in reliance on consistent application of that
|
||||||
|
system; it is up to the author/donor to decide if he or she is willing
|
||||||
|
to distribute software through any other system and a licensee cannot
|
||||||
|
impose that choice.
|
||||||
|
|
||||||
|
This section is intended to make thoroughly clear what is believed to
|
||||||
|
be a consequence of the rest of this License.
|
||||||
|
|
||||||
|
8. If the distribution and/or use of the Program is restricted in
|
||||||
|
certain countries either by patents or by copyrighted interfaces, the
|
||||||
|
original copyright holder who places the Program under this License
|
||||||
|
may add an explicit geographical distribution limitation excluding
|
||||||
|
those countries, so that distribution is permitted only in or among
|
||||||
|
countries not thus excluded. In such case, this License incorporates
|
||||||
|
the limitation as if written in the body of this License.
|
||||||
|
|
||||||
|
9. The Free Software Foundation may publish revised and/or new versions
|
||||||
|
of the General Public License from time to time. Such new versions will
|
||||||
|
be similar in spirit to the present version, but may differ in detail to
|
||||||
|
address new problems or concerns.
|
||||||
|
|
||||||
|
Each version is given a distinguishing version number. If the Program
|
||||||
|
specifies a version number of this License which applies to it and "any
|
||||||
|
later version", you have the option of following the terms and conditions
|
||||||
|
either of that version or of any later version published by the Free
|
||||||
|
Software Foundation. If the Program does not specify a version number of
|
||||||
|
this License, you may choose any version ever published by the Free Software
|
||||||
|
Foundation.
|
||||||
|
|
||||||
|
10. If you wish to incorporate parts of the Program into other free
|
||||||
|
programs whose distribution conditions are different, write to the author
|
||||||
|
to ask for permission. For software which is copyrighted by the Free
|
||||||
|
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||||
|
make exceptions for this. Our decision will be guided by the two goals
|
||||||
|
of preserving the free status of all derivatives of our free software and
|
||||||
|
of promoting the sharing and reuse of software generally.
|
||||||
|
|
||||||
|
NO WARRANTY
|
||||||
|
|
||||||
|
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||||
|
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||||
|
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||||
|
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||||
|
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||||
|
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||||
|
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||||
|
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||||
|
REPAIR OR CORRECTION.
|
||||||
|
|
||||||
|
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||||
|
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||||
|
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||||
|
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||||
|
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||||
|
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||||
|
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||||
|
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||||
|
POSSIBILITY OF SUCH DAMAGES.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
How to Apply These Terms to Your New Programs
|
||||||
|
|
||||||
|
If you develop a new program, and you want it to be of the greatest
|
||||||
|
possible use to the public, the best way to achieve this is to make it
|
||||||
|
free software which everyone can redistribute and change under these terms.
|
||||||
|
|
||||||
|
To do so, attach the following notices to the program. It is safest
|
||||||
|
to attach them to the start of each source file to most effectively
|
||||||
|
convey the exclusion of warranty; and each file should have at least
|
||||||
|
the "copyright" line and a pointer to where the full notice is found.
|
||||||
|
|
||||||
|
<one line to give the program's name and a brief idea of what it does.>
|
||||||
|
Copyright (C) <year> <name of author>
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 2 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License along
|
||||||
|
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
|
||||||
|
Also add information on how to contact you by electronic and paper mail.
|
||||||
|
|
||||||
|
If the program is interactive, make it output a short notice like this
|
||||||
|
when it starts in an interactive mode:
|
||||||
|
|
||||||
|
Gnomovision version 69, Copyright (C) year name of author
|
||||||
|
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||||
|
This is free software, and you are welcome to redistribute it
|
||||||
|
under certain conditions; type `show c' for details.
|
||||||
|
|
||||||
|
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||||
|
parts of the General Public License. Of course, the commands you use may
|
||||||
|
be called something other than `show w' and `show c'; they could even be
|
||||||
|
mouse-clicks or menu items--whatever suits your program.
|
||||||
|
|
||||||
|
You should also get your employer (if you work as a programmer) or your
|
||||||
|
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||||
|
necessary. Here is a sample; alter the names:
|
||||||
|
|
||||||
|
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||||
|
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||||
|
|
||||||
|
<signature of Ty Coon>, 1 April 1989
|
||||||
|
Ty Coon, President of Vice
|
||||||
|
|
||||||
|
This General Public License does not permit incorporating your program into
|
||||||
|
proprietary programs. If your program is a subroutine library, you may
|
||||||
|
consider it more useful to permit linking proprietary applications with the
|
||||||
|
library. If this is what you want to do, use the GNU Lesser General
|
||||||
|
Public License instead of this License.
|
|
@ -0,0 +1,35 @@
|
||||||
|
= Redmine Code Review Plugin
|
||||||
|
|
||||||
|
This is a plugin for Redmine which lets you annotate source code within the repository browser.
|
||||||
|
|
||||||
|
http://www.r-labs.org/wiki/r-labs/Code_Review
|
||||||
|
|
||||||
|
=== Plugin installation
|
||||||
|
|
||||||
|
1. Copy the plugin directory into the plugins directory
|
||||||
|
|
||||||
|
2. Migrate plugin:
|
||||||
|
rake redmine:plugins:migrate RAILS_ENV=production
|
||||||
|
|
||||||
|
3. Start Redmine
|
||||||
|
|
||||||
|
4. Add code review module into your project.
|
||||||
|
|
||||||
|
5. Go to code review setting tab in the project setting page and select tracker.
|
||||||
|
|
||||||
|
=== Language contributors
|
||||||
|
|
||||||
|
* de.yml - Michael Diederich, Sebastian Bernhard
|
||||||
|
* fr.yml - Thomas M
|
||||||
|
* hu.yml - Péter Major
|
||||||
|
* ko.yml - Ki-yong Kim, Ki Won Kim
|
||||||
|
* nl.yml - Stefan Verstege
|
||||||
|
* pt-br.yml - Alessandro Hecht
|
||||||
|
* zh.yml - Marshall Wu
|
||||||
|
* zh-tw.yml - Andrew Liu
|
||||||
|
* ru.yml - Mykhaylo Sorochan
|
||||||
|
* sk.yml - Milan Freml
|
||||||
|
* es.yml - Ignacio Carrera
|
||||||
|
* pl.yml - Rafal Grzymkowski
|
||||||
|
* sv.yml - André Jonsson
|
||||||
|
* bg.yml - Ivan Cenov, jwalkerbg
|
|
@ -0,0 +1,398 @@
|
||||||
|
# Code Review plugin for Redmine
|
||||||
|
# Copyright (C) 2009-2013 Haruyuki Iida
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or
|
||||||
|
# modify it under the terms of the GNU General Public License
|
||||||
|
# as published by the Free Software Foundation; either version 2
|
||||||
|
# of the License, or (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program; if not, write to the Free Software
|
||||||
|
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
|
||||||
|
class CodeReviewController < ApplicationController
|
||||||
|
unloadable
|
||||||
|
before_filter :find_project, :authorize, :find_user, :find_setting, :find_repository
|
||||||
|
|
||||||
|
helper :sort
|
||||||
|
include SortHelper
|
||||||
|
helper :journals
|
||||||
|
helper :projects
|
||||||
|
include ProjectsHelper
|
||||||
|
helper :issues
|
||||||
|
include IssuesHelper
|
||||||
|
helper :code_review
|
||||||
|
include CodeReviewHelper
|
||||||
|
helper :custom_fields
|
||||||
|
include CustomFieldsHelper
|
||||||
|
|
||||||
|
def index
|
||||||
|
sort_init "#{Issue.table_name}.id", 'desc'
|
||||||
|
sort_update ["#{Issue.table_name}.id", "#{Issue.table_name}.status_id", "#{Issue.table_name}.subject", "path", "updated_at", "user_id", "#{Changeset.table_name}.committer", "#{Changeset.table_name}.revision"]
|
||||||
|
|
||||||
|
limit = per_page_option
|
||||||
|
@review_count = CodeReview.count(:conditions => ['project_id = ? and issue_id is NOT NULL', @project.id])
|
||||||
|
@all_review_count = CodeReview.count(:conditions => ['project_id = ?', @project.id])
|
||||||
|
@review_pages = Paginator.new self, @review_count, limit, params['page']
|
||||||
|
@show_closed = (params['show_closed'] == 'true')
|
||||||
|
show_closed_option = " and #{IssueStatus.table_name}.is_closed = ? "
|
||||||
|
if (@show_closed)
|
||||||
|
show_closed_option = ''
|
||||||
|
end
|
||||||
|
conditions = ["#{CodeReview.table_name}.project_id = ? and issue_id is NOT NULL" + show_closed_option, @project.id]
|
||||||
|
unless (@show_closed)
|
||||||
|
conditions << false
|
||||||
|
end
|
||||||
|
|
||||||
|
@reviews = CodeReview.order(sort_clause).limit(limit).where(conditions).joins(
|
||||||
|
"left join #{Change.table_name} on change_id = #{Change.table_name}.id left join #{Changeset.table_name} on #{Change.table_name}.changeset_id = #{Changeset.table_name}.id " +
|
||||||
|
"left join #{Issue.table_name} on issue_id = #{Issue.table_name}.id " +
|
||||||
|
"left join #{IssueStatus.table_name} on #{Issue.table_name}.status_id = #{IssueStatus.table_name}.id").offset(@review_pages.current.offset)
|
||||||
|
@i_am_member = @user.member_of?(@project)
|
||||||
|
render :template => 'code_review/index.html.erb', :layout => !request.xhr?
|
||||||
|
end
|
||||||
|
|
||||||
|
def new
|
||||||
|
begin
|
||||||
|
CodeReview.transaction {
|
||||||
|
@review = CodeReview.new
|
||||||
|
@review.issue = Issue.new
|
||||||
|
|
||||||
|
if params[:issue] and params[:issue][:tracker_id]
|
||||||
|
@review.issue.tracker_id = params[:issue][:tracker_id].to_i
|
||||||
|
else
|
||||||
|
@review.issue.tracker_id = @setting.tracker_id
|
||||||
|
end
|
||||||
|
@review.safe_attributes = params[:review]
|
||||||
|
@review.project_id = @project.id
|
||||||
|
@review.issue.project_id = @project.id
|
||||||
|
|
||||||
|
@review.user_id = @user.id
|
||||||
|
@review.updated_by_id = @user.id
|
||||||
|
@review.issue.start_date = Date.today
|
||||||
|
@review.action_type = params[:action_type]
|
||||||
|
@review.rev = params[:rev] unless params[:rev].blank?
|
||||||
|
@review.rev_to = params[:rev_to] unless params[:rev_to].blank?
|
||||||
|
@review.file_path = params[:path] unless params[:path].blank?
|
||||||
|
@review.file_count = params[:file_count].to_i unless params[:file_count].blank?
|
||||||
|
@review.attachment_id = params[:attachment_id].to_i unless params[:attachment_id].blank?
|
||||||
|
@issue = @review.issue
|
||||||
|
@review.issue.safe_attributes = params[:issue] unless params[:issue].blank?
|
||||||
|
@review.diff_all = (params[:diff_all] == 'true')
|
||||||
|
|
||||||
|
@parent_candidate = get_parent_candidate(@review.rev) if @review.rev
|
||||||
|
|
||||||
|
if request.post?
|
||||||
|
@review.issue.save!
|
||||||
|
if @review.changeset
|
||||||
|
@review.changeset.issues.each {|issue|
|
||||||
|
create_relation @review, issue, @setting.issue_relation_type
|
||||||
|
} if @setting.auto_relation?
|
||||||
|
elsif @review.attachment and @review.attachment.container_type == 'Issue'
|
||||||
|
issue = Issue.find_by_id(@review.attachment.container_id)
|
||||||
|
create_relation @review, issue, @setting.issue_relation_type if @setting.auto_relation?
|
||||||
|
end
|
||||||
|
@review.open_assignment_issues(@user.id).each {|issue|
|
||||||
|
create_relation @review, issue, IssueRelation::TYPE_RELATES
|
||||||
|
watcher = Watcher.new
|
||||||
|
watcher.watchable_id = @review.issue.id
|
||||||
|
watcher.watchable_type = 'Issue'
|
||||||
|
watcher.user = issue.author
|
||||||
|
watcher.save!
|
||||||
|
}
|
||||||
|
@review.save!
|
||||||
|
|
||||||
|
render :partial => 'add_success', :status => 200
|
||||||
|
return
|
||||||
|
else
|
||||||
|
change_id = params[:change_id].to_i unless params[:change_id].blank?
|
||||||
|
@review.change = Change.find(change_id) if change_id
|
||||||
|
@review.line = params[:line].to_i unless params[:line].blank?
|
||||||
|
if (@review.changeset and @review.changeset.user_id)
|
||||||
|
@review.issue.assigned_to_id = @review.changeset.user_id
|
||||||
|
end
|
||||||
|
@default_version_id = @review.issue.fixed_version.id if @review.issue.fixed_version
|
||||||
|
if @review.changeset and @default_version_id.blank?
|
||||||
|
@review.changeset.issues.each {|issue|
|
||||||
|
if issue.fixed_version
|
||||||
|
@default_version_id = issue.fixed_version.id
|
||||||
|
break;
|
||||||
|
end
|
||||||
|
}
|
||||||
|
end
|
||||||
|
@review.open_assignment_issues(@user.id).each {|issue|
|
||||||
|
if issue.fixed_version
|
||||||
|
@default_version_id = issue.fixed_version.id
|
||||||
|
break;
|
||||||
|
end
|
||||||
|
} unless @default_version_id
|
||||||
|
|
||||||
|
|
||||||
|
end
|
||||||
|
render :partial => 'new_form', :status => 200
|
||||||
|
}
|
||||||
|
rescue ActiveRecord::RecordInvalid
|
||||||
|
render :partial => 'new_form', :status => 200
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def assign
|
||||||
|
code = {}
|
||||||
|
code[:action_type] = params[:action_type] unless params[:action_type].blank?
|
||||||
|
code[:rev] = params[:rev] unless params[:rev].blank?
|
||||||
|
code[:rev_to] = params[:rev_to] unless params[:rev_to].blank?
|
||||||
|
code[:path] = params[:path] unless params[:path].blank?
|
||||||
|
code[:change_id] = params[:change_id].to_i unless params[:change_id].blank?
|
||||||
|
code[:changeset_id] = params[:changeset_id].to_i unless params[:changeset_id].blank?
|
||||||
|
code[:attachment_id] = params[:attachment_id].to_i unless params[:attachment_id].blank?
|
||||||
|
code[:repository_id] = @repository_id if @repository_id
|
||||||
|
|
||||||
|
changeset = Changeset.find(code[:changeset_id]) if code[:changeset_id]
|
||||||
|
if (changeset == nil and code[:change_id] != nil)
|
||||||
|
change = Change.find(code[:change_id])
|
||||||
|
changeset = change.changeset if change
|
||||||
|
end
|
||||||
|
attachment = Attachment.find(code[:attachment_id]) if code[:attachment_id]
|
||||||
|
|
||||||
|
issue = {}
|
||||||
|
issue[:subject] = l(:code_review_requrest)
|
||||||
|
issue[:subject] << " [#{changeset.text_tag}: #{changeset.short_comments}]" if changeset
|
||||||
|
unless changeset
|
||||||
|
issue[:subject] << " [#{attachment.filename}]" if attachment
|
||||||
|
end
|
||||||
|
issue[:tracker_id] = @setting.assignment_tracker_id if @setting.assignment_tracker_id
|
||||||
|
|
||||||
|
redirect_to :controller => 'issues', :action => "new" , :project_id => @project,
|
||||||
|
:issue => issue, :code => code
|
||||||
|
end
|
||||||
|
|
||||||
|
def update_diff_view
|
||||||
|
@show_review_id = params[:review_id].to_i unless params[:review_id].blank?
|
||||||
|
@show_review = CodeReview.find(@show_review_id) if @show_review_id
|
||||||
|
@review = CodeReview.new
|
||||||
|
@rev = params[:rev] unless params[:rev].blank?
|
||||||
|
@rev_to = params[:rev_to] unless params[:rev_to].blank?
|
||||||
|
@path = params[:path] unless params[:path].blank?
|
||||||
|
@paths = []
|
||||||
|
@paths << @path unless @path.blank?
|
||||||
|
|
||||||
|
@action_type = params[:action_type]
|
||||||
|
changeset = @repository.find_changeset_by_name(@rev)
|
||||||
|
if @paths.empty?
|
||||||
|
changeset.filechanges.each{|chg|
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
url = @repository.url
|
||||||
|
root_url = @repository.root_url
|
||||||
|
if (url == nil || root_url == nil)
|
||||||
|
fullpath = @path
|
||||||
|
else
|
||||||
|
rootpath = url[root_url.length, url.length - root_url.length]
|
||||||
|
if rootpath.blank?
|
||||||
|
fullpath = @path
|
||||||
|
else
|
||||||
|
fullpath = (rootpath + '/' + @path).gsub(/[\/]+/, '/')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
@change = nil
|
||||||
|
changeset.filechanges.each{|chg|
|
||||||
|
@change = chg if ((chg.path == fullpath) or ("/#{chg.path}" == fullpath)) or (chg.path == "/#{@path}")
|
||||||
|
} unless @path.blank?
|
||||||
|
|
||||||
|
@changeset = changeset
|
||||||
|
if @path
|
||||||
|
@reviews = CodeReview.where(['file_path = ? and rev = ? and issue_id is NOT NULL', @path, @rev]).all
|
||||||
|
else
|
||||||
|
@reviews = CodeReview.where(['rev = ? and issue_id is NOT NULL', @rev]).all
|
||||||
|
end
|
||||||
|
@review.change_id = @change.id if @change
|
||||||
|
|
||||||
|
#render :partial => 'show_error'
|
||||||
|
#return
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
render :partial => 'update_diff_view'
|
||||||
|
end
|
||||||
|
|
||||||
|
def update_attachment_view
|
||||||
|
@show_review_id = params[:review_id].to_i unless params[:review_id].blank?
|
||||||
|
@attachment_id = params[:attachment_id].to_i
|
||||||
|
@show_review = CodeReview.find(@show_review_id) if @show_review_id
|
||||||
|
@review = CodeReview.new
|
||||||
|
@action_type = 'attachment'
|
||||||
|
@attachment = Attachment.find(@attachment_id)
|
||||||
|
|
||||||
|
@reviews = CodeReview.where(['attachment_id = (?) and issue_id is NOT NULL', @attachment_id]).all
|
||||||
|
|
||||||
|
render :partial => 'update_diff_view'
|
||||||
|
end
|
||||||
|
|
||||||
|
def show
|
||||||
|
@review = CodeReview.find(params[:review_id].to_i) unless params[:review_id].blank?
|
||||||
|
@repository = @review.repository if @review
|
||||||
|
@assignment = CodeReviewAssignment.find(params[:assignment_id].to_i) unless params[:assignment_id].blank?
|
||||||
|
@repository_id = @assignment.repository_identifier if @assignment
|
||||||
|
@issue = @review.issue if @review
|
||||||
|
@allowed_statuses = @review.issue.new_statuses_allowed_to(User.current) if @review
|
||||||
|
target = @review if @review
|
||||||
|
target = @assignment if @assignment
|
||||||
|
@repository_id = target.repository_identifier
|
||||||
|
if request.xhr? or !params[:update].blank?
|
||||||
|
render :partial => 'show'
|
||||||
|
elsif target.path
|
||||||
|
#@review = @review.root
|
||||||
|
path = URI.decode(target.path)
|
||||||
|
#path = '/' + path unless path.match(/^\//)
|
||||||
|
action_name = target.action_type
|
||||||
|
rev_to = ''
|
||||||
|
rev_to = '&rev_to=' + target.rev_to if target.rev_to
|
||||||
|
if action_name == 'attachment'
|
||||||
|
attachment = target.attachment
|
||||||
|
url = url_for(:controller => 'attachments', :action => 'show', :id => attachment.id) + '/' + URI.escape(attachment.filename)
|
||||||
|
url << '?review_id=' + @review.id.to_s if @review
|
||||||
|
redirect_to(url)
|
||||||
|
else
|
||||||
|
path = nil if target.diff_all
|
||||||
|
url = url_for(:controller => 'repositories', :action => action_name, :id => @project,
|
||||||
|
:repository_id => @repository_id, :rev => target.revision, :path => path)
|
||||||
|
#url = url_for(:controller => 'repositories', :action => action_name, :id => @project, :repository_id => @repository_id) + path + '?rev=' + target.revision
|
||||||
|
url << '?review_id=' + @review.id.to_s + rev_to if @review
|
||||||
|
redirect_to url
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def reply
|
||||||
|
begin
|
||||||
|
@review = CodeReview.find(params[:review_id].to_i)
|
||||||
|
@issue = @review.issue
|
||||||
|
@issue.lock_version = params[:issue][:lock_version]
|
||||||
|
comment = params[:reply][:comment]
|
||||||
|
journal = @issue.init_journal(User.current, comment)
|
||||||
|
@review.safe_attributes = params[:review]
|
||||||
|
@allowed_statuses = @issue.new_statuses_allowed_to(User.current)
|
||||||
|
|
||||||
|
@issue.save!
|
||||||
|
if !journal.new_record?
|
||||||
|
# Only send notification if something was actually changed
|
||||||
|
flash[:notice] = l(:notice_successful_update)
|
||||||
|
end
|
||||||
|
|
||||||
|
render :partial => 'show'
|
||||||
|
rescue ActiveRecord::StaleObjectError
|
||||||
|
# Optimistic locking exception
|
||||||
|
@error = l(:notice_locking_conflict)
|
||||||
|
render :partial => 'show'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def update
|
||||||
|
begin
|
||||||
|
CodeReview.transaction {
|
||||||
|
@review = CodeReview.find(params[:review_id].to_i)
|
||||||
|
journal = @review.issue.init_journal(User.current, nil)
|
||||||
|
@allowed_statuses = @review.issue.new_statuses_allowed_to(User.current)
|
||||||
|
@issue = @review.issue
|
||||||
|
@issue.lock_version = params[:issue][:lock_version]
|
||||||
|
@review.safe_attributes = params[:review]
|
||||||
|
@review.updated_by_id = @user.id
|
||||||
|
@review.save!
|
||||||
|
@review.issue.save!
|
||||||
|
@notice = l(:notice_review_updated)
|
||||||
|
lang = current_language
|
||||||
|
Mailer.deliver_issue_edit(journal) if Setting.notified_events.include?('issue_updated')
|
||||||
|
set_language lang if respond_to? 'set_language'
|
||||||
|
render :partial => 'show'
|
||||||
|
}
|
||||||
|
rescue ActiveRecord::StaleObjectError
|
||||||
|
# Optimistic locking exception
|
||||||
|
@error = l(:notice_locking_conflict)
|
||||||
|
render :partial => 'show'
|
||||||
|
rescue
|
||||||
|
render :partial => 'show'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
def destroy
|
||||||
|
@review = CodeReview.find(params[:review_id].to_i)
|
||||||
|
@review.issue.destroy if @review
|
||||||
|
render :text => 'delete success.'
|
||||||
|
end
|
||||||
|
|
||||||
|
def forward_to_revision
|
||||||
|
path = params[:path]
|
||||||
|
rev = params[:rev]
|
||||||
|
changesets = @repository.latest_changesets(path, rev, Setting.repository_log_display_limit.to_i)
|
||||||
|
change = changesets[0]
|
||||||
|
|
||||||
|
identifier = change.identifier
|
||||||
|
redirect_to url_for(:controller => 'repositories', :action => 'entry', :id => @project, :repository_id => @repository_id) + '/' + path + '?rev=' + identifier.to_s
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
def preview
|
||||||
|
@text = params[:review][:comment]
|
||||||
|
@text = params[:reply][:comment] unless @text
|
||||||
|
render :partial => 'common/preview'
|
||||||
|
end
|
||||||
|
|
||||||
|
def update_revisions_view
|
||||||
|
changeset_ids = []
|
||||||
|
#changeset_ids = CGI.unescape(params[:changeset_ids]).split(',') unless params[:changeset_ids].blank?
|
||||||
|
changeset_ids = params[:changeset_ids].split(',') unless params[:changeset_ids].blank?
|
||||||
|
@changesets = []
|
||||||
|
changeset_ids.each {|id|
|
||||||
|
@changesets << @repository.find_changeset_by_name(id) unless id.blank?
|
||||||
|
}
|
||||||
|
render :partial => 'update_revisions'
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
def find_repository
|
||||||
|
if params[:repository_id].present? and @project.repositories
|
||||||
|
@repository = @project.repositories.find_by_identifier_param(params[:repository_id])
|
||||||
|
else
|
||||||
|
@repository = @project.repository
|
||||||
|
end
|
||||||
|
@repository_id = @repository.identifier_param if @repository.respond_to?("identifier_param")
|
||||||
|
end
|
||||||
|
|
||||||
|
def find_project
|
||||||
|
# @project variable must be set before calling the authorize filter
|
||||||
|
@project = Project.find(params[:id])
|
||||||
|
end
|
||||||
|
|
||||||
|
def find_user
|
||||||
|
@user = User.current
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
def find_setting
|
||||||
|
@setting = CodeReviewProjectSetting.find_or_create(@project)
|
||||||
|
end
|
||||||
|
|
||||||
|
def get_parent_candidate(revision)
|
||||||
|
changeset = @repository.find_changeset_by_name(revision)
|
||||||
|
changeset.issues.each {|issue|
|
||||||
|
return Issue.find(issue.parent_issue_id) if issue.parent_issue_id
|
||||||
|
}
|
||||||
|
nil
|
||||||
|
end
|
||||||
|
|
||||||
|
def create_relation(review, issue, type)
|
||||||
|
return unless issue.project == @project
|
||||||
|
relation = IssueRelation.new
|
||||||
|
relation.relation_type = type
|
||||||
|
relation.issue_from_id = review.issue.id
|
||||||
|
relation.issue_to_id = issue.id
|
||||||
|
relation.save!
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,119 @@
|
||||||
|
# Code Review plugin for Redmine
|
||||||
|
# Copyright (C) 2010 Haruyuki Iida
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or
|
||||||
|
# modify it under the terms of the GNU General Public License
|
||||||
|
# as published by the Free Software Foundation; either version 2
|
||||||
|
# of the License, or (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program; if not, write to the Free Software
|
||||||
|
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
|
||||||
|
class CodeReviewSettingsController < ApplicationController
|
||||||
|
unloadable
|
||||||
|
layout 'base'
|
||||||
|
menu_item :code_review
|
||||||
|
include CodeReviewAutoAssignSettings
|
||||||
|
|
||||||
|
before_filter :find_project, :authorize, :find_user
|
||||||
|
|
||||||
|
def update
|
||||||
|
begin
|
||||||
|
@setting = CodeReviewProjectSetting.find_or_create(@project)
|
||||||
|
|
||||||
|
@setting.safe_attributes = params[:setting]
|
||||||
|
@setting.updated_by = @user.id
|
||||||
|
params[:auto_assign][:filters] = params[:auto_assign][:filters].values unless params[:auto_assign][:filters].blank?
|
||||||
|
@setting.auto_assign_settings = params[:auto_assign].to_yaml
|
||||||
|
|
||||||
|
@setting.save!
|
||||||
|
|
||||||
|
flash[:notice] = l(:notice_successful_update)
|
||||||
|
rescue ActiveRecord::StaleObjectError
|
||||||
|
# Optimistic locking exception
|
||||||
|
flash[:error] = l(:notice_locking_conflict)
|
||||||
|
end
|
||||||
|
redirect_to :controller => 'projects', :action => "settings", :id => @project, :tab => 'code_review'
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
def add_filter
|
||||||
|
setting = CodeReviewProjectSetting.find_or_create(@project)
|
||||||
|
@auto_assign = setting.auto_assign_settings
|
||||||
|
filters = params[:auto_assign][:filters].values unless params[:auto_assign][:filters].blank?
|
||||||
|
filters = [] unless filters
|
||||||
|
filters << params[:auto_assign_add_filter]
|
||||||
|
|
||||||
|
@auto_assign.filters = filters.collect{|f|
|
||||||
|
filter = AssignmentFilter.new
|
||||||
|
filter.attributes = f
|
||||||
|
filter
|
||||||
|
}
|
||||||
|
@auto_assign.filter_enabled = true
|
||||||
|
render :partial => "code_review_settings/filters"
|
||||||
|
end
|
||||||
|
|
||||||
|
def edit_filter
|
||||||
|
setting = CodeReviewProjectSetting.find_or_create(@project)
|
||||||
|
@auto_assign = setting.auto_assign_settings
|
||||||
|
num = params[:num].to_i
|
||||||
|
filters = params[:auto_assign][:filters].values unless params[:auto_assign][:filters].blank?
|
||||||
|
filters = [] unless filters
|
||||||
|
i = 0
|
||||||
|
@auto_assign.filters = filters.collect{|f|
|
||||||
|
filter = AssignmentFilter.new
|
||||||
|
if i == num
|
||||||
|
filter.attributes = params[:auto_assign_edit_filter][num.to_s]
|
||||||
|
else
|
||||||
|
filter.attributes = f
|
||||||
|
end
|
||||||
|
i = i + 1
|
||||||
|
filter
|
||||||
|
}
|
||||||
|
render :partial => "code_review_settings/filters"
|
||||||
|
end
|
||||||
|
|
||||||
|
def sort
|
||||||
|
setting = CodeReviewProjectSetting.find_or_create(@project)
|
||||||
|
@auto_assign = setting.auto_assign_settings
|
||||||
|
filters = params[:auto_assign][:filters].values unless params[:auto_assign][:filters].blank?
|
||||||
|
filters = [] unless filters
|
||||||
|
num = params[:auto_assign_filter][:num].to_i
|
||||||
|
move_to = params[:auto_assign_filter][:move_to]
|
||||||
|
|
||||||
|
if move_to == 'highest'
|
||||||
|
filters[num][:order] = 0
|
||||||
|
elsif move_to == 'higher'
|
||||||
|
filters[num][:order] = filters[num][:order].to_i - 15
|
||||||
|
elsif move_to == 'lower'
|
||||||
|
filters[num][:order] = filters[num][:order].to_i + 15
|
||||||
|
elsif move_to == 'lowest'
|
||||||
|
filters[num][:order] = 999999999
|
||||||
|
end
|
||||||
|
|
||||||
|
@auto_assign.filters = filters.collect{|f|
|
||||||
|
filter = AssignmentFilter.new
|
||||||
|
filter.attributes = f
|
||||||
|
filter
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
render :partial => "code_review_settings/filters"
|
||||||
|
end
|
||||||
|
private
|
||||||
|
def find_project
|
||||||
|
# @project variable must be set before calling the authorize filter
|
||||||
|
@project = Project.find(params[:id])
|
||||||
|
end
|
||||||
|
|
||||||
|
def find_user
|
||||||
|
@user = User.current
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
|
@ -0,0 +1,37 @@
|
||||||
|
# Code Review plugin for Redmine
|
||||||
|
# Copyright (C) 2009-2011 Haruyuki Iida
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or
|
||||||
|
# modify it under the terms of the GNU General Public License
|
||||||
|
# as published by the Free Software Foundation; either version 2
|
||||||
|
# of the License, or (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program; if not, write to the Free Software
|
||||||
|
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
module CodeReviewHelper
|
||||||
|
unloadable
|
||||||
|
def show_assignments(assignments, project, options = {})
|
||||||
|
html = "#{l(:review_assignments)}:"
|
||||||
|
assignments.each do |assignment|
|
||||||
|
issue = assignment.issue
|
||||||
|
html << link_to("##{issue.id} ", {:controller => 'issues', :action => 'show', :id => issue.id},
|
||||||
|
:class => issue.css_classes, :title => "#{issue}(#{issue.status})")
|
||||||
|
end if assignments
|
||||||
|
|
||||||
|
link = link_to(l(:button_add), {:controller => 'code_review',
|
||||||
|
:action => 'assign', :id=>project, :action_type => options[:action_type],
|
||||||
|
:rev => options[:rev], :rev_to => options[:rev_to], :path => options[:path],
|
||||||
|
:change_id => options[:change_id], :attachment_id => options[:attachment_id],
|
||||||
|
:changeset_id => options[:changeset_id]}, :class => 'icon icon-add')
|
||||||
|
|
||||||
|
html << link if link
|
||||||
|
|
||||||
|
html
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,175 @@
|
||||||
|
# Code Review plugin for Redmine
|
||||||
|
# Copyright (C) 2009-2012 Haruyuki Iida
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or
|
||||||
|
# modify it under the terms of the GNU General Public License
|
||||||
|
# as published by the Free Software Foundation; either version 2
|
||||||
|
# of the License, or (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program; if not, write to the Free Software
|
||||||
|
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
class CodeReview < ActiveRecord::Base
|
||||||
|
include Redmine::SafeAttributes
|
||||||
|
unloadable
|
||||||
|
belongs_to :project
|
||||||
|
belongs_to :change
|
||||||
|
belongs_to :issue
|
||||||
|
belongs_to :updated_by, :class_name => 'User', :foreign_key => 'updated_by_id'
|
||||||
|
belongs_to :attachment
|
||||||
|
|
||||||
|
validates_presence_of :project_id, :user_id, :updated_by_id, :issue,
|
||||||
|
:subject, :action_type, :line
|
||||||
|
|
||||||
|
STATUS_OPEN = 0
|
||||||
|
STATUS_CLOSED = 1
|
||||||
|
|
||||||
|
safe_attributes 'change_id', 'subject', 'line', 'parent_id', 'comment', 'status_id'
|
||||||
|
|
||||||
|
def before_create
|
||||||
|
issue = Issue.new unless issue
|
||||||
|
end
|
||||||
|
|
||||||
|
def is_closed?
|
||||||
|
issue.closed?
|
||||||
|
#self.root.status == STATUS_CLOSED
|
||||||
|
end
|
||||||
|
|
||||||
|
def close
|
||||||
|
issue.status = IssueStatus.find(5)
|
||||||
|
#self.root.status = STATUS_CLOSED
|
||||||
|
end
|
||||||
|
|
||||||
|
def reopen
|
||||||
|
issue.status = IssueStatus.find(1)
|
||||||
|
#self.root.status = STATUS_OPEN
|
||||||
|
end
|
||||||
|
|
||||||
|
def committer
|
||||||
|
return changeset.author if changeset
|
||||||
|
end
|
||||||
|
|
||||||
|
def path
|
||||||
|
begin
|
||||||
|
return file_path if file_path
|
||||||
|
return @path if @path
|
||||||
|
if attachment_id
|
||||||
|
@path = attachment.filename
|
||||||
|
return @path
|
||||||
|
end
|
||||||
|
repository = changeset.repository
|
||||||
|
url = repository.url
|
||||||
|
root_url = repository.root_url
|
||||||
|
if (url == nil || root_url == nil)
|
||||||
|
@path = change.path
|
||||||
|
return @path
|
||||||
|
end
|
||||||
|
rootpath = url[root_url.length, url.length - root_url.length]
|
||||||
|
if rootpath == '/' || rootpath.blank?
|
||||||
|
@path = change.path
|
||||||
|
else
|
||||||
|
@path = change.path[rootpath.length, change.path.length - rootpath.length]
|
||||||
|
end
|
||||||
|
rescue => ex
|
||||||
|
return ex.to_s
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def revision
|
||||||
|
return rev if rev
|
||||||
|
changeset.revision if changeset
|
||||||
|
end
|
||||||
|
|
||||||
|
def changeset
|
||||||
|
@changeset ||= change.changeset if change
|
||||||
|
end
|
||||||
|
|
||||||
|
def repository
|
||||||
|
@repository ||= changeset.repository if changeset
|
||||||
|
end
|
||||||
|
|
||||||
|
def repository_identifier
|
||||||
|
return nil unless repository
|
||||||
|
@repository_identifier ||= repository.identifier_param
|
||||||
|
end
|
||||||
|
|
||||||
|
def comment=(str)
|
||||||
|
issue.description = str if issue
|
||||||
|
end
|
||||||
|
|
||||||
|
def comment
|
||||||
|
issue.description if issue
|
||||||
|
end
|
||||||
|
|
||||||
|
def before_save
|
||||||
|
issue.project_id = project_id unless issue.project_id
|
||||||
|
end
|
||||||
|
|
||||||
|
def validate
|
||||||
|
unless issue.validate
|
||||||
|
false
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def user=(u)
|
||||||
|
issue.author = u
|
||||||
|
end
|
||||||
|
|
||||||
|
def user_id=(id)
|
||||||
|
issue.author_id = id
|
||||||
|
end
|
||||||
|
|
||||||
|
def user_id
|
||||||
|
issue.author_id
|
||||||
|
end
|
||||||
|
|
||||||
|
def user
|
||||||
|
issue.author if issue
|
||||||
|
end
|
||||||
|
|
||||||
|
def subject=(s)
|
||||||
|
issue.subject = s
|
||||||
|
end
|
||||||
|
|
||||||
|
def subject
|
||||||
|
issue.subject
|
||||||
|
end
|
||||||
|
|
||||||
|
def parent_id= (p)
|
||||||
|
issue.parent_issue_id = p
|
||||||
|
end
|
||||||
|
|
||||||
|
def parent_id
|
||||||
|
issue.parent_issue_id
|
||||||
|
end
|
||||||
|
|
||||||
|
def status_id=(s)
|
||||||
|
issue.status_id = s
|
||||||
|
end
|
||||||
|
|
||||||
|
def status_id
|
||||||
|
issue.status_id
|
||||||
|
end
|
||||||
|
|
||||||
|
def open_assignment_issues(user_id)
|
||||||
|
issues = []
|
||||||
|
assignments = []
|
||||||
|
assignments = change.code_review_assignments if change
|
||||||
|
assignments = assignments + changeset.code_review_assignments if changeset
|
||||||
|
assignments = assignments + attachment.code_review_assignments if attachment
|
||||||
|
|
||||||
|
assignments.each {|assignment|
|
||||||
|
unless assignment.is_closed?
|
||||||
|
issues << assignment.issue if user_id == assignment.issue.assigned_to_id
|
||||||
|
end
|
||||||
|
}
|
||||||
|
|
||||||
|
issues
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,80 @@
|
||||||
|
# Code Review plugin for Redmine
|
||||||
|
# Copyright (C) 2010-2011 Haruyuki Iida
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or
|
||||||
|
# modify it under the terms of the GNU General Public License
|
||||||
|
# as published by the Free Software Foundation; either version 2
|
||||||
|
# of the License, or (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program; if not, write to the Free Software
|
||||||
|
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
|
||||||
|
class CodeReviewAssignment < ActiveRecord::Base
|
||||||
|
unloadable
|
||||||
|
belongs_to :issue
|
||||||
|
belongs_to :change
|
||||||
|
belongs_to :changeset
|
||||||
|
belongs_to :attachment
|
||||||
|
validates_presence_of :issue_id
|
||||||
|
|
||||||
|
def is_closed?
|
||||||
|
issue.closed?
|
||||||
|
end
|
||||||
|
|
||||||
|
def path
|
||||||
|
file_path
|
||||||
|
end
|
||||||
|
|
||||||
|
def revision
|
||||||
|
return rev if rev
|
||||||
|
changeset.revision if changeset
|
||||||
|
end
|
||||||
|
|
||||||
|
def repository
|
||||||
|
@repository ||= change.changeset.repository if change
|
||||||
|
@repository ||= changeset.repository if changeset
|
||||||
|
@repository
|
||||||
|
end
|
||||||
|
|
||||||
|
def repository_identifier
|
||||||
|
return nil unless repository
|
||||||
|
@repository_identifier ||= repository.identifier_param if repository.respond_to?("identifier_param")
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.create_with_changeset(changeset)
|
||||||
|
project = changeset.project
|
||||||
|
setting = CodeReviewProjectSetting.find_or_create(project)
|
||||||
|
auto_assign = setting.auto_assign_settings
|
||||||
|
assignment = CodeReviewAssignment.new
|
||||||
|
issue = Issue.new
|
||||||
|
issue.subject = auto_assign.subject
|
||||||
|
issue.subject = l(:code_review_requrest) if issue.subject.blank?
|
||||||
|
issue.subject = issue.subject.sub("$REV" , changeset.revision)
|
||||||
|
issue.subject = issue.subject.sub("$COMMENTS" , changeset.comments.split(//u)[0..60].join) unless changeset.comments.blank?
|
||||||
|
issue.tracker_id = setting.assignment_tracker_id
|
||||||
|
issue.project = project
|
||||||
|
issue.author = User.find(auto_assign.author_id)
|
||||||
|
issue.assigned_to_id = auto_assign.select_assign_to(project, changeset.user)
|
||||||
|
issue.description = auto_assign.description
|
||||||
|
issue.description = issue.description.sub("$REV" , changeset.revision) unless issue.description.blank?
|
||||||
|
issue.description = issue.description.sub("$COMMENTS" , changeset.comments) unless changeset.comments.blank?
|
||||||
|
|
||||||
|
issue.save!
|
||||||
|
|
||||||
|
assignment.issue_id = issue.id
|
||||||
|
assignment.changeset_id = changeset.id
|
||||||
|
assignment.save!
|
||||||
|
assignment
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
def diff_all
|
||||||
|
path.blank?
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,77 @@
|
||||||
|
# Code Review plugin for Redmine
|
||||||
|
# Copyright (C) 2009-2011 Haruyuki Iida
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or
|
||||||
|
# modify it under the terms of the GNU General Public License
|
||||||
|
# as published by the Free Software Foundation; either version 2
|
||||||
|
# of the License, or (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program; if not, write to the Free Software
|
||||||
|
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
class CodeReviewProjectSetting < ActiveRecord::Base
|
||||||
|
unloadable
|
||||||
|
include Redmine::SafeAttributes
|
||||||
|
include CodeReviewAutoAssignSettings
|
||||||
|
|
||||||
|
belongs_to :project
|
||||||
|
belongs_to :tracker
|
||||||
|
belongs_to :assignment_tracker, :class_name => 'Tracker'
|
||||||
|
|
||||||
|
validates_presence_of :project_id
|
||||||
|
validates_presence_of :tracker_id
|
||||||
|
validates_presence_of :assignment_tracker_id
|
||||||
|
|
||||||
|
before_save :set_assignment_settings
|
||||||
|
|
||||||
|
safe_attributes 'tracker_id', 'assignment_tracker_id', 'hide_code_review_tab', 'auto_relation', 'tracker_in_review_dialog'
|
||||||
|
|
||||||
|
AUTORELATION_TYPE_NONE = 0
|
||||||
|
AUTORELATION_TYPE_RELATES = 1
|
||||||
|
AUTORELATION_TYPE_BLOCKS = 2
|
||||||
|
|
||||||
|
def self.find_or_create(project)
|
||||||
|
setting = CodeReviewProjectSetting.find_by_project_id(project.id)
|
||||||
|
unless setting
|
||||||
|
setting = CodeReviewProjectSetting.new
|
||||||
|
setting.project_id = project.id
|
||||||
|
return setting if project.trackers.length == 0
|
||||||
|
setting.tracker = project.trackers[0]
|
||||||
|
setting.assignment_tracker = project.trackers[0]
|
||||||
|
setting.save!
|
||||||
|
end
|
||||||
|
setting
|
||||||
|
end
|
||||||
|
|
||||||
|
def auto_assign_settings
|
||||||
|
@auto_assign_settings ||= AutoAssignSettings.load(auto_assign)
|
||||||
|
end
|
||||||
|
|
||||||
|
def auto_assign_settings=(settings)
|
||||||
|
@auto_assign_settings = settings
|
||||||
|
end
|
||||||
|
|
||||||
|
def issue_relation_type
|
||||||
|
return IssueRelation::TYPE_RELATES if auto_relation == CodeReviewProjectSetting::AUTORELATION_TYPE_RELATES
|
||||||
|
return IssueRelation::TYPE_BLOCKS if auto_relation == CodeReviewProjectSetting::AUTORELATION_TYPE_BLOCKS
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
|
def auto_relation?
|
||||||
|
issue_relation_type != nil
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
def set_assignment_settings
|
||||||
|
if auto_assign_settings
|
||||||
|
self.auto_assign = auto_assign_settings.to_s
|
||||||
|
else
|
||||||
|
self.auto_assign = nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,50 @@
|
||||||
|
# Code Review plugin for Redmine
|
||||||
|
# Copyright (C) 2011 Haruyuki Iida
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or
|
||||||
|
# modify it under the terms of the GNU General Public License
|
||||||
|
# as published by the Free Software Foundation; either version 2
|
||||||
|
# of the License, or (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program; if not, write to the Free Software
|
||||||
|
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
class CodeReviewUserSetting < ActiveRecord::Base
|
||||||
|
unloadable
|
||||||
|
belongs_to :user
|
||||||
|
|
||||||
|
validates_presence_of :user_id
|
||||||
|
validates_presence_of :mail_notification
|
||||||
|
validates_uniqueness_of :user_id
|
||||||
|
|
||||||
|
NOTIFCIATION_NONE = 0
|
||||||
|
NOTIFICATION_INVOLVED_IN = 1
|
||||||
|
NOTIFICATION_ALL = 2
|
||||||
|
|
||||||
|
def CodeReviewUserSetting.find_or_create(uid)
|
||||||
|
setting = CodeReviewUserSetting.find_by_user_id(uid)
|
||||||
|
return setting if setting
|
||||||
|
setting = CodeReviewUserSetting.new
|
||||||
|
setting.user_id = uid
|
||||||
|
setting.mail_notification = NOTIFICATION_INVOLVED_IN
|
||||||
|
setting.save
|
||||||
|
return setting
|
||||||
|
end
|
||||||
|
|
||||||
|
def mail_notification_none?
|
||||||
|
mail_notification == NOTIFCIATION_NONE
|
||||||
|
end
|
||||||
|
|
||||||
|
def mail_notification_involved_in?
|
||||||
|
mail_notification == NOTIFICATION_INVOLVED_IN
|
||||||
|
end
|
||||||
|
|
||||||
|
def mail_notification_all?
|
||||||
|
mail_notification == NOTIFICATION_ALL
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,122 @@
|
||||||
|
# Code Review plugin for Redmine
|
||||||
|
# Copyright (C) 2009 Haruyuki Iida
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or
|
||||||
|
# modify it under the terms of the GNU General Public License
|
||||||
|
# as published by the Free Software Foundation; either version 2
|
||||||
|
# of the License, or (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program; if not, write to the Free Software
|
||||||
|
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
|
||||||
|
class ReviewMailer < Mailer
|
||||||
|
|
||||||
|
def review_add(project, review)
|
||||||
|
redmine_headers 'Project' => review.project.identifier,
|
||||||
|
'Review-Id' => review.id,
|
||||||
|
'Review-Author' => review.user.login
|
||||||
|
|
||||||
|
recipients get_mail_addresses(review)
|
||||||
|
|
||||||
|
subject "[#{review.project.name} - #{l(:label_review_new)} - #{l(:label_review)}##{review.id}] "
|
||||||
|
review_url = url_for(:controller => 'code_review', :action => 'show', :id => project, :review_id => review.id)
|
||||||
|
|
||||||
|
body :review => review, :review_url => review_url
|
||||||
|
|
||||||
|
return if (l(:this_is_checking_for_before_rails_2_2_2) == 'this_is_checking_for_before_rails_2_2_2')
|
||||||
|
# 何故かrails 2.2 以後は以下の処理が必要
|
||||||
|
|
||||||
|
content_type "multipart/alternative"
|
||||||
|
|
||||||
|
part "text/plain" do |p|
|
||||||
|
p.body = render_message("review_add.text.plain.erb", :body => body, :review=>review, :review_url => review_url)
|
||||||
|
end
|
||||||
|
|
||||||
|
part "text/html" do |p|
|
||||||
|
p.body = render_message("review_add.text.html.erb", :body => body, :review=>review, :review_url => review_url)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def review_reply(project, review)
|
||||||
|
redmine_headers 'Project' => review.project.identifier,
|
||||||
|
'Review-Id' => review.id,
|
||||||
|
'Review-Author' => review.user.login
|
||||||
|
|
||||||
|
recipients recipients get_mail_addresses(review)
|
||||||
|
|
||||||
|
subject "[#{review.project.name} - Updated - #{l(:label_review)}##{review.root.id}] "
|
||||||
|
review_url = url_for(:controller => 'code_review', :action => 'show', :id => project, :review_id => review.root.id)
|
||||||
|
body :review => review, :review_url => review_url
|
||||||
|
|
||||||
|
return if (l(:this_is_checking_for_before_rails_2_2_2) == 'this_is_checking_for_before_rails_2_2_2')
|
||||||
|
# 何故かrails 2.2 以後は以下の処理が必要
|
||||||
|
|
||||||
|
content_type "multipart/alternative"
|
||||||
|
|
||||||
|
part "text/plain" do |p|
|
||||||
|
p.body = render_message("review_reply.text.plain.erb", :body => body, :review=>review, :review_url => review_url)
|
||||||
|
end
|
||||||
|
|
||||||
|
part "text/html" do |p|
|
||||||
|
p.body = render_message("review_reply.text.html.erb", :body => body, :review=>review, :review_url => review_url)
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
def review_status_changed(project, review)
|
||||||
|
redmine_headers 'Project' => review.project.identifier,
|
||||||
|
'Review-Id' => review.id,
|
||||||
|
'Review-Author' => review.user.login
|
||||||
|
|
||||||
|
recipients recipients get_mail_addresses(review)
|
||||||
|
|
||||||
|
new_status = l(:label_review_open) if review.status_changed_to == CodeReview::STATUS_OPEN
|
||||||
|
new_status = l(:label_review_closed) if review.status_changed_to == CodeReview::STATUS_CLOSED
|
||||||
|
|
||||||
|
subject "[#{review.project.name} - Updated - #{l(:label_review)}##{review.root.id}] Status changed to #{new_status}."
|
||||||
|
review_url = url_for(:controller => 'code_review', :action => 'show', :id => project, :review_id => review.root.id)
|
||||||
|
|
||||||
|
body :review => review, :review_url => review_url
|
||||||
|
|
||||||
|
return if (l(:this_is_checking_for_before_rails_2_2_2) == 'this_is_checking_for_before_rails_2_2_2')
|
||||||
|
# 何故かrails 2.2 以後は以下の処理が必要
|
||||||
|
|
||||||
|
content_type "multipart/alternative"
|
||||||
|
|
||||||
|
part "text/plain" do |p|
|
||||||
|
p.body = render_message("review_status_changed.text.plain.erb", :body => body, :review=>review, :review_url => review_url)
|
||||||
|
end
|
||||||
|
|
||||||
|
part "text/html" do |p|
|
||||||
|
p.body = render_message("review_status_changed.text.html.erb", :body => body, :review=>review, :review_url => review_url)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def get_mail_addresses(review)
|
||||||
|
mail_addresses = []
|
||||||
|
review.root.users_for_notification.each{|u|
|
||||||
|
mail_addresses << u.mail
|
||||||
|
}
|
||||||
|
committer = review.change.changeset.user
|
||||||
|
if committer
|
||||||
|
setting = CodeReviewUserSetting.find_or_create(committer.id)
|
||||||
|
mail_addresses << committer.mail if setting and !setting.mail_notification_none?
|
||||||
|
end
|
||||||
|
|
||||||
|
review.project.members.each{|member|
|
||||||
|
user = member.user
|
||||||
|
setting = CodeReviewUserSetting.find_or_create(user.id)
|
||||||
|
next unless setting
|
||||||
|
mail_addresses << user.mail if setting.mail_notification_all?
|
||||||
|
}
|
||||||
|
mail_addresses.compact.uniq
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
|
@ -0,0 +1,27 @@
|
||||||
|
<%
|
||||||
|
# Code Review plugin for Redmine
|
||||||
|
# Copyright (C) 2009 Haruyuki Iida
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or
|
||||||
|
# modify it under the terms of the GNU General Public License
|
||||||
|
# as published by the Free Software Foundation; either version 2
|
||||||
|
# of the License, or (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program; if not, write to the Free Software
|
||||||
|
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
-%>
|
||||||
|
<%= javascript_tag do %>
|
||||||
|
|
||||||
|
var line = <%= @review.line %>;
|
||||||
|
var review_id = <%= @review.id %>;
|
||||||
|
var file_count = <%= @review.file_count %>;
|
||||||
|
hideForm();
|
||||||
|
setShowReviewButton(line, review_id, false, file_count);
|
||||||
|
|
||||||
|
<% end %>
|
|
@ -0,0 +1,82 @@
|
||||||
|
<%
|
||||||
|
# Code Review plugin for Redmine
|
||||||
|
# Copyright (C) 2010 Haruyuki Iida
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or
|
||||||
|
# modify it under the terms of the GNU General Public License
|
||||||
|
# as published by the Free Software Foundation; either version 2
|
||||||
|
# of the License, or (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program; if not, write to the Free Software
|
||||||
|
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
-%>
|
||||||
|
|
||||||
|
<%
|
||||||
|
is_target = false
|
||||||
|
|
||||||
|
if project and controller and project.module_enabled?(:code_review)
|
||||||
|
is_target = true
|
||||||
|
is_target = false unless User.current.allowed_to?({:controller => 'code_review', :action => 'update_diff_view'}, project)
|
||||||
|
setting = CodeReviewProjectSetting.find(:first, :conditions => ['project_id = ?', project.id])
|
||||||
|
is_target = false unless setting
|
||||||
|
is_target = false if(setting && setting.tracker_id == nil)
|
||||||
|
action_name = controller.action_name
|
||||||
|
is_target = false unless action_name
|
||||||
|
is_target = false unless (controller.class.name == 'RepositoriesController' or controller.class.name == 'AttachmentsController')
|
||||||
|
if (is_target == true)
|
||||||
|
context = {:project => project, :controller => controller, :requrest => request}
|
||||||
|
%>
|
||||||
|
<% if (controller.class.name == 'AttachmentsController') %>
|
||||||
|
<%= render :partial => 'code_review/change_attachement_view', :locals => context %>
|
||||||
|
<% elsif (action_name == 'show' or action_name == 'revisions') %>
|
||||||
|
<%= render :partial => 'code_review/change_repository_view', :locals => context %>
|
||||||
|
<% elsif (action_name == 'revision') %>
|
||||||
|
<%= render :partial => 'code_review/change_revision_view', :locals => context %>
|
||||||
|
<% elsif (action_name == 'diff' or action_name == 'entry' or action_name == 'annotate')%>
|
||||||
|
<%if (controller.params[:rev].blank? or controller.params[:rev] == 'master')%>
|
||||||
|
<%= render :partial => 'code_review/change_entry_norevision_view', :locals => context %>
|
||||||
|
<% else
|
||||||
|
changeset = @repository.find_changeset_by_name(controller.params[:rev])
|
||||||
|
%>
|
||||||
|
<% unless changeset %>
|
||||||
|
<%= render :partial => 'code_review/change_entry_norevision_view', :locals => context %>
|
||||||
|
<% else
|
||||||
|
parameters = request.parameters
|
||||||
|
rev_to = parameters['rev_to'] unless parameters['rev_to'].blank?
|
||||||
|
review_id = parameters['review_id']
|
||||||
|
rev = parameters['rev']
|
||||||
|
path = parameters['path']
|
||||||
|
|
||||||
|
|
||||||
|
repository_id = @repository.identifier_param if @repository.respond_to?("identifier_param")
|
||||||
|
url = url_for :controller => 'code_review', :action => 'update_diff_view', :id => project, :repository_id => repository_id
|
||||||
|
%>
|
||||||
|
<div id="code_review">
|
||||||
|
</div>
|
||||||
|
<script type="text/javascript">
|
||||||
|
$(document).ready(function(){
|
||||||
|
$('#code_review').load('<%=url%>', {
|
||||||
|
rev: '<%=rev%>',
|
||||||
|
path:'<%=path%>',
|
||||||
|
review_id: '<%=review_id%>',
|
||||||
|
action_type:'<%=action_name%>',
|
||||||
|
rev_to: '<%=rev_to%>'});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
<% end %>
|
||||||
|
|
||||||
|
<% end %>
|
||||||
|
<% end %>
|
||||||
|
<%
|
||||||
|
end
|
||||||
|
end
|
||||||
|
-%>
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,35 @@
|
||||||
|
<%
|
||||||
|
# Code Review plugin for Redmine
|
||||||
|
# Copyright (C) 2010-2012 Haruyuki Iida
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or
|
||||||
|
# modify it under the terms of the GNU General Public License
|
||||||
|
# as published by the Free Software Foundation; either version 2
|
||||||
|
# of the License, or (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program; if not, write to the Free Software
|
||||||
|
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
-%>
|
||||||
|
<%
|
||||||
|
parameters = request.parameters
|
||||||
|
id = parameters[:id].to_i
|
||||||
|
attachment = Attachment.find(id)
|
||||||
|
return '' unless attachment.is_text? or attachment.is_diff?
|
||||||
|
review_id = parameters[:review_id] unless parameters[:review_id].blank?
|
||||||
|
url = url_for :controller => 'code_review', :action => 'update_attachment_view', :id => project
|
||||||
|
-%>
|
||||||
|
<div id="code_review">
|
||||||
|
<div id="review_comment"/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script type="text/javascript">
|
||||||
|
$(document).ready(function(){
|
||||||
|
$('#code_review').load('<%=url%>', {'attachment_id': '<%=id%>', 'review_id': '<%=review_id%>'});
|
||||||
|
});
|
||||||
|
</script>
|
|
@ -0,0 +1,39 @@
|
||||||
|
<%
|
||||||
|
# Code Review plugin for Redmine
|
||||||
|
# Copyright (C) 2010-2011 Haruyuki Iida
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or
|
||||||
|
# modify it under the terms of the GNU General Public License
|
||||||
|
# as published by the Free Software Foundation; either version 2
|
||||||
|
# of the License, or (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program; if not, write to the Free Software
|
||||||
|
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
-%>
|
||||||
|
<%
|
||||||
|
parameters = request.parameters
|
||||||
|
path = parameters['path']
|
||||||
|
rev = parameters['rev']
|
||||||
|
repository_id = @repository.identifier_param if @repository.respond_to?("identifier_param")
|
||||||
|
unless path.blank? or path.empty?
|
||||||
|
changesets = @repository.latest_changesets(path, rev, Setting.repository_log_display_limit.to_i)
|
||||||
|
change = changesets[0]
|
||||||
|
|
||||||
|
if change
|
||||||
|
link = link_to(l(:label_add_review), {:controller => 'code_review',
|
||||||
|
:action => 'forward_to_revision', :id => project, :path => path, :rev => rev, :repository_id => repository_id},
|
||||||
|
:class => 'icon icon-edit')
|
||||||
|
%>
|
||||||
|
|
||||||
|
<script type="text/javascript">
|
||||||
|
make_addreview_link('<%=project.name%>', '<%=link%>');
|
||||||
|
</script>
|
||||||
|
<% end %>
|
||||||
|
|
||||||
|
<% end %>
|
|
@ -0,0 +1,41 @@
|
||||||
|
<%
|
||||||
|
# Code Review plugin for Redmine
|
||||||
|
# Copyright (C) 2010-2012 Haruyuki Iida
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or
|
||||||
|
# modify it under the terms of the GNU General Public License
|
||||||
|
# as published by the Free Software Foundation; either version 2
|
||||||
|
# of the License, or (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program; if not, write to the Free Software
|
||||||
|
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
-%>
|
||||||
|
<%
|
||||||
|
|
||||||
|
if @changesets
|
||||||
|
changeset_ids = ''
|
||||||
|
@changesets.each { |changeset|
|
||||||
|
changeset_ids << changeset.revision
|
||||||
|
changeset_ids << ','
|
||||||
|
}
|
||||||
|
|
||||||
|
repository_id = @repository.identifier_param if @repository.respond_to?("identifier_param")
|
||||||
|
url = url_for :controller => 'code_review', :action => 'update_revisions_view', :id => project, :repository_id => repository_id
|
||||||
|
%>
|
||||||
|
|
||||||
|
<div id="code_review_revisions"></div>
|
||||||
|
|
||||||
|
|
||||||
|
<script type="text/javascript">
|
||||||
|
$(document).ready(function(){
|
||||||
|
$('#code_review_revisions').load('<%=url%>', {changeset_ids: '<%=raw changeset_ids%>'});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<% end %>
|
|
@ -0,0 +1,73 @@
|
||||||
|
<%
|
||||||
|
# Code Review plugin for Redmine
|
||||||
|
# Copyright (C) 2010-2011 Haruyuki Iida
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or
|
||||||
|
# modify it under the terms of the GNU General Public License
|
||||||
|
# as published by the Free Software Foundation; either version 2
|
||||||
|
# of the License, or (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program; if not, write to the Free Software
|
||||||
|
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
-%>
|
||||||
|
<%
|
||||||
|
repository_id = @repository.identifier_param if @repository.respond_to?("identifier_param")
|
||||||
|
if @changeset
|
||||||
|
urlprefix = url_for(:controller => 'repositories', :action => 'revisions', :id => project, :repository_id => repository_id) +
|
||||||
|
'/' + @changeset.identifier + '/entry'
|
||||||
|
%>
|
||||||
|
<div id="code_review_assignments">
|
||||||
|
<%=h l(:review_assignments)%>
|
||||||
|
<% @changeset.code_review_assignments.each do |assignment|
|
||||||
|
issue = assignment.issue %>
|
||||||
|
<%= link_to("##{issue.id} ", {:controller => 'issues', :action => 'show', :id => issue.id},
|
||||||
|
:class => issue.css_classes, :title => "#{issue}(#{issue.status})") %>
|
||||||
|
<% end if @changeset.code_review_assignments %>
|
||||||
|
|
||||||
|
<%= link_to(l(:button_add), {:controller => 'code_review',
|
||||||
|
:action => 'assign', :id=>project,
|
||||||
|
:rev => @changeset.revision,
|
||||||
|
:changeset_id => @changeset.id, :repository_id => repository_id}, :class => 'icon icon-add') %>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script type="text/javascript">
|
||||||
|
$('#changes-legend').after($('#code_review_assignments'));
|
||||||
|
urlprefix = '<%=urlprefix%>';
|
||||||
|
<% @changeset.changes.each{|change| %>
|
||||||
|
var reviewlist = [];
|
||||||
|
<%
|
||||||
|
cnt = 0
|
||||||
|
change.code_reviews.each {|review|
|
||||||
|
issue = review.issue
|
||||||
|
url = link_to('#' + "#{issue.id} #{review.subject}(#{issue.status})",
|
||||||
|
:controller => 'code_review', :action => 'show', :id => project, :review_id => review.id, :repository_id => repository_id)
|
||||||
|
%>
|
||||||
|
var review = new CodeReview(<%=review.id%>);
|
||||||
|
review.url = '<%=url%>';
|
||||||
|
<% if review.is_closed? %>
|
||||||
|
review.is_closed = true;
|
||||||
|
<% end %>
|
||||||
|
reviewlist[<%=cnt%>] = review;
|
||||||
|
<%
|
||||||
|
cnt += 1
|
||||||
|
|
||||||
|
}
|
||||||
|
relative_path = change.relative_path || ""
|
||||||
|
if relative_path[0] != ?/
|
||||||
|
relative_path = '/' + relative_path
|
||||||
|
end
|
||||||
|
escaped_relative_path = relative_path.gsub("'"){"\\'"}
|
||||||
|
%>
|
||||||
|
code_reviews_map['<%=escaped_relative_path-%>'] = reviewlist;
|
||||||
|
<%
|
||||||
|
}
|
||||||
|
%>
|
||||||
|
UpdateRevisionView();
|
||||||
|
</script>
|
||||||
|
<% end %>
|
|
@ -0,0 +1,84 @@
|
||||||
|
<%
|
||||||
|
# Code Review plugin for Redmine
|
||||||
|
# Copyright (C) 2009 Haruyuki Iida
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or
|
||||||
|
# modify it under the terms of the GNU General Public License
|
||||||
|
# as published by the Free Software Foundation; either version 2
|
||||||
|
# of the License, or (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program; if not, write to the Free Software
|
||||||
|
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
-%>
|
||||||
|
<% for journal in journals %>
|
||||||
|
|
||||||
|
<!-- skip initial entry of code review creation -->
|
||||||
|
<% if not journal.initial? %>
|
||||||
|
|
||||||
|
<!-- header and notes/comments -->
|
||||||
|
<%
|
||||||
|
header = <<-HTML
|
||||||
|
<h4>
|
||||||
|
#{authoring journal.created_at, journal.user, :label => :label_updated_time_by}
|
||||||
|
#{content_tag('a', '', :name => "note-#{journal.anchor}")}
|
||||||
|
</h4>
|
||||||
|
|
||||||
|
<div class="profile-wrap">
|
||||||
|
#{avatar(journal.user, :size => "40")}
|
||||||
|
</div>
|
||||||
|
HTML
|
||||||
|
|
||||||
|
if not journal.notes.blank?
|
||||||
|
if User.current.logged?
|
||||||
|
editable = User.current.allowed_to?(:edit_issue_notes, journal.project)
|
||||||
|
if journal.user == User.current
|
||||||
|
editable ||= User.current.allowed_to?(:edit_own_issue_notes, journal.project)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
links = [].tap do |l|
|
||||||
|
if editable
|
||||||
|
l << link_to_in_place_notes_editor(image_tag('edit.png'), "journal-#{journal.id}-notes",
|
||||||
|
{ :controller => 'journals', :action => 'edit', :id => journal },
|
||||||
|
:title => l(:button_edit))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
css_classes = "wiki"
|
||||||
|
css_classes << " editable" if editable
|
||||||
|
|
||||||
|
content = ''
|
||||||
|
content << content_tag('div', links.join(' '), :class => 'contextual') unless links.empty?
|
||||||
|
content << textilizable(journal, :notes)
|
||||||
|
|
||||||
|
header << content_tag("div", content, :id => "journal-#{journal.id}-notes", :class => css_classes)
|
||||||
|
end
|
||||||
|
%>
|
||||||
|
|
||||||
|
<!-- details such as attribute changes -->
|
||||||
|
<%
|
||||||
|
details = ''
|
||||||
|
if journal.details.any?
|
||||||
|
content = journal.details.collect do |detail|
|
||||||
|
if d = journal.render_detail(detail)
|
||||||
|
content_tag("li", d)
|
||||||
|
end
|
||||||
|
end.compact.join(' ')
|
||||||
|
|
||||||
|
details = content_tag("ul", content, :class => "details journal-attributes") unless content.empty?
|
||||||
|
end
|
||||||
|
%>
|
||||||
|
|
||||||
|
<!-- output HTML code -->
|
||||||
|
<%= content_tag "div", "#{header}#{details}",
|
||||||
|
{ :id => "change-#{journal.id}", :class => journal.css_classes } %>
|
||||||
|
|
||||||
|
<% end %>
|
||||||
|
|
||||||
|
<% end %>
|
|
@ -0,0 +1,30 @@
|
||||||
|
<%
|
||||||
|
# Code Review plugin for Redmine
|
||||||
|
# Copyright (C) 2010-2012 Haruyuki Iida
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or
|
||||||
|
# modify it under the terms of the GNU General Public License
|
||||||
|
# as published by the Free Software Foundation; either version 2
|
||||||
|
# of the License, or (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program; if not, write to the Free Software
|
||||||
|
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
-%>
|
||||||
|
<% if @project and @project.module_enabled?('code_review') %>
|
||||||
|
<%
|
||||||
|
baseurl = Redmine::Utils.relative_url_root
|
||||||
|
|
||||||
|
-%>
|
||||||
|
<%= javascript_include_tag(baseurl + "/plugin_assets/redmine_code_review/javascripts/code_review.js") %>
|
||||||
|
<%= javascript_include_tag(baseurl + '/javascripts/jstoolbar/jstoolbar.js') %>
|
||||||
|
<%= javascript_include_tag(baseurl + '/javascripts/jstoolbar/textile.js') %>
|
||||||
|
<%= javascript_include_tag(baseurl + "/javascripts/jstoolbar/lang/jstoolbar-#{@project.current_language}.js") %>
|
||||||
|
<%= stylesheet_link_tag(baseurl + "/plugin_assets/redmine_code_review/stylesheets/code_review.css") %>
|
||||||
|
<%= stylesheet_link_tag(baseurl + "/stylesheets/jstoolbar.css") %>
|
||||||
|
<% end %>
|
|
@ -0,0 +1,56 @@
|
||||||
|
<%#
|
||||||
|
# To change this template, choose Tools | Templates
|
||||||
|
# and open the template in the editor.
|
||||||
|
%>
|
||||||
|
|
||||||
|
<%
|
||||||
|
unless User.current.allowed_to?({:controller => 'code_review', :action => 'show'}, project)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
%>
|
||||||
|
|
||||||
|
<% if issue.code_review %>
|
||||||
|
<%
|
||||||
|
review = issue.code_review
|
||||||
|
%>
|
||||||
|
<tr>
|
||||||
|
<td><b><%= l(:code_review) %>:</b></td>
|
||||||
|
<td colspan="3">
|
||||||
|
<%
|
||||||
|
label = URI.decode("#{review.repository_identifier + ':' if review.repository_identifier}#{review.path}#{'@' + review.revision if review.revision}:line #{review.line}")
|
||||||
|
-%>
|
||||||
|
<%= link_to(label,
|
||||||
|
:controller => 'code_review', :action => 'show', :id => project, :review_id => review.id, :repository_id => review.repository_identifier) %>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<% end %>
|
||||||
|
<% if issue.code_review_assignment %>
|
||||||
|
<%
|
||||||
|
assignment = issue.code_review_assignment
|
||||||
|
repository_id = assignment.repository_identifier
|
||||||
|
%>
|
||||||
|
<tr>
|
||||||
|
<td><b><%= l(:review_assigned_for) %>:</b></td>
|
||||||
|
<td colspan="3">
|
||||||
|
<% if assignment.path %>
|
||||||
|
<%
|
||||||
|
label = URI.decode("#{repository_id + ':' if repository_id}#{assignment.path}#{'@' + assignment.revision if assignment.revision}")
|
||||||
|
-%>
|
||||||
|
<%= link_to(label,
|
||||||
|
:controller => 'code_review', :action => 'show', :id => project, :assignment_id => assignment.id, :repository_id => repository_id) %>
|
||||||
|
<% elsif assignment.revision %>
|
||||||
|
<%
|
||||||
|
repo = project unless repository_id
|
||||||
|
repo ||= assignment.repository
|
||||||
|
%>
|
||||||
|
<%= l(:label_revision) + " "%>
|
||||||
|
<%= link_to_revision(assignment.revision, repo) %>
|
||||||
|
<% elsif assignment.attachment %>
|
||||||
|
<%= link_to(assignment.attachment.filename, :controller => 'attachments', :action => 'show', :id => attachment.id) %>
|
||||||
|
<% end %>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<% end %>
|
||||||
|
|
|
@ -0,0 +1,121 @@
|
||||||
|
<%
|
||||||
|
# Code Review plugin for Redmine
|
||||||
|
# Copyright (C) 2009-2013 Haruyuki Iida
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or
|
||||||
|
# modify it under the terms of the GNU General Public License
|
||||||
|
# as published by the Free Software Foundation; either version 2
|
||||||
|
# of the License, or (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program; if not, write to the Free Software
|
||||||
|
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
-%>
|
||||||
|
|
||||||
|
|
||||||
|
<div class="box">
|
||||||
|
<h2>
|
||||||
|
<%= l(:label_line_number, :line => @review.line) %>
|
||||||
|
</h2>
|
||||||
|
<%= form_for @review,:as => :review,
|
||||||
|
:url => {:controller => 'code_review', :action => 'new', :id=>@project}, :html => {:id => 'review_form'} do |f| %>
|
||||||
|
<%= error_messages_for 'review' %>
|
||||||
|
<%= error_messages_for 'issue' %>
|
||||||
|
<%= error_messages_for 'relation' %>
|
||||||
|
<%= f.hidden_field(:change_id) %>
|
||||||
|
<%= f.hidden_field(:line) %>
|
||||||
|
<%= hidden_field_tag(:action_type, @review.action_type) %>
|
||||||
|
<%= hidden_field_tag(:rev, @review.revision) %>
|
||||||
|
<%= hidden_field_tag(:rev_to, @review.rev_to) %>
|
||||||
|
<%= hidden_field_tag(:path, @review.path) %>
|
||||||
|
<%= hidden_field_tag(:file_count, @review.file_count) %>
|
||||||
|
<%= hidden_field_tag(:attachment_id, @review.attachment_id) %>
|
||||||
|
<%= hidden_field_tag(:repository_id, @repository_id) %>
|
||||||
|
<%= hidden_field_tag(:diff_all, @review.diff_all) %>
|
||||||
|
<p>
|
||||||
|
<label><b><%=h l(:field_subject)%>:</b></label>
|
||||||
|
<%= f.text_field :subject, :size => 70, :required => true %>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<% if @setting.tracker_in_review_dialog %>
|
||||||
|
<p>
|
||||||
|
<label><b><%=h l(:label_tracker) %>:</b></label>
|
||||||
|
<%= select :issue, :tracker_id, @project.trackers.collect {|t| [t.name, t.id]}, :required => true %>
|
||||||
|
<script type="text/javascript">
|
||||||
|
|
||||||
|
$(function(){
|
||||||
|
$('#issue_tracker_id').change(function(){
|
||||||
|
var url = "<%= url_for(:controller => 'code_review', :action => 'new') -%>";
|
||||||
|
url = url + '?' + $('#review_form').serialize();
|
||||||
|
$('#review-form').load(url);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</p>
|
||||||
|
<% end %>
|
||||||
|
<p>
|
||||||
|
<label><b><%=h l(:field_parent_issue)%>:</b></label>
|
||||||
|
<%= f.text_field :parent_id, :size => 10 %>
|
||||||
|
<% if @parent_candidate %>
|
||||||
|
<%= raw l(:label_parent_suggestion, {:issue_id => link_to_issue(@parent_candidate)}) %>
|
||||||
|
<input type="button" value="<%=h l(:general_text_Yes)%>" onclick="$('#review_parent_id').val(<%= @parent_candidate.id %>)"/>
|
||||||
|
<% end %>
|
||||||
|
</p>
|
||||||
|
<% @issue.custom_field_values.each do |value| %>
|
||||||
|
<% next unless value.required? -%>
|
||||||
|
<p><%= custom_field_tag_with_label :issue, value %></p>
|
||||||
|
<% end %>
|
||||||
|
<p>
|
||||||
|
<%= f.text_area :comment,
|
||||||
|
:cols => 30,
|
||||||
|
:rows => 12,
|
||||||
|
:accesskey => accesskey(:edit),
|
||||||
|
:class => 'wiki-edit' %>
|
||||||
|
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<label><b><%=h l(:field_assigned_to) %>:</b></label>
|
||||||
|
<%= select :issue, :assigned_to_id, (@issue.assignable_users.collect {|m| [m.name, m.id]}), :include_blank => true %>
|
||||||
|
</p>
|
||||||
|
<% unless @project.issue_categories.empty? %>
|
||||||
|
<p>
|
||||||
|
<label><b><%=h l(:field_category) %>:</b></label>
|
||||||
|
<%= select :issue, :category_id, (@project.issue_categories.collect {|c| [c.name, c.id]}), :include_blank => true %>
|
||||||
|
</p>
|
||||||
|
<% end %>
|
||||||
|
<% unless @issue.assignable_versions.empty? %>
|
||||||
|
<p>
|
||||||
|
<label><b><%=h l(:field_fixed_version) %>:</b></label>
|
||||||
|
<%= select :issue, :fixed_version_id, (@issue.assignable_versions.collect {|v| [v.name, v.id]}), :include_blank => true, :selected => @default_version_id %>
|
||||||
|
</p>
|
||||||
|
<% end %>
|
||||||
|
|
||||||
|
<%
|
||||||
|
@allowed_statuses = @issue.new_statuses_allowed_to(User.current)
|
||||||
|
-%>
|
||||||
|
<% if @issue.new_record? || @allowed_statuses.any? %>
|
||||||
|
<p><%= f.select :status_id, (@allowed_statuses.collect {|p| [p.name, p.id]}), :required => true %></p>
|
||||||
|
<% else %>
|
||||||
|
<p><label><%= l(:field_status) %></label> <%= h(@issue.status.name) %></p>
|
||||||
|
<% end %>
|
||||||
|
<p>
|
||||||
|
<%
|
||||||
|
submit_url = url_for(:controller => 'code_review', :action => 'new', :id=>@project)
|
||||||
|
%>
|
||||||
|
<%= button_to_function l(:button_apply), "$('#review-form').load('#{submit_url}', $('#review_form').serialize2json())" %>
|
||||||
|
|
||||||
|
<input type="button" value="<%=h l(:button_cancel) %> " onclick="javascript:hideForm();"/>
|
||||||
|
<%= preview_link({ :controller => 'code_review', :action => 'preview', :id => @project}, 'review_form') %>
|
||||||
|
</p>
|
||||||
|
<div id="preview" class="wiki"></div>
|
||||||
|
<%= wikitoolbar_for 'review_comment' %>
|
||||||
|
<% end %>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,36 @@
|
||||||
|
<%
|
||||||
|
# Code Review plugin for Redmine
|
||||||
|
# Copyright (C) 2009 Haruyuki Iida
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or
|
||||||
|
# modify it under the terms of the GNU General Public License
|
||||||
|
# as published by the Free Software Foundation; either version 2
|
||||||
|
# of the License, or (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program; if not, write to the Free Software
|
||||||
|
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
-%>
|
||||||
|
<p class="author">
|
||||||
|
|
||||||
|
<%= authoring reply.created_on, reply.user %>.
|
||||||
|
</p>
|
||||||
|
<%= avatar(reply.user, :size => "32") %>
|
||||||
|
<ul>
|
||||||
|
<% for detail in reply.details %>
|
||||||
|
<li><%= show_detail(detail) %></li>
|
||||||
|
<% end %>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
|
||||||
|
<div class="wiki">
|
||||||
|
<%= textilizable reply, :notes %>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<hr/>
|
|
@ -0,0 +1,187 @@
|
||||||
|
<%
|
||||||
|
# Code Review plugin for Redmine
|
||||||
|
# Copyright (C) 2009-2012 Haruyuki Iida
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or
|
||||||
|
# modify it under the terms of the GNU General Public License
|
||||||
|
# as published by the Free Software Foundation; either version 2
|
||||||
|
# of the License, or (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program; if not, write to the Free Software
|
||||||
|
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
-%>
|
||||||
|
<div class="code-review-dialog" id="code-review-dialog-<%= @review.id%>">
|
||||||
|
|
||||||
|
<div class="code_review_body">
|
||||||
|
|
||||||
|
<!-- flash -->
|
||||||
|
<%= error_messages_for 'review' -%>
|
||||||
|
<%= error_messages_for 'reply' -%>
|
||||||
|
<% if @notice -%>
|
||||||
|
<div class="flash notice"><%= @notice -%></div>
|
||||||
|
<% end -%>
|
||||||
|
<% if @error -%>
|
||||||
|
<div class="flash error"><%= @error -%></div>
|
||||||
|
<% end -%>
|
||||||
|
|
||||||
|
<!-- code review view -->
|
||||||
|
<div class="code_review_viewer issue">
|
||||||
|
|
||||||
|
<!-- toolbar -->
|
||||||
|
<div class="contextual">
|
||||||
|
<% if authorize_for('code_review', 'update') -%>
|
||||||
|
<%= link_to_function l(:button_update), "$('#update-form-#{@review.id}').show();return false;", :class => 'icon icon-edit' %>
|
||||||
|
<% end %>
|
||||||
|
<% if authorize_for('code_review', 'destroy') -%>
|
||||||
|
<%= link_to(l(:button_delete),
|
||||||
|
{:controller => 'code_review',
|
||||||
|
:action => 'destroy',
|
||||||
|
:id => @project,
|
||||||
|
:review_id => @review},
|
||||||
|
:update => "show_review_#{@review.id}",
|
||||||
|
:remote => true,
|
||||||
|
:confirm => l(:text_are_you_sure),
|
||||||
|
:success => "deleteReview(#{@review.id})",
|
||||||
|
:class => 'icon icon-del') %>
|
||||||
|
<% end -%>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- title -->
|
||||||
|
<h2>
|
||||||
|
<%= link_to h(@issue.tracker.name) + ' #' +@issue.id.to_s + ' (' + h(@review.issue.status) + ')',
|
||||||
|
:controller => 'issues', :action => 'show', :id => @review.issue.id %>:
|
||||||
|
<br />
|
||||||
|
<%=h @review.subject %>
|
||||||
|
</h2>
|
||||||
|
|
||||||
|
<!-- author and creation time -->
|
||||||
|
<p class="author">
|
||||||
|
<%= avatar(@review.user, :size => "64") %>
|
||||||
|
<br />
|
||||||
|
<%= authoring @review.created_at, @review.user %>.
|
||||||
|
<%= l(:label_updated_time, distance_of_time_in_words(Time.now, @review.updated_at)) + '.' if @review.created_at != @review.updated_at %>
|
||||||
|
</p>
|
||||||
|
<hr />
|
||||||
|
|
||||||
|
<!-- review comment -->
|
||||||
|
<div class="wiki">
|
||||||
|
<%= textilizable @review, :comment %>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- review comment edit form -->
|
||||||
|
<div class="box" id="update-form-<%= @review.id %>" style="display:none;">
|
||||||
|
<%
|
||||||
|
review_form_id = "review_form_#{@review.id}"
|
||||||
|
-%>
|
||||||
|
<%= form_for :review,
|
||||||
|
:url => {:controller => 'code_review',
|
||||||
|
:action => 'update',
|
||||||
|
:id => @project},
|
||||||
|
:update => "show_review_#{@review.id}",
|
||||||
|
:html => {:id => review_form_id} do |f| %>
|
||||||
|
<%= f.hidden_field :lock_version %>
|
||||||
|
<%= hidden_field :issue, :lock_version%>
|
||||||
|
<%= hidden_field_tag :review_id, @review.id %>
|
||||||
|
<p>
|
||||||
|
<label><b><%=h l(:field_subject)%>:</b></label>
|
||||||
|
<%= f.text_field :subject, :size => 70, :value => @review.subject%>
|
||||||
|
</p>
|
||||||
|
<% if @allowed_statuses and @allowed_statuses.any? %>
|
||||||
|
<p>
|
||||||
|
<label><b><%=h l(:field_status)%>:</b></label>
|
||||||
|
<%= f.select :status_id, (@allowed_statuses.collect {|p| [p.name, p.id]}), :required => true %>
|
||||||
|
</p>
|
||||||
|
<% end %>
|
||||||
|
<p>
|
||||||
|
<%= f.text_area :comment,
|
||||||
|
:cols => 30,
|
||||||
|
:rows => 10,
|
||||||
|
:accesskey => accesskey(:edit),
|
||||||
|
:class => 'wiki-edit',
|
||||||
|
:id => 'review_comment_' + @review.id.to_s %>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<%
|
||||||
|
submit_url = url_for(:controller => 'code_review', :action => 'update', :id => @project)
|
||||||
|
-%>
|
||||||
|
<%= button_to_function l(:button_apply), "$('#show_review_#{@review.id}').load('#{submit_url}', $('##{review_form_id}').serialize())" %>
|
||||||
|
<input type="button" value="<%=h l(:button_cancel) %>" onclick='$("#review_form_<%= @review.id %>").hide();' />
|
||||||
|
<%= link_to_function l(:label_preview), "$('#preview_#{@review.id}').load('#{url_for(:controller => 'code_review', :action => 'preview', :id => @project)}', $('##{review_form_id}').serialize())" %>
|
||||||
|
</p>
|
||||||
|
<div id="preview_<%= @review.id%>" class="wiki"></div>
|
||||||
|
<%= wikitoolbar_for 'review_comment_' + @review.id.to_s %>
|
||||||
|
<% end %>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- review replies -->
|
||||||
|
<% journals = @review.issue.journals.sort {|a, b| a.id <=> b.id } %>
|
||||||
|
<% if respond_to?('render_journal') %>
|
||||||
|
<% # ChiliProject -%>
|
||||||
|
<% if journals.length > 0 %>
|
||||||
|
<div id="history">
|
||||||
|
<h3 class="rounded-background"><%= l(:label_history) %></h3>
|
||||||
|
<%= render :partial => 'history', :locals => { :issue => @review.issue, :journals => journals } %>
|
||||||
|
</div>
|
||||||
|
<% end %>
|
||||||
|
<% else %>
|
||||||
|
<% # Redmine -%>
|
||||||
|
<% if journals.length > 0 %>
|
||||||
|
<h3><%= l(:label_history) %></h3>
|
||||||
|
<% end %>
|
||||||
|
<%= render :partial => 'reply', :collection => journals %>
|
||||||
|
<% end %>
|
||||||
|
|
||||||
|
<!-- reply form -->
|
||||||
|
<% if authorize_for('code_review', 'reply') -%>
|
||||||
|
<p>
|
||||||
|
<%= toggle_link l(:button_reply), "reply_#{@review.id}", :focus => 'reply_comment_' + @review.id.to_s %>
|
||||||
|
</p>
|
||||||
|
<%
|
||||||
|
message_form_id = "message-form-#{@review.id}"
|
||||||
|
-%>
|
||||||
|
<div id="reply_<%= @review.id %>" style="display:none;" class="box">
|
||||||
|
<%= form_for @reply, :as => :reply, :url => {:action => 'reply', :id => @project, :review_id => @review.id}, :html => {:id => message_form_id} do |f| %>
|
||||||
|
<%= hidden_field_tag :review_id, @review.id %>
|
||||||
|
<%= hidden_field :review, :lock_version%>
|
||||||
|
<%= hidden_field :issue, :lock_version%>
|
||||||
|
<% if @allowed_statuses and @allowed_statuses.any? %>
|
||||||
|
<p>
|
||||||
|
<label><%=h l(:field_status) %>:</label>
|
||||||
|
<% # select :review, :status, {l(:label_review_closed) => CodeReview::STATUS_CLOSED, l(:label_review_open) => CodeReview::STATUS_OPEN} %>
|
||||||
|
<%= select :review, :status_id, (@allowed_statuses.collect {|p| [p.name, p.id]}), :required => true %>
|
||||||
|
</p>
|
||||||
|
<% end %>
|
||||||
|
<p>
|
||||||
|
<%= f.text_area :comment,
|
||||||
|
:cols => 30,
|
||||||
|
:rows => 10,
|
||||||
|
:accesskey => accesskey(:edit),
|
||||||
|
:class => 'wiki-edit',
|
||||||
|
:id => 'reply_comment_' + @review.id.to_s %>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<%
|
||||||
|
submit_url = url_for(:controller => 'code_review', :action => 'reply', :id => @project)
|
||||||
|
-%>
|
||||||
|
<%= button_to_function l(:button_apply), "$('#show_review_#{@review.id}').load('#{submit_url}', $('##{message_form_id}').serialize())" %>
|
||||||
|
<%
|
||||||
|
reply_preview_id = "reply_preview_#{@review.id}"
|
||||||
|
-%>
|
||||||
|
<%= link_to_function l(:label_preview), "$('##{reply_preview_id}').load('#{url_for(:controller => 'code_review', :action => 'preview', :id => @project)}', $('##{message_form_id}').serialize())" %>
|
||||||
|
</p>
|
||||||
|
<div id="<%= reply_preview_id %>" class="wiki"></div>
|
||||||
|
<%= wikitoolbar_for 'reply_comment_' + @review.id.to_s %>
|
||||||
|
<% end %>
|
||||||
|
</div>
|
||||||
|
<% end %>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
|
@ -0,0 +1,24 @@
|
||||||
|
<div id="error_message_div">
|
||||||
|
<h1>Error</h1>
|
||||||
|
|
||||||
|
<p>change not found.</p>
|
||||||
|
|
||||||
|
@path = '<%=h @path %>'<br/>
|
||||||
|
@changeset = <%=h @changeset %><br/>
|
||||||
|
@rev = <%=h @rev %><br/>
|
||||||
|
<% if @changeset %>
|
||||||
|
<ul>
|
||||||
|
<% for change in @changeset.changes do%>
|
||||||
|
<li>
|
||||||
|
'<%=h change.path%>'
|
||||||
|
</li>
|
||||||
|
<% end %>
|
||||||
|
</ul>
|
||||||
|
<% end %>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
var innerhtml = $('content').innerHTML;
|
||||||
|
$('content').innerHTML = $('error_message_div').innerHTML + innerhtml;
|
||||||
|
$('error_message_div').innerHTML = "";
|
||||||
|
</script>
|
|
@ -0,0 +1,77 @@
|
||||||
|
<%
|
||||||
|
# Code Review plugin for Redmine
|
||||||
|
# Copyright (C) 2009-2012 Haruyuki Iida
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or
|
||||||
|
# modify it under the terms of the GNU General Public License
|
||||||
|
# as published by the Free Software Foundation; either version 2
|
||||||
|
# of the License, or (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program; if not, write to the Free Software
|
||||||
|
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
-%>
|
||||||
|
|
||||||
|
<div class="code_review">
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="review-form-frame">
|
||||||
|
<div id="review-form">
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="code-review-assign-form" />
|
||||||
|
|
||||||
|
<div id="code-review-assign-link" style="text-align: right;">
|
||||||
|
<%
|
||||||
|
change_id = ''
|
||||||
|
change_id = @change.id if @change
|
||||||
|
assignments = @change.code_review_assignments if @change
|
||||||
|
attachment_id = @attachment.id if @attachment
|
||||||
|
assignments = @attachment.code_review_assignments if @attachment
|
||||||
|
escaped_path = @path.gsub("'"){"\\'"} if @path
|
||||||
|
-%>
|
||||||
|
|
||||||
|
<%= raw show_assignments assignments, @project, {:action_type => @action_type, :rev => @rev, :rev_to => @rev_to, :path => @path, :change_id => change_id, :attachment_id => attachment_id} -%>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script type="text/javascript">
|
||||||
|
repository_id = "<%= @repository_id %>";
|
||||||
|
add_form_title = "<%= l(:label_add_review) %>";
|
||||||
|
review_dialog_title = "<%= l(:code_review) %>";
|
||||||
|
var addReviewUrl = '<%= url_for :controller => 'code_review', :action => 'new', :id => @project %>';
|
||||||
|
var is_readonly = true;
|
||||||
|
<% if authorize_for('code_review', 'new') -%>
|
||||||
|
is_readonly = false;
|
||||||
|
<% end %>
|
||||||
|
var is_diff = false;
|
||||||
|
<% if @action_type == 'diff' or (@attachment and @attachment.is_diff?) -%>
|
||||||
|
is_diff = true;
|
||||||
|
<% end %>
|
||||||
|
action_type = '<%= @action_type %>';
|
||||||
|
rev = '<%= @rev %>';
|
||||||
|
rev_to = '<%= @rev_to %>';
|
||||||
|
path = '<%= escaped_path -%>';
|
||||||
|
|
||||||
|
setAddReviewButton(addReviewUrl, '<%= @change.id if @change %>', '<%= image_tag('edit.png', :alt => l(:label_add_review), :title => l(:label_add_review)) %>', is_readonly, is_diff, '<%= @attachment_id%>' );
|
||||||
|
|
||||||
|
showReviewUrl = '<%= url_for :controller => 'code_review', :action => 'show', :id=>@project %>';
|
||||||
|
showReviewImageTag = '<%= image_tag('review.png', :plugin => 'redmine_code_review', :alt => l(:label_show_review), :title => l(:label_show_review)) %>';
|
||||||
|
showClosedReviewImageTag = '<%= image_tag('closed_review.png', :plugin => 'redmine_code_review', :alt => l(:label_show_review), :title => l(:label_show_review)) %>';
|
||||||
|
|
||||||
|
<% for review in @reviews do %>
|
||||||
|
setShowReviewButton(<%= review.line %>, <%= review.id %>, <%= review.is_closed? %>, <%= review.file_count %> );
|
||||||
|
<% end %>
|
||||||
|
|
||||||
|
<% if @show_review_id -%>
|
||||||
|
popupReview(<%= @show_review_id %>);
|
||||||
|
<% end -%>
|
||||||
|
$('#content table.filecontent:first').before($('#code-review-assign-link'));
|
||||||
|
</script>
|
|
@ -0,0 +1,49 @@
|
||||||
|
<%#
|
||||||
|
# Code Review plugin for Redmine
|
||||||
|
# Copyright (C) 2009-2011 Haruyuki Iida
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or
|
||||||
|
# modify it under the terms of the GNU General Public License
|
||||||
|
# as published by the Free Software Foundation; either version 2
|
||||||
|
# of the License, or (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program; if not, write to the Free Software
|
||||||
|
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
%>
|
||||||
|
|
||||||
|
<script type="text/javascript">
|
||||||
|
<% @changesets.each do |changeset| %>
|
||||||
|
<%
|
||||||
|
if changeset.review_count > 0
|
||||||
|
progress = '<span style="white-space: nowrap">' + progress_bar([changeset.closed_review_pourcent, changeset.completed_review_pourcent],
|
||||||
|
:width => '60px',
|
||||||
|
:legend => "#{changeset.closed_review_count}/#{changeset.review_count} #{l(:label_closed_issues)}") + '</span>'
|
||||||
|
elsif changeset.assignment_count > 0
|
||||||
|
if (changeset.open_assignment_count > 0)
|
||||||
|
progress = '<p class="progress-info" style="white-space: nowrap">' + l(:code_review_assigned) + '</p>'
|
||||||
|
else
|
||||||
|
progress = '<p class="progress-info" style="white-space: nowrap">' + l(:code_review_reviewed) + '</p>'
|
||||||
|
end
|
||||||
|
|
||||||
|
else
|
||||||
|
progress = '<p class="progress-info" style="white-space: nowrap;"><span style="white-space: nowrap;">' + l(:lable_no_code_reviews) + '</span>:<span style="white-space: nowrap;">' + link_to(l(:label_assign_review), {:controller => 'code_review',
|
||||||
|
:action => 'assign', :id=>@project,
|
||||||
|
:rev => changeset.revision,
|
||||||
|
:changeset_id => changeset.id}) + '</span></p>'
|
||||||
|
end
|
||||||
|
%>
|
||||||
|
|
||||||
|
var count = new ReviewCount(<%= changeset.review_count %>, <%= changeset.open_review_count %>, '<%= raw progress %>');
|
||||||
|
|
||||||
|
review_counts['revision_<%=changeset.identifier %>'] = count;
|
||||||
|
<% end %>
|
||||||
|
UpdateRepositoryView('<%=l(:code_reviews)%>');
|
||||||
|
</script>
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,101 @@
|
||||||
|
<%
|
||||||
|
# Code Review plugin for Redmine
|
||||||
|
# Copyright (C) 2009-2012 Haruyuki Iida
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or
|
||||||
|
# modify it under the terms of the GNU General Public License
|
||||||
|
# as published by the Free Software Foundation; either version 2
|
||||||
|
# of the License, or (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program; if not, write to the Free Software
|
||||||
|
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
-%>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
function change_option(flag) {
|
||||||
|
var url = "<%= raw url_for(:controller => 'code_review', :action=>'index', :id => @project) %>";
|
||||||
|
$('#content').load(url, {'show_closed': flag});
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<div id="code_review_list">
|
||||||
|
<h2>
|
||||||
|
<%=h l(:code_reviews) %>
|
||||||
|
</h2>
|
||||||
|
|
||||||
|
<% if @all_review_count > 0 %>
|
||||||
|
<p>
|
||||||
|
<%= form_tag({:controller => 'code_review', :action=>'index', :id => @project}, :id => 'optionform') do %>
|
||||||
|
<%= check_box_tag 'show_closed', 'true', @show_closed, :onchange => "change_option($('#show_closed').is(':checked'));"%> <%=h l(:label_show_closed_reviews) %>
|
||||||
|
<% end %>
|
||||||
|
<%# observe_field 'show_closed', :with => 'show_closed', :update => 'content' %>
|
||||||
|
</p>
|
||||||
|
<% end %>
|
||||||
|
|
||||||
|
<% if @reviews == nil or @reviews.length == 0 %>
|
||||||
|
<p class="nodata"><%= l(:label_no_data) %></p>
|
||||||
|
<% else %>
|
||||||
|
|
||||||
|
|
||||||
|
<table class="list">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<%= sort_header_tag "#{Issue.table_name}.id", :caption => '#' %>
|
||||||
|
<%= sort_header_tag "#{Issue.table_name}.status_id", :caption => l(:field_status)%>
|
||||||
|
<%= sort_header_tag "#{Issue.table_name}.subject", :caption => l(:field_subject)%>
|
||||||
|
<%= sort_header_tag 'path', :caption => l(:label_code_path)%>
|
||||||
|
<th>
|
||||||
|
<%=h l(:label_code_line)%>
|
||||||
|
</th>
|
||||||
|
<%= sort_header_tag "#{Changeset.table_name}.revision", :caption => l(:label_revision)%>
|
||||||
|
<%= sort_header_tag "#{Changeset.table_name}.committer", :caption => l(:label_code_author)%>
|
||||||
|
<%= sort_header_tag 'user_id', :caption => l(:label_code_reviewer)%>
|
||||||
|
<%= sort_header_tag 'updated_at', :caption => l(:label_date) %>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<% for review in @reviews %>
|
||||||
|
<tr class="<%= cycle 'odd', 'even' %>">
|
||||||
|
<td>
|
||||||
|
<%= link_to review.issue.id.to_s, {:controller => 'issues', :action => 'show',
|
||||||
|
:id => review.issue.id}, :title => review.issue.subject %>
|
||||||
|
</td>
|
||||||
|
|
||||||
|
<td class="status">
|
||||||
|
<%=h review.issue.status %>
|
||||||
|
</td>
|
||||||
|
<td class="subject">
|
||||||
|
<%=h review.issue.subject %>
|
||||||
|
</td>
|
||||||
|
<td class="path">
|
||||||
|
<%
|
||||||
|
review_path = URI.decode(review.path)
|
||||||
|
codepath = review_path
|
||||||
|
if (review_path.length > 55)
|
||||||
|
codepath = review_path[0, 15] + '...' + review_path[review_path.length - 35, 35]
|
||||||
|
end
|
||||||
|
-%>
|
||||||
|
<%= link_to(raw(codepath), {:controller => 'code_review', :action => 'show', :id => @project, :review_id => review.id}, :title => review_path) -%>
|
||||||
|
</td>
|
||||||
|
<td><%=h review.line %></td>
|
||||||
|
<td><%=h review.revision %></td>
|
||||||
|
<td><%=h review.committer %></td>
|
||||||
|
<td><%=h review.user.name %></td>
|
||||||
|
<td><%=h format_time(review.created_at) %></td>
|
||||||
|
</tr>
|
||||||
|
<% end %>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
<p class="pagination"><%= pagination_links_full @review_pages, @review_count %></p>
|
||||||
|
|
||||||
|
<% end %>
|
||||||
|
|
||||||
|
<% content_for :header_tags do %>
|
||||||
|
<%= stylesheet_link_tag "code_review.css", :plugin => "redmine_code_review", :media => "screen" %>
|
||||||
|
<% end %>
|
||||||
|
</div>
|
|
@ -0,0 +1,117 @@
|
||||||
|
<%
|
||||||
|
# Code Review plugin for Redmine
|
||||||
|
# Copyright (C) 2009-2012 Haruyuki Iida
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or
|
||||||
|
# modify it under the terms of the GNU General Public License
|
||||||
|
# as published by the Free Software Foundation; either version 2
|
||||||
|
# of the License, or (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program; if not, write to the Free Software
|
||||||
|
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
-%>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<label><%=h l(:label_auto_assignment_filters)%></label>
|
||||||
|
<%= check_box_tag "auto_assign[filter_enabled]", true, @auto_assign.filter_enabled?, :onchange => 'setAutoAssignSettingFiltersEnable();' %><%=h l(:button_activate)%>
|
||||||
|
|
||||||
|
</p>
|
||||||
|
<div id="auto_assignment_filter_form" style="display: <%= @auto_assign.filter_enabled? ? 'true' : 'none'%>;">
|
||||||
|
<div style="padding: 5px 0 8px 180px;">
|
||||||
|
<div class="contextual">
|
||||||
|
<%= link_to_function(l(:button_add), "$('#add_filter_form').show('blind');", :class => 'icon icon-add') %>
|
||||||
|
</div>
|
||||||
|
<table class="list">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th style="width: 1em; text-align: right;">#</th>
|
||||||
|
<th style="width: 8em;"><%=h l(:auto_assign_filter_assign)%>/<%=h l(:auto_assign_filter_drop) %></th>
|
||||||
|
<th><%=h l(:auto_assign_filter_expression)%> </th>
|
||||||
|
<th><%=h l(:button_sort) %> </th>
|
||||||
|
<th></th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<% @auto_assign.filters.each_with_index do |filter, i| -%>
|
||||||
|
<% tr_class = cycle('odd', 'even') -%>
|
||||||
|
<tr class="<%= tr_class %>" id="auto_assign_tr_<%= i%>">
|
||||||
|
<td style="text-align: right"><%= i + 1 %>
|
||||||
|
<%= hidden_field_tag "auto_assign[filters][#{i}][accept]", filter.accept? %>
|
||||||
|
<%= hidden_field_tag "auto_assign[filters][#{i}][expression]", filter.expression %>
|
||||||
|
<%= hidden_field_tag "auto_assign[filters][#{i}][order]", (i+1) * 10 %>
|
||||||
|
</td>
|
||||||
|
<td style="text-align: center"><%= filter.accept? ? l(:auto_assign_filter_assign) : l(:auto_assign_filter_drop)%> </td>
|
||||||
|
<td style="text-align: center"><%= filter.expression %></td>
|
||||||
|
<td align="center" style="width:15%;">
|
||||||
|
<%
|
||||||
|
name = 'auto_assign_filter'
|
||||||
|
url = {:controller => 'code_review_settings', :action => 'sort', :id => @project, "#{name}[num]" => i}
|
||||||
|
-%>
|
||||||
|
<%=
|
||||||
|
link_to(image_tag('2uparrow.png', :alt => l(:label_sort_highest)), :remote => true, :url => url.merge({"#{name}[move_to]" => 'highest'}), :method => :post, :title => l(:label_sort_highest), :update => 'auto_assignment_filters', :submit => 'code_review_form') +
|
||||||
|
link_to(image_tag('1uparrow.png', :alt => l(:label_sort_higher)), :remote => true, :url => url.merge({"#{name}[move_to]" => 'higher'}), :method => :post, :title => l(:label_sort_higher), :update => 'auto_assignment_filters', :submit => 'code_review_form') +
|
||||||
|
link_to(image_tag('1downarrow.png', :alt => l(:label_sort_lower)), :remote => true, :url => url.merge({"#{name}[move_to]" => 'lower'}), :method => :post, :title => l(:label_sort_lower), :update => 'auto_assignment_filters', :submit => 'code_review_form') +
|
||||||
|
link_to(image_tag('2downarrow.png', :alt => l(:label_sort_lowest)), :remote => true, :url => url.merge({"#{name}[move_to]" => 'lowest'}), :method => :post, :title => l(:label_sort_lowest), :update => 'auto_assignment_filters', :submit => 'code_review_form')
|
||||||
|
-%>
|
||||||
|
|
||||||
|
</td>
|
||||||
|
<td class="buttons">
|
||||||
|
<span class="icon icon-del">
|
||||||
|
<%= link_to_function(l(:button_delete), "$('#auto_assign_tr_#{i}').remove();")%>
|
||||||
|
</span><span class="icon icon-edit">
|
||||||
|
<%= link_to_function(l(:button_edit), "$('#auto_assign_tr_#{i}').hide();$('#auto_assign_edit_tr_#{i}').show()")%>
|
||||||
|
</span>
|
||||||
|
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr class="<%= tr_class %>" id="auto_assign_edit_tr_<%= i%>" style="display: none;">
|
||||||
|
<td style="text-align: right">
|
||||||
|
<%= i + 1 %>
|
||||||
|
</td>
|
||||||
|
<td style="text-align: center">
|
||||||
|
<%= hidden_field_tag "auto_assign_edit_filter[#{i}][order]", (i + 1) * 10 %>
|
||||||
|
<%= select_tag("auto_assign_edit_filter[#{i}][accept]",
|
||||||
|
options_for_select([[l(:auto_assign_filter_assign), true], [l(:auto_assign_filter_drop), false]], filter.accept?)) %>
|
||||||
|
</td>
|
||||||
|
<td><%= text_field_tag("auto_assign_edit_filter[#{i}][expression]", filter.expression, :size => 60)%>
|
||||||
|
</td>
|
||||||
|
<td></td>
|
||||||
|
<td style="white-space: nowrap">
|
||||||
|
<%= button_to_function(l(:button_apply), "update_assign_filter(#{i})", :condition => "is_valid_expression($('#auto_assign_edit_filter_#{i}_expression'))") %>
|
||||||
|
<%= button_to_function(l(:button_cancel), "$('#auto_assign_tr_#{i}').show();$('#auto_assign_edit_tr_#{i}').hide()") %>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<% end -%>
|
||||||
|
<tr id="add_filter_form" style="display: none;">
|
||||||
|
<td style="text-align: right"><%= @auto_assign.filters.length + 1 %> </td>
|
||||||
|
<td>
|
||||||
|
<%= hidden_field_tag 'auto_assign_add_filter[order]', 999999999 %>
|
||||||
|
<%= select_tag('auto_assign_add_filter[accept]',
|
||||||
|
options_for_select([[l(:auto_assign_filter_assign), true], [l(:auto_assign_filter_drop), false]])) %>
|
||||||
|
</td>
|
||||||
|
<td><%= text_field_tag('auto_assign_add_filter[expression]', '', :size => 60)%>
|
||||||
|
</td>
|
||||||
|
<td></td>
|
||||||
|
<td style="white-space: nowrap;">
|
||||||
|
<%= button_to_function(l(:button_apply), "add_assign_filter()") %>
|
||||||
|
<%= button_to_function(l(:button_cancel), "$('#add_filter_form').hide()") %>
|
||||||
|
|
||||||
|
</td>
|
||||||
|
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<p>
|
||||||
|
<label><%=h l(:label_default)%></label>
|
||||||
|
<%= select(:auto_assign, :accept_for_default, [[l(:auto_assign_filter_assign), true], [l(:auto_assign_filter_drop), false]]) %>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
</div>
|
|
@ -0,0 +1,163 @@
|
||||||
|
<%
|
||||||
|
# Code Review plugin for Redmine
|
||||||
|
# Copyright (C) 2010-2012 Haruyuki Iida
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or
|
||||||
|
# modify it under the terms of the GNU General Public License
|
||||||
|
# as published by the Free Software Foundation; either version 2
|
||||||
|
# of the License, or (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program; if not, write to the Free Software
|
||||||
|
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
-%>
|
||||||
|
<div id="code_review_settings">
|
||||||
|
<script type="text/javascript">
|
||||||
|
function setAutoAssignSettingFormEnable() {
|
||||||
|
var form = $('#cr_auto_assign_settings');
|
||||||
|
var flag = $('#auto_assign_enabled').is(':checked');
|
||||||
|
if (flag) {
|
||||||
|
form.show('blind');
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
form.hide('blind');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function setAutoAssignSettingFiltersEnable() {
|
||||||
|
var form = $('#auto_assignment_filter_form');
|
||||||
|
var flag = $('#auto_assign_filter_enabled').is(':checked');
|
||||||
|
if (flag) {
|
||||||
|
form.show('blind');
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
form.hide('blind');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function is_valid_expression(field) {
|
||||||
|
var text = field[0].value;
|
||||||
|
if (text == '') {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
new RegExp(text);
|
||||||
|
}
|
||||||
|
catch (e) {
|
||||||
|
alert(e);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function add_assign_filter() {
|
||||||
|
if (!is_valid_expression($('#auto_assign_add_filter_expression'))) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
var url = '<%=url_for(:controller => 'code_review_settings', :action => 'add_filter', :id => @project) %>';
|
||||||
|
var args = $('#code_review_form').serialize2json();
|
||||||
|
$('#auto_assignment_filters').load(url, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
function update_assign_filter(num) {
|
||||||
|
if (!is_valid_expression($('#auto_assign_edit_filter_' + num + '_expression'))) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
var url = '<%=url_for(:controller => 'code_review_settings', :action => 'edit_filter', :id => @project) %>';
|
||||||
|
var args = $('#code_review_form').serialize2json();
|
||||||
|
args['num'] = num;
|
||||||
|
$('#auto_assignment_filters').load(url, args);
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<%
|
||||||
|
@code_review_setting = CodeReviewProjectSetting.find_or_create(@project)
|
||||||
|
%>
|
||||||
|
|
||||||
|
<%= labelled_form_for :setting, @code_review_setting,
|
||||||
|
:url => {:controller => 'code_review_settings',
|
||||||
|
:action => 'update', :id => @project, :tab => 'code_review',
|
||||||
|
:partial => 'code_review_settings/update',
|
||||||
|
:setting_id => @code_review_setting.id}, :html => {:id => 'code_review_form'} do |f| %>
|
||||||
|
<%= error_messages_for 'code_review_setting' %>
|
||||||
|
<div class="box">
|
||||||
|
<%= f.hidden_field :lock_version %>
|
||||||
|
<p><%= f.check_box :tracker_in_review_dialog %></p>
|
||||||
|
|
||||||
|
<b><%=h l(:select_tracker_for_code_reviews)%>:</b>
|
||||||
|
<p><%= f.select :tracker_id, @project.trackers.collect {|t| [t.name, t.id]}, :required => true %></p>
|
||||||
|
|
||||||
|
<b><%=h l(:select_tracker_for_code_review_assignment)%>:</b>
|
||||||
|
<p><%= f.select :assignment_tracker_id, @project.trackers.collect {|t| [t.name, t.id]}, :required => true %></p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<%= f.check_box :hide_code_review_tab %>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<label><%=h l(:label_if_revision_has_issues)%>:</label>
|
||||||
|
<%= f.radio_button(:auto_relation, CodeReviewProjectSetting::AUTORELATION_TYPE_RELATES) %>
|
||||||
|
<%=h l(:label_review_issue_relates) %>
|
||||||
|
|
||||||
|
<%= f.radio_button(:auto_relation, CodeReviewProjectSetting::AUTORELATION_TYPE_BLOCKS) %>
|
||||||
|
<%=h l(:label_review_issue_blocks) %>
|
||||||
|
|
||||||
|
<%= f.radio_button(:auto_relation, CodeReviewProjectSetting::AUTORELATION_TYPE_NONE) %>
|
||||||
|
<%=h l(:label_review_issue_do_nothing) %>
|
||||||
|
|
||||||
|
</p>
|
||||||
|
<hr/>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<%
|
||||||
|
@auto_assign = @code_review_setting.auto_assign_settings
|
||||||
|
@auto_assign.subject = l(:code_review_requrest) if @auto_assign.subject.blank?
|
||||||
|
-%>
|
||||||
|
<label><%=h l(:label_auto_assign_settings)%></label>
|
||||||
|
<%= check_box_tag "auto_assign[enabled]", true, @auto_assign.enabled?, :onchange => 'setAutoAssignSettingFormEnable();'%><%=h l(:button_activate)%>
|
||||||
|
</p>
|
||||||
|
<div id="cr_auto_assign_settings" style="display: <%= @auto_assign.enabled? ? 'true' : 'none'%>;">
|
||||||
|
<p>
|
||||||
|
<label><%=h l(:field_author)%></label>
|
||||||
|
<%= select :auto_assign, :author_id,
|
||||||
|
(@project.users.collect {|user|
|
||||||
|
[user.name, user.id]
|
||||||
|
}), :selected => @auto_assign.author_id, :required => true %>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<label><%=h l(:label_candidates_of_reviewer)%></label>
|
||||||
|
<% @project.users.each do |user| %>
|
||||||
|
<label class="floating"><%= check_box_tag 'auto_assign[assignable_list][]', user.id, @auto_assign.assignable?(user) %> <%=h user %></label>
|
||||||
|
<% end %>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<label><%=h l(:field_subject)%></label>
|
||||||
|
<%= text_field(:auto_assign, :subject, :size => 70) %>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<label><%=h l(:field_description) %></label>
|
||||||
|
<%= text_area :auto_assign, :description,
|
||||||
|
:cols => 30,
|
||||||
|
:rows => 12,
|
||||||
|
:accesskey => accesskey(:edit),
|
||||||
|
:class => 'wiki-edit' %>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<div id="auto_assignment_filters">
|
||||||
|
<%= render :partial => 'code_review_settings/filters' %>
|
||||||
|
</div>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<%= submit_tag l(:button_update) %>
|
||||||
|
<% end %>
|
||||||
|
</div>
|
||||||
|
<%= wikitoolbar_for 'auto_assign_description' %>
|
After Width: | Height: | Size: 508 B |
After Width: | Height: | Size: 498 B |
|
@ -0,0 +1,354 @@
|
||||||
|
/*
|
||||||
|
# Code Review plugin for Redmine
|
||||||
|
# Copyright (C) 2009-2013 Haruyuki Iida
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or
|
||||||
|
# modify it under the terms of the GNU General Public License
|
||||||
|
# as published by the Free Software Foundation; either version 2
|
||||||
|
# of the License, or (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program; if not, write to the Free Software
|
||||||
|
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
var topZindex = 1000;
|
||||||
|
var action_type = '';
|
||||||
|
var rev = '';
|
||||||
|
var rev_to = '';
|
||||||
|
var path = '';
|
||||||
|
var urlprefix = '';
|
||||||
|
var review_form_dialog = null;
|
||||||
|
var add_form_title = null;
|
||||||
|
var review_dialog_title = null;
|
||||||
|
var repository_id = null;
|
||||||
|
var filenames = [];
|
||||||
|
|
||||||
|
var ReviewCount = function(total, open, progress){
|
||||||
|
this.total = total;
|
||||||
|
this.open = open;
|
||||||
|
this.closed = total - open;
|
||||||
|
this.progress = progress
|
||||||
|
};
|
||||||
|
|
||||||
|
var CodeReview = function(id) {
|
||||||
|
this.id = id;
|
||||||
|
this.path = '';
|
||||||
|
this.line = 0;
|
||||||
|
this.url = '';
|
||||||
|
this.is_closed = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
var review_counts = new Array();
|
||||||
|
var code_reviews_map = new Array();
|
||||||
|
var code_reviews_dialog_map = new Array();
|
||||||
|
|
||||||
|
function UpdateRepositoryView(title) {
|
||||||
|
var header = $("table.changesets thead tr:first");
|
||||||
|
var th = $('<th></th>');
|
||||||
|
th.html(title);
|
||||||
|
header.append(th);
|
||||||
|
$('tr.changeset td.id a').each(function(i){
|
||||||
|
var revision = this.getAttribute("href");
|
||||||
|
revision = revision.substr(revision.lastIndexOf("/") + 1);
|
||||||
|
var review = review_counts['revision_' + revision];
|
||||||
|
var td = $('<td/>',{
|
||||||
|
'class':'progress'
|
||||||
|
});
|
||||||
|
td.html(review.progress);
|
||||||
|
$(this.parentNode.parentNode).append(td);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
//add function $.down
|
||||||
|
if(! $.fn.down)
|
||||||
|
(function($) {
|
||||||
|
$.fn.down = function() {
|
||||||
|
var el = this[0] && this[0].firstChild;
|
||||||
|
while (el && el.nodeType != 1)
|
||||||
|
el = el.nextSibling;
|
||||||
|
return $(el);
|
||||||
|
};
|
||||||
|
})(jQuery);
|
||||||
|
|
||||||
|
function UpdateRevisionView() {
|
||||||
|
$('li.change').each(function(){
|
||||||
|
var li = $(this);
|
||||||
|
if (li.hasClass('folder')) return;
|
||||||
|
|
||||||
|
var a = li.down('a');
|
||||||
|
if (a.size() == 0) return;
|
||||||
|
var path = a.attr('href').replace(urlprefix, '').replace(/\?.*$/, '');
|
||||||
|
|
||||||
|
var reviewlist = code_reviews_map[path];
|
||||||
|
if (reviewlist == null) return;
|
||||||
|
|
||||||
|
var ul = $('<ul></ul>');
|
||||||
|
for (var j = 0; j < reviewlist.length; j++) {
|
||||||
|
var review = reviewlist[j];
|
||||||
|
var icon = review.is_closed? 'icon-closed-review': 'icon-review';
|
||||||
|
var item = $('<li></li>', {
|
||||||
|
'class': 'icon ' + icon + ' code_review_summary'
|
||||||
|
});
|
||||||
|
item.html(review.url);
|
||||||
|
ul.append(item);
|
||||||
|
}
|
||||||
|
li.append(ul);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function setAddReviewButton(url, change_id, image_tag, is_readonly, is_diff, attachment_id){
|
||||||
|
var filetables = [];
|
||||||
|
var j = 0;
|
||||||
|
$('table').each(function(){
|
||||||
|
if($(this).hasClass('filecontent')){
|
||||||
|
filetables[j++] = this;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
j = 0;
|
||||||
|
$('table.filecontent th.filename').each(function(){
|
||||||
|
filenames[j] = $.trim($(this).text());
|
||||||
|
j++;
|
||||||
|
});
|
||||||
|
addReviewUrl = url + '?change_id=' + change_id + '&action_type=' + action_type +
|
||||||
|
'&rev=' + rev + '&rev_to=' + rev_to +
|
||||||
|
'&attachment_id=' + attachment_id + '&repository_id=' + encodeURIComponent(repository_id);
|
||||||
|
if (path != null && path.length > 0) {
|
||||||
|
addReviewUrl = addReviewUrl + '&path=' + encodeURIComponent(path);
|
||||||
|
}
|
||||||
|
var num = 0;
|
||||||
|
if (is_diff) {
|
||||||
|
num = 1;
|
||||||
|
}
|
||||||
|
var i, l, tl;
|
||||||
|
for (i = 0, tl = filetables.length; i < tl; i++) {
|
||||||
|
var table = filetables[i];
|
||||||
|
var trs = table.getElementsByTagName('tr');
|
||||||
|
|
||||||
|
for (j = 0,l = trs.length; j < l; j++) {
|
||||||
|
var tr = trs[j];
|
||||||
|
var ths = tr.getElementsByTagName('th');
|
||||||
|
|
||||||
|
var th = ths[num];
|
||||||
|
if (th == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var th_html = th.innerHTML;
|
||||||
|
|
||||||
|
var line = th_html.match(/[0-9]+/);
|
||||||
|
if (line == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var span_html = '<span white-space="nowrap" id="review_span_' + line + '_' + i + '">';
|
||||||
|
|
||||||
|
if (!is_readonly) {
|
||||||
|
span_html += image_tag;
|
||||||
|
}
|
||||||
|
span_html += '</span>';
|
||||||
|
th.innerHTML = th_html + span_html;
|
||||||
|
|
||||||
|
var img = th.getElementsByTagName('img')[0];
|
||||||
|
if (img != null ) {
|
||||||
|
img.id = 'add_revew_img_' + line + '_' + i;
|
||||||
|
$(img).click(clickPencil);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function clickPencil(e)
|
||||||
|
{
|
||||||
|
// alert('$(e.target).attr("id") = ' + $(e.target).attr("id"));
|
||||||
|
var result = $(e.target).attr("id").match(/([0-9]+)_([0-9]+)/);
|
||||||
|
var line = result[1];
|
||||||
|
var file_count = eval(result[2]);
|
||||||
|
var url = addReviewUrl + '&line=' + line + '&file_count=' + file_count;
|
||||||
|
|
||||||
|
if (path == null || path.length == 0) {
|
||||||
|
url = url + '&path=' + encodeURIComponent(filenames[file_count]) + '&diff_all=true';
|
||||||
|
}
|
||||||
|
addReview(url);
|
||||||
|
formPopup(e.pageX, e.pageY);
|
||||||
|
e.preventDefault();
|
||||||
|
}
|
||||||
|
var addReviewUrl = null;
|
||||||
|
var showReviewUrl = null;
|
||||||
|
var showReviewImageTag = null;
|
||||||
|
var showClosedReviewImageTag = null;
|
||||||
|
|
||||||
|
function setShowReviewButton(line, review_id, is_closed, file_count) {
|
||||||
|
//alert('file_count = ' + file_count);
|
||||||
|
var span = $('#review_span_' + line + '_' + file_count);
|
||||||
|
if (span.size() == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var innerSpan = $('<span></span>',{id: 'review_' + review_id});
|
||||||
|
span.append(innerSpan);
|
||||||
|
innerSpan.html(is_closed? showClosedReviewImageTag : showReviewImageTag);
|
||||||
|
var div = $('<div></div>', {
|
||||||
|
'class':'draggable',
|
||||||
|
id: 'show_review_' + review_id
|
||||||
|
});
|
||||||
|
$('#code_review').append(div);
|
||||||
|
innerSpan.down('img').click(function(e) {
|
||||||
|
var review_id = $(e.target).parent().attr('id').match(/[0-9]+/)[0];
|
||||||
|
var span = $('#review_' + review_id); // span element of view review button
|
||||||
|
var pos = span.offset();
|
||||||
|
showReview(showReviewUrl, review_id, pos.left + 10 + 5, pos.top + 25);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function popupReview(review_id) {
|
||||||
|
var span = $('#review_' + review_id); // span element of view review button
|
||||||
|
var pos = span.offset();
|
||||||
|
$('html,body').animate({ scrollTop: pos.top },
|
||||||
|
{duration: 'fast',
|
||||||
|
complete: function(){showReview(showReviewUrl, review_id, pos.left + 10 + 5, pos.top)}});
|
||||||
|
// position and show popup dialog
|
||||||
|
// create popup dialog
|
||||||
|
//var win = showReview(showReviewUrl, review_id, pos.left + 10 + 5, pos.top);
|
||||||
|
// win.toFront();
|
||||||
|
}
|
||||||
|
|
||||||
|
function showReview(url, review_id, x, y) {
|
||||||
|
if (code_reviews_dialog_map[review_id] != null) {
|
||||||
|
var cur_win = code_reviews_dialog_map[review_id];
|
||||||
|
cur_win.hide();
|
||||||
|
code_reviews_dialog_map[review_id] = null;
|
||||||
|
}
|
||||||
|
$('#show_review_' + review_id).load(url, {review_id: review_id});
|
||||||
|
var review = getReviewObjById(review_id);
|
||||||
|
|
||||||
|
var win = $('#show_review_' + review_id).dialog({
|
||||||
|
show: {effect:'scale'},// ? 'top-left'
|
||||||
|
//position: [x, y + 5],
|
||||||
|
width:640,
|
||||||
|
zIndex: topZindex,
|
||||||
|
title: review_dialog_title
|
||||||
|
});
|
||||||
|
// win.getContent().style.color = "#484848";
|
||||||
|
// win.getContent().style.background = "#ffffff";
|
||||||
|
topZindex++;
|
||||||
|
code_reviews_dialog_map[review_id] = win;
|
||||||
|
return win
|
||||||
|
}
|
||||||
|
|
||||||
|
function getReviewObjById(review_id) {
|
||||||
|
for (var reviewlist in code_reviews_map) {
|
||||||
|
for (var i = 0; i < reviewlist.length; i++) {
|
||||||
|
var review = reviewlist[i];
|
||||||
|
if (review.id == review_id) {
|
||||||
|
return review;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function formPopup(x, y){
|
||||||
|
//@see http://docs.jquery.com/UI/Effects/Scale
|
||||||
|
var win = $('#review-form-frame').dialog({
|
||||||
|
show: {effect:'scale', direction: 'both'},// ? 'top-left'
|
||||||
|
// position: [x, y + 5],
|
||||||
|
width:640,
|
||||||
|
zIndex: topZindex,
|
||||||
|
title: add_form_title
|
||||||
|
});
|
||||||
|
// win.getContent().style.background = "#ffffff";
|
||||||
|
if (review_form_dialog != null) {
|
||||||
|
review_form_dialog.destroy();
|
||||||
|
review_form_dialog = null;
|
||||||
|
}
|
||||||
|
review_form_dialog = win;
|
||||||
|
topZindex += 10;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function hideForm() {
|
||||||
|
if (review_form_dialog == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
review_form_dialog.dialog('close');
|
||||||
|
review_form_dialog = null;
|
||||||
|
$('#review-form').html('');
|
||||||
|
}
|
||||||
|
function addReview(url) {
|
||||||
|
$('#review-form').load(url);
|
||||||
|
}
|
||||||
|
|
||||||
|
function deleteReview(review_id) {
|
||||||
|
$('show_review_' + review_id).remove();
|
||||||
|
$('review_' + review_id).remove();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function changeImage(review_id, is_closed) {
|
||||||
|
var span = $('review_' + review_id);
|
||||||
|
var new_image = null;
|
||||||
|
var dummy = new Element('span');
|
||||||
|
if (is_closed) {
|
||||||
|
dummy.insert(showClosedReviewImageTag);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
dummy.insert(showReviewImageTag);
|
||||||
|
}
|
||||||
|
new_image = dummy.down().getAttribute('src');
|
||||||
|
//alert(new_image);
|
||||||
|
span.down('img').setAttribute('src', new_image);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function make_addreview_link(project, link) {
|
||||||
|
var alist = $('#content p a');
|
||||||
|
if (alist == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var a = alist[0];
|
||||||
|
var p = a.parentNode;
|
||||||
|
p.innerHTML = p.innerHTML + " | " + link;
|
||||||
|
}
|
||||||
|
|
||||||
|
function call_update_revisions(url) {
|
||||||
|
var changeset_ids = '';
|
||||||
|
var links = $$('table.changesets tbody tr.changeset td.id a');
|
||||||
|
for (var i = 0; i < links.length; i++) {
|
||||||
|
var link = links[i];
|
||||||
|
var href = link.getAttribute('href');
|
||||||
|
var id = href.replace(/^.*\/revisions\//, '');
|
||||||
|
if (i > 0) {
|
||||||
|
changeset_ids += ',';
|
||||||
|
}
|
||||||
|
changeset_ids += id;
|
||||||
|
}
|
||||||
|
new Ajax.Updater('code_review_revisions', url,
|
||||||
|
{
|
||||||
|
evalScripts:true,
|
||||||
|
method:'get',
|
||||||
|
parameters: 'changeset_ids=' + encodeURI(changeset_ids)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
$.fn.serialize2json = function()
|
||||||
|
{
|
||||||
|
var o = {};
|
||||||
|
var a = this.serializeArray();
|
||||||
|
$.each(a, function() {
|
||||||
|
if (o[this.name]) {
|
||||||
|
if (!o[this.name].push) {
|
||||||
|
o[this.name] = [o[this.name]];
|
||||||
|
}
|
||||||
|
o[this.name].push(this.value || '');
|
||||||
|
} else {
|
||||||
|
o[this.name] = this.value || '';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return o;
|
||||||
|
};
|
|
@ -0,0 +1,4 @@
|
||||||
|
|
||||||
|
dt.code_review {
|
||||||
|
background-image: url(../images/review.png);
|
||||||
|
}
|
|
@ -0,0 +1,97 @@
|
||||||
|
/*
|
||||||
|
# Code Review plugin for Redmine
|
||||||
|
# Copyright (C) 2009 Haruyuki Iida
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or
|
||||||
|
# modify it under the terms of the GNU General Public License
|
||||||
|
# as published by the Free Software Foundation; either version 2
|
||||||
|
# of the License, or (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program; if not, write to the Free Software
|
||||||
|
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
#review-form-frame {
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.autoscroll table.filecontent th.line-num {
|
||||||
|
white-space: nowrap;
|
||||||
|
vertical-align: bottom;
|
||||||
|
padding-top: 0;
|
||||||
|
padding-bottom: 0;
|
||||||
|
text-align:left;
|
||||||
|
}
|
||||||
|
|
||||||
|
table.filecontent th.line-num img{
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.code-review-form-title {
|
||||||
|
background-color: #002059;
|
||||||
|
color: white;
|
||||||
|
padding-left: 2px;
|
||||||
|
padding-right: 2px;
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.code_review_viewer {
|
||||||
|
|
||||||
|
min-width: 300px;
|
||||||
|
/*
|
||||||
|
max-width: 60%;
|
||||||
|
*/
|
||||||
|
/* max-height: 400px; */
|
||||||
|
}
|
||||||
|
|
||||||
|
.code_review_viewer .issue{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.code_review_body {
|
||||||
|
background-color: white;
|
||||||
|
|
||||||
|
padding:2px;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#code_review_list table.list td {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
#code_review_list table.list td.path {
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
#code_review_list table.list td.subject {
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-review {
|
||||||
|
background-image: url(../images/review.png);
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-closed-review {
|
||||||
|
background-image: url(../images/closed_review.png);
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-settings {
|
||||||
|
background-image: url(../../../images/changeset.png);
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
li.code_review_summary {
|
||||||
|
list-style-type: none;
|
||||||
|
}
|
|
@ -0,0 +1,19 @@
|
||||||
|
Copyright (c) 2006 Sébastien Gruhier (http://xilinus.com, http://itseb.com)
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
a copy of this software and associated documentation files (the
|
||||||
|
"Software"), to deal in the Software without restriction, including
|
||||||
|
without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
distribute, sublicense, and/or sell copies of the Software, and to
|
||||||
|
permit persons to whom the Software is furnished to do so, subject to
|
||||||
|
the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be
|
||||||
|
included in all copies or substantial portions of the Software.
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||||
|
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||||
|
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
|
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
@ -0,0 +1,119 @@
|
||||||
|
.overlay_alert {
|
||||||
|
background-color: #85BBEF;
|
||||||
|
filter:alpha(opacity=60);
|
||||||
|
-moz-opacity: 0.6;
|
||||||
|
opacity: 0.6;
|
||||||
|
}
|
||||||
|
|
||||||
|
.alert_nw {
|
||||||
|
width: 5px;
|
||||||
|
height: 5px;
|
||||||
|
background: transparent url(alert/top_left.gif) no-repeat bottom left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.alert_n {
|
||||||
|
height: 5px;
|
||||||
|
background: transparent url(alert/top.gif) repeat-x bottom left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.alert_ne {
|
||||||
|
width: 5px;
|
||||||
|
height: 5px;
|
||||||
|
background: transparent url(alert/top_right.gif) no-repeat bottom left
|
||||||
|
}
|
||||||
|
|
||||||
|
.alert_e {
|
||||||
|
width: 5px;
|
||||||
|
background: transparent url(alert/right.gif) repeat-y 0 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.alert_w {
|
||||||
|
width: 5px;
|
||||||
|
background: transparent url(alert/left.gif) repeat-y 0 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.alert_sw {
|
||||||
|
width: 5px;
|
||||||
|
height: 5px;
|
||||||
|
background: transparent url(alert/bottom_left.gif) no-repeat 0 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.alert_s {
|
||||||
|
height: 5px;
|
||||||
|
background: transparent url(alert/bottom.gif) repeat-x 0 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.alert_se, .alert_sizer {
|
||||||
|
width: 5px;
|
||||||
|
height: 5px;
|
||||||
|
background: transparent url(alert/bottom_right.gif) no-repeat 0 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.alert_close {
|
||||||
|
width:0px;
|
||||||
|
height:0px;
|
||||||
|
display:none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.alert_minimize {
|
||||||
|
width:0px;
|
||||||
|
height:0px;
|
||||||
|
display:none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.alert_maximize {
|
||||||
|
width:0px;
|
||||||
|
height:0px;
|
||||||
|
display:none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.alert_title {
|
||||||
|
float:left;
|
||||||
|
height:1px;
|
||||||
|
width:100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.alert_content {
|
||||||
|
overflow:visible;
|
||||||
|
color: #000;
|
||||||
|
font-family: Tahoma, Arial, sans-serif;
|
||||||
|
font: 12px arial;
|
||||||
|
background: #FFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* For alert/confirm dialog */
|
||||||
|
.alert_window {
|
||||||
|
background: #FFF;
|
||||||
|
padding:20px;
|
||||||
|
margin-left:auto;
|
||||||
|
margin-right:auto;
|
||||||
|
width:400px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.alert_message {
|
||||||
|
font: 12px arial;
|
||||||
|
width:100%;
|
||||||
|
color:#F00;
|
||||||
|
padding-bottom:10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.alert_buttons {
|
||||||
|
text-align:center;
|
||||||
|
width:100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.alert_buttons input {
|
||||||
|
width:20%;
|
||||||
|
margin:10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.alert_progress {
|
||||||
|
float:left;
|
||||||
|
margin:auto;
|
||||||
|
text-align:center;
|
||||||
|
width:100%;
|
||||||
|
height:16px;
|
||||||
|
background: #FFF url('alert/progress.gif') no-repeat center center
|
||||||
|
}
|
||||||
|
|
||||||
|
|
After Width: | Height: | Size: 70 B |
After Width: | Height: | Size: 49 B |
After Width: | Height: | Size: 49 B |
After Width: | Height: | Size: 84 B |
After Width: | Height: | Size: 2.8 KiB |
After Width: | Height: | Size: 1.5 KiB |
After Width: | Height: | Size: 84 B |
After Width: | Height: | Size: 70 B |
After Width: | Height: | Size: 49 B |
After Width: | Height: | Size: 49 B |
|
@ -0,0 +1,88 @@
|
||||||
|
.overlay_alert_lite {
|
||||||
|
background-color: #85BBEF;
|
||||||
|
filter:alpha(opacity=60);
|
||||||
|
-moz-opacity: 0.6;
|
||||||
|
opacity: 0.6;
|
||||||
|
}
|
||||||
|
|
||||||
|
.alert_lite_sizer {
|
||||||
|
width:0px;
|
||||||
|
height:0px;
|
||||||
|
display:none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.alert_lite_close {
|
||||||
|
width:0px;
|
||||||
|
height:0px;
|
||||||
|
display:none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.alert_lite_minimize {
|
||||||
|
width:0px;
|
||||||
|
height:0px;
|
||||||
|
display:none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.alert_lite_maximize {
|
||||||
|
width:0px;
|
||||||
|
height:0px;
|
||||||
|
display:none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.alert_lite_title {
|
||||||
|
width:0px;
|
||||||
|
height:0px;
|
||||||
|
display:none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.alert_lite_content {
|
||||||
|
overflow:auto;
|
||||||
|
color: #000;
|
||||||
|
font-family: Tahoma, Arial, sans-serif;
|
||||||
|
font-size: 10px;
|
||||||
|
background: #FFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* For alert/confirm dialog */
|
||||||
|
.alert_lite_window {
|
||||||
|
border:1px solid #F00;
|
||||||
|
background: #FFF;
|
||||||
|
padding:20px;
|
||||||
|
margin-left:auto;
|
||||||
|
margin-right:auto;
|
||||||
|
width:400px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.alert_lite_message {
|
||||||
|
font-size:16px;
|
||||||
|
text-align:center;
|
||||||
|
width:100%;
|
||||||
|
color:#F00;
|
||||||
|
padding-bottom:10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.alert_lite_buttons {
|
||||||
|
text-align:center;
|
||||||
|
width:100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.alert_lite_buttons input {
|
||||||
|
width:20%;
|
||||||
|
margin:10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.alert_lite_progress {
|
||||||
|
float:left;
|
||||||
|
margin:auto;
|
||||||
|
text-align:center;
|
||||||
|
width:100%;
|
||||||
|
height:16px;
|
||||||
|
background: #FFF url('alert/progress.gif') no-repeat center center
|
||||||
|
}
|
||||||
|
|
||||||
|
table.alert_lite_header {
|
||||||
|
border:1px solid #F00;
|
||||||
|
background:#FFF
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,150 @@
|
||||||
|
.overlay_alphacube {
|
||||||
|
background-color: #85BBEF;
|
||||||
|
filter:alpha(opacity=60);
|
||||||
|
-moz-opacity: 0.6;
|
||||||
|
opacity: 0.6;
|
||||||
|
}
|
||||||
|
|
||||||
|
.alphacube_nw {
|
||||||
|
background: transparent url(alphacube/left-top.gif) no-repeat 0 0;
|
||||||
|
width:10px;
|
||||||
|
height:25px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.alphacube_n {
|
||||||
|
background: transparent url(alphacube/top-middle.gif) repeat-x 0 0;
|
||||||
|
height:25px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.alphacube_ne {
|
||||||
|
background: transparent url(alphacube/right-top.gif) no-repeat 0 0;
|
||||||
|
width:10px;
|
||||||
|
height:25px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.alphacube_w {
|
||||||
|
background: transparent url(alphacube/frame-left.gif) repeat-y top left;
|
||||||
|
width:7px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.alphacube_e {
|
||||||
|
background: transparent url(alphacube/frame-right.gif) repeat-y top right;
|
||||||
|
width:7px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.alphacube_sw {
|
||||||
|
background: transparent url(alphacube/bottom-left-c.gif) no-repeat 0 0;
|
||||||
|
width:7px;
|
||||||
|
height:7px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.alphacube_s {
|
||||||
|
background: transparent url(alphacube/bottom-middle.gif) repeat-x 0 0;
|
||||||
|
height:7px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.alphacube_se, .alphacube_sizer {
|
||||||
|
background: transparent url(alphacube/bottom-right-c.gif) no-repeat 0 0;
|
||||||
|
width:7px;
|
||||||
|
height:7px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.alphacube_sizer {
|
||||||
|
cursor:se-resize;
|
||||||
|
}
|
||||||
|
|
||||||
|
.alphacube_close {
|
||||||
|
width: 23px;
|
||||||
|
height: 23px;
|
||||||
|
background: transparent url(alphacube/button-close-focus.gif) no-repeat 0 0;
|
||||||
|
position:absolute;
|
||||||
|
top:0px;
|
||||||
|
right:11px;
|
||||||
|
cursor:pointer;
|
||||||
|
z-index:1000;
|
||||||
|
}
|
||||||
|
|
||||||
|
.alphacube_minimize {
|
||||||
|
width: 23px;
|
||||||
|
height: 23px;
|
||||||
|
background: transparent url(alphacube/button-min-focus.gif) no-repeat 0 0;
|
||||||
|
position:absolute;
|
||||||
|
top:0px;
|
||||||
|
right:55px;
|
||||||
|
cursor:pointer;
|
||||||
|
z-index:1000;
|
||||||
|
}
|
||||||
|
|
||||||
|
.alphacube_maximize {
|
||||||
|
width: 23px;
|
||||||
|
height: 23px;
|
||||||
|
background: transparent url(alphacube/button-max-focus.gif) no-repeat 0 0;
|
||||||
|
position:absolute;
|
||||||
|
top:0px;
|
||||||
|
right:33px;
|
||||||
|
cursor:pointer;
|
||||||
|
z-index:1000;
|
||||||
|
}
|
||||||
|
|
||||||
|
.alphacube_title {
|
||||||
|
float:left;
|
||||||
|
height:14px;
|
||||||
|
font-size:14px;
|
||||||
|
text-align:center;
|
||||||
|
margin-top:2px;
|
||||||
|
width:100%;
|
||||||
|
color:#123456;
|
||||||
|
}
|
||||||
|
|
||||||
|
.alphacube_content {
|
||||||
|
overflow:auto;
|
||||||
|
color: #000;
|
||||||
|
font-family: Tahoma, Arial, sans-serif;
|
||||||
|
font: 12px arial;
|
||||||
|
background:#FDFDFD;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* For alert/confirm dialog */
|
||||||
|
.alphacube_window {
|
||||||
|
border:1px solid #F00;
|
||||||
|
background: #FFF;
|
||||||
|
padding:20px;
|
||||||
|
margin-left:auto;
|
||||||
|
margin-right:auto;
|
||||||
|
width:400px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.alphacube_message {
|
||||||
|
font: 12px arial;
|
||||||
|
text-align:center;
|
||||||
|
width:100%;
|
||||||
|
padding-bottom:10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.alphacube_buttons {
|
||||||
|
text-align:center;
|
||||||
|
width:100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.alphacube_buttons input {
|
||||||
|
width:20%;
|
||||||
|
margin:10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.alphacube_progress {
|
||||||
|
float:left;
|
||||||
|
margin:auto;
|
||||||
|
text-align:center;
|
||||||
|
width:100%;
|
||||||
|
height:16px;
|
||||||
|
background: #FFF url('alert/progress.gif') no-repeat center center
|
||||||
|
}
|
||||||
|
|
||||||
|
.alphacube_wired_frame {
|
||||||
|
background: #FFF;
|
||||||
|
filter:alpha(opacity=60);
|
||||||
|
-moz-opacity: 0.6;
|
||||||
|
opacity: 0.6;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
After Width: | Height: | Size: 60 B |
After Width: | Height: | Size: 50 B |
After Width: | Height: | Size: 61 B |
After Width: | Height: | Size: 699 B |
After Width: | Height: | Size: 765 B |
After Width: | Height: | Size: 472 B |
After Width: | Height: | Size: 64 B |
After Width: | Height: | Size: 64 B |
After Width: | Height: | Size: 171 B |
After Width: | Height: | Size: 168 B |
After Width: | Height: | Size: 97 B |
|
@ -0,0 +1,51 @@
|
||||||
|
<public:component>
|
||||||
|
<public:attach event="onpropertychange" onevent="propertyChanged()" />
|
||||||
|
<script>
|
||||||
|
|
||||||
|
var supported = /MSIE (5\.5)|[6789]/.test(navigator.userAgent) && navigator.platform == "Win32";
|
||||||
|
var realSrc;
|
||||||
|
var blankSrc = "blank.gif";
|
||||||
|
|
||||||
|
if (supported) fixImage();
|
||||||
|
|
||||||
|
function propertyChanged() {
|
||||||
|
if (!supported) return;
|
||||||
|
|
||||||
|
var pName = event.propertyName;
|
||||||
|
if (pName != "src") return;
|
||||||
|
// if not set to blank
|
||||||
|
if ( ! new RegExp(blankSrc).test(src))
|
||||||
|
fixImage();
|
||||||
|
};
|
||||||
|
|
||||||
|
function fixImage() {
|
||||||
|
// get src
|
||||||
|
var src = element.src;
|
||||||
|
|
||||||
|
// check for real change
|
||||||
|
if (src == realSrc) {
|
||||||
|
element.src = blankSrc;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( ! new RegExp(blankSrc).test(src)) {
|
||||||
|
// backup old src
|
||||||
|
realSrc = src;
|
||||||
|
}
|
||||||
|
|
||||||
|
// test for png
|
||||||
|
if ( /\.png$/.test( realSrc.toLowerCase() ) ) {
|
||||||
|
// set blank image
|
||||||
|
element.src = blankSrc;
|
||||||
|
// set filter
|
||||||
|
element.runtimeStyle.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='" +
|
||||||
|
src + "',sizingMethod='scale')";
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// remove filter
|
||||||
|
element.runtimeStyle.filter = "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
</public:component>
|
|
@ -0,0 +1,121 @@
|
||||||
|
.overlay_darkX {
|
||||||
|
background-color: #85BBEF;
|
||||||
|
filter:alpha(opacity=60);
|
||||||
|
-moz-opacity: 0.6;
|
||||||
|
opacity: 0.6;
|
||||||
|
}
|
||||||
|
|
||||||
|
.darkX_nw {
|
||||||
|
background: transparent url(darkX/titlebar-left-focused.png) no-repeat 0 0;
|
||||||
|
width:6px;
|
||||||
|
height:21px;
|
||||||
|
}
|
||||||
|
.darkX_n {
|
||||||
|
background: transparent url(darkX/titlebar-mid-focused.png) repeat-x 0 0;
|
||||||
|
height:21px;
|
||||||
|
}
|
||||||
|
.darkX_ne {
|
||||||
|
background: transparent url(darkX/titlebar-right-focused.png) no-repeat 0 0;
|
||||||
|
width:6px;
|
||||||
|
height:21px;
|
||||||
|
}
|
||||||
|
.darkX_w {
|
||||||
|
background: transparent url(darkX/frame-left-focused.png) repeat-y top left;
|
||||||
|
width:3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.darkX_e {
|
||||||
|
background: transparent url(darkX/frame-right-focused.png) repeat-y top right;
|
||||||
|
width:3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.darkX_sw {
|
||||||
|
background: transparent url(darkX/frame-bottom-left-focused.png) no-repeat 0 0;
|
||||||
|
width:5px;
|
||||||
|
height:3px;
|
||||||
|
}
|
||||||
|
.darkX_s {
|
||||||
|
background: transparent url(darkX/frame-bottom-mid-focused.png) repeat-x 0 0;
|
||||||
|
height:3px;
|
||||||
|
}
|
||||||
|
.darkX_se, .darkX_sizer {
|
||||||
|
background: transparent url(darkX/frame-bottom-right-focused.png) no-repeat 0 0;
|
||||||
|
width:5px;
|
||||||
|
height:3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.darkX_sizer {
|
||||||
|
cursor:se-resize;
|
||||||
|
}
|
||||||
|
|
||||||
|
.darkX_close {
|
||||||
|
width: 21px;
|
||||||
|
height: 21px;
|
||||||
|
background: transparent url(darkX/button-close-focused.png) no-repeat 0 0;
|
||||||
|
position:absolute;
|
||||||
|
top:0px;
|
||||||
|
right:5px;
|
||||||
|
cursor:pointer;
|
||||||
|
z-index:1000;
|
||||||
|
}
|
||||||
|
|
||||||
|
.darkX_minimize {
|
||||||
|
width: 21px;
|
||||||
|
height: 21px;
|
||||||
|
background: transparent url(darkX/button-minimize-focused.png) no-repeat 0 0;
|
||||||
|
position:absolute;
|
||||||
|
top:0px;
|
||||||
|
right:26px;
|
||||||
|
cursor:pointer;
|
||||||
|
z-index:1000;
|
||||||
|
}
|
||||||
|
|
||||||
|
.darkX_maximize {
|
||||||
|
width: 21px;
|
||||||
|
height: 21px;
|
||||||
|
background: transparent url(darkX/button-maximize-focused.png) no-repeat 0 0;
|
||||||
|
position:absolute;
|
||||||
|
top:0px;
|
||||||
|
right:47px;
|
||||||
|
cursor:pointer;
|
||||||
|
z-index:1000;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.darkX_title {
|
||||||
|
float:left;
|
||||||
|
height:14px;
|
||||||
|
font-size:12px;
|
||||||
|
text-align:center;
|
||||||
|
margin-top:2px;
|
||||||
|
width:100%;
|
||||||
|
color:#FFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
.darkX_content {
|
||||||
|
overflow:auto;
|
||||||
|
color: #E6DF2A;
|
||||||
|
font-family: Tahoma, Arial, sans-serif;
|
||||||
|
font-size: 14px;
|
||||||
|
background:#5E5148;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* FOR IE */
|
||||||
|
* html .darkX_minimize {
|
||||||
|
background-color: transparent;
|
||||||
|
background-image: none;
|
||||||
|
filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src="../themes/darkX/button-minimize-focused.png", sizingMethod="crop");
|
||||||
|
}
|
||||||
|
|
||||||
|
* html .darkX_maximize {
|
||||||
|
background-color: transparent;
|
||||||
|
background-image: none;
|
||||||
|
filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src="../themes/darkX/button-maximize-focused.png", sizingMethod="scale");
|
||||||
|
}
|
||||||
|
|
||||||
|
* html .darkX_close {
|
||||||
|
background-color: transparent;
|
||||||
|
background-image: none;
|
||||||
|
filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src="../themes/darkX/button-close-focused.png", sizingMethod="crop");
|
||||||
|
}
|
After Width: | Height: | Size: 904 B |
After Width: | Height: | Size: 882 B |
After Width: | Height: | Size: 839 B |
After Width: | Height: | Size: 142 B |
After Width: | Height: | Size: 142 B |
After Width: | Height: | Size: 142 B |
After Width: | Height: | Size: 142 B |
After Width: | Height: | Size: 142 B |
After Width: | Height: | Size: 180 B |
After Width: | Height: | Size: 175 B |
After Width: | Height: | Size: 180 B |
|
@ -0,0 +1,25 @@
|
||||||
|
div.inspector div.inspectable {
|
||||||
|
padding: 0.25em 0 0.25em 1em;
|
||||||
|
background-color: Gray;
|
||||||
|
color: white;
|
||||||
|
border: outset 2px white;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.inspector div.child {
|
||||||
|
margin: 0 0 0 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
#debug_window_content { /* DIV container for debug sizing*/
|
||||||
|
width:250px;
|
||||||
|
height:100px;
|
||||||
|
background-color:#000;
|
||||||
|
}
|
||||||
|
|
||||||
|
#debug { /* DIV container for debug contents*/
|
||||||
|
padding:3px;
|
||||||
|
color:#0f0;
|
||||||
|
font-family:monaco, Tahoma, Verdana, Arial, Helvetica, sans-serif;
|
||||||
|
font-size:10px;
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,155 @@
|
||||||
|
.overlay_dialog {
|
||||||
|
background-color: #666666;
|
||||||
|
filter:alpha(opacity=60);
|
||||||
|
-moz-opacity: 0.6;
|
||||||
|
opacity: 0.6;
|
||||||
|
}
|
||||||
|
|
||||||
|
.overlay___invisible__ {
|
||||||
|
background-color: #666666;
|
||||||
|
filter:alpha(opacity=0);
|
||||||
|
-moz-opacity: 0;
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dialog_nw {
|
||||||
|
width: 9px;
|
||||||
|
height: 23px;
|
||||||
|
background: transparent url(default/top_left.gif) no-repeat 0 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dialog_n {
|
||||||
|
background: transparent url(default/top_mid.gif) repeat-x 0 0;
|
||||||
|
height: 23px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dialog_ne {
|
||||||
|
width: 9px;
|
||||||
|
height: 23px;
|
||||||
|
background: transparent url(default/top_right.gif) no-repeat 0 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dialog_e {
|
||||||
|
width: 2px;
|
||||||
|
background: transparent url(default/center_right.gif) repeat-y 0 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dialog_w {
|
||||||
|
width: 2px;
|
||||||
|
background: transparent url(default/center_left.gif) repeat-y 0 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dialog_sw {
|
||||||
|
width: 9px;
|
||||||
|
height: 19px;
|
||||||
|
background: transparent url(default/bottom_left.gif) no-repeat 0 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dialog_s {
|
||||||
|
background: transparent url(default/bottom_mid.gif) repeat-x 0 0;
|
||||||
|
height: 19px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dialog_se {
|
||||||
|
width: 9px;
|
||||||
|
height: 19px;
|
||||||
|
background: transparent url(default/bottom_right.gif) no-repeat 0 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dialog_sizer {
|
||||||
|
width: 9px;
|
||||||
|
height: 19px;
|
||||||
|
background: transparent url(default/sizer.gif) no-repeat 0 0;
|
||||||
|
cursor:se-resize;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dialog_close {
|
||||||
|
width: 14px;
|
||||||
|
height: 14px;
|
||||||
|
background: transparent url(default/close.gif) no-repeat 0 0;
|
||||||
|
position:absolute;
|
||||||
|
top:5px;
|
||||||
|
left:8px;
|
||||||
|
cursor:pointer;
|
||||||
|
z-index:2000;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dialog_minimize {
|
||||||
|
width: 14px;
|
||||||
|
height: 15px;
|
||||||
|
background: transparent url(default/minimize.gif) no-repeat 0 0;
|
||||||
|
position:absolute;
|
||||||
|
top:5px;
|
||||||
|
left:28px;
|
||||||
|
cursor:pointer;
|
||||||
|
z-index:2000;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dialog_maximize {
|
||||||
|
width: 14px;
|
||||||
|
height: 15px;
|
||||||
|
background: transparent url(default/maximize.gif) no-repeat 0 0;
|
||||||
|
position:absolute;
|
||||||
|
top:5px;
|
||||||
|
left:49px;
|
||||||
|
cursor:pointer;
|
||||||
|
z-index:2000;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dialog_title {
|
||||||
|
float:left;
|
||||||
|
height:14px;
|
||||||
|
font-family: Tahoma, Arial, sans-serif;
|
||||||
|
font-size:12px;
|
||||||
|
text-align:center;
|
||||||
|
width:100%;
|
||||||
|
color:#000;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dialog_content {
|
||||||
|
overflow:auto;
|
||||||
|
color: #DDD;
|
||||||
|
font-family: Tahoma, Arial, sans-serif;
|
||||||
|
font-size: 10px;
|
||||||
|
background-color:#123;
|
||||||
|
}
|
||||||
|
|
||||||
|
.top_draggable, .bottom_draggable {
|
||||||
|
cursor:move;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status_bar {
|
||||||
|
font-size:12px;
|
||||||
|
}
|
||||||
|
.status_bar input{
|
||||||
|
font-size:12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wired_frame {
|
||||||
|
display: block;
|
||||||
|
position: absolute;
|
||||||
|
border: 1px #000 dashed;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* DO NOT CHANGE THESE VALUES*/
|
||||||
|
.dialog {
|
||||||
|
display: block;
|
||||||
|
position: absolute;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dialog table.table_window {
|
||||||
|
border-collapse: collapse;
|
||||||
|
border-spacing: 0;
|
||||||
|
width: 100%;
|
||||||
|
margin: 0px;
|
||||||
|
padding:0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dialog table.table_window td , .dialog table.table_window th {
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dialog .title_window {
|
||||||
|
-moz-user-select:none;
|
||||||
|
}
|
||||||
|
|
After Width: | Height: | Size: 187 B |
After Width: | Height: | Size: 68 B |
After Width: | Height: | Size: 187 B |
After Width: | Height: | Size: 201 B |
After Width: | Height: | Size: 52 B |
After Width: | Height: | Size: 49 B |
After Width: | Height: | Size: 1014 B |
After Width: | Height: | Size: 1012 B |
After Width: | Height: | Size: 556 B |
After Width: | Height: | Size: 1.0 KiB |
After Width: | Height: | Size: 1023 B |
After Width: | Height: | Size: 2.8 KiB |
After Width: | Height: | Size: 138 B |
After Width: | Height: | Size: 201 B |
After Width: | Height: | Size: 358 B |
After Width: | Height: | Size: 149 B |
After Width: | Height: | Size: 357 B |
After Width: | Height: | Size: 49 B |
|
@ -0,0 +1,3 @@
|
||||||
|
/* PNG fix for all themes that uses PNG images on IE */
|
||||||
|
td, div { behavior: url(../themes/iefix/iepngfix.htc) }
|
||||||
|
|