Merge branch 'dev_newproject' into 'develop'

Issue和commit关联功能



See merge request !49
This commit is contained in:
黄井泉 2016-12-09 14:17:06 +08:00
commit 74a20dddc1
28 changed files with 400 additions and 69 deletions

View File

@ -50,10 +50,10 @@ gem 'elasticsearch-model'
gem 'elasticsearch-rails'
#rails 3.2.22.2 bug
gem "test-unit", "~>3.0"
# gem "test-unit", "~>3.0"
### profile
gem 'oneapm_rpm'
# gem 'oneapm_rpm'
group :development do
gem 'grape-swagger'

View File

@ -55,7 +55,7 @@ class ApplicationController < ActionController::Base
include Redmine::Search::Controller
include Redmine::MenuManager::MenuController
helper Redmine::MenuManager::MenuHelper
def user_agent
logger.info "HTTP_USER_AGENT #{request.env["HTTP_USER_AGENT"]}"
end

View File

@ -22,9 +22,9 @@ class IssuesController < ApplicationController
before_filter :authorize1, :only => [:show]
before_filter :find_issue, :only => [:show, :edit, :update,:add_journal, :add_journal_in_org]
before_filter :find_issues, :only => [:bulk_edit, :bulk_update, :destroy]
before_filter :find_project, :only => [:new, :create, :update_form]
before_filter :find_project, :only => [:new, :create, :update_form, :issue_commits, :commit_for_issue, :issue_commit_delete]
#before_filter :authorize, :except => [:index, :show]
before_filter :authorize, :except => [:index,:add_journal, :add_journal_in_org,:delete_journal,:reply,:add_reply]
before_filter :authorize, :except => [:index,:add_journal, :add_journal_in_org,:delete_journal,:reply,:add_reply, :issue_commits, :commit_for_issue, :issue_commit_delete]
before_filter :find_optional_project, :only => [:index]
before_filter :check_for_default_issue_status, :only => [:new, :create]
@ -57,6 +57,57 @@ class IssuesController < ApplicationController
helper :project_score
include ApplicationHelper
# issue和代码提交id关联模块 --> over
# 获取某个项目的commit_ids
def issue_commits
begin
return render_404 if @project.gpid.nil?
@issue_commit_ids = (params[:issue_commit_ids].is_a?(Array) ? params[:issue_commit_ids] : params[:issue_commit_ids].split(",")) unless params[:issue_commit_ids].nil?
search = params[:search].to_s.strip
@type = params[:type]
limit = 15
g = Gitlab.client
g_project = g.project(@project.gpid)
rev = params[:branch].nil? ? g_project.default_branch : params[:branch]
@project_branches = g.branches(@project.gpid)
@branch_names = @project_branches.map{|b| b.name}
@default_branch = g_project.default_branch
# 搜索的分页需要单独处理,因为搜索不容易获取总数
if search.present?
@commits = g.commits(@project.gpid, ref_name:rev, :search => search)
@commits_count = @commits.count
@commits_pages = Paginator.new @commits_count, limit, params['page'] || 1
@offset ||= @commits_pages.offset
@commits = paginateHelper @commits,limit
else
@commits = g.commits(@project.gpid, page:(params[:page].to_i - 1).to_s, ref_name:rev, :search => search)
@commits_count = g.user_static(@project.gpid, :rev => rev).count
@commits_pages = Redmine::Pagination::Paginator.new @commits_count, limit, params[:page]
end
rescue Exception => e
puts e
end
end
# 选择对应的Commit
def commit_for_issue
history_commit_ids = params[:issue_for_commit_ids].split(",") unless params[:issue_for_commit_ids].nil?
@issue_commit_ids = (history_commit_ids.blank? ? params[:checkbox1] : params[:checkbox1] | history_commit_ids).uniq
end
def issue_commit_delete
commit_id = params[:commit_id].split(",")
issue_commit_ids = params[:issue_commit_ids]
# issue_id存在则为issue详情或者编辑的时候否则为新建Issue
# 编辑和详情的时候需要在数据库中删除记录,新建的时候在内存中删除
if params[:issue_id]
commit_issue = CommitIssues.where(:commit_id => commit_id, :issue_id => params[:issue_id], :project_id => @project.id).first
commit_issue.delete if commit_issue
end
@issue_commit_ids = issue_commit_ids - commit_id
end
# over
def index
# 顶部导航
@project_menu_type = 2
@ -163,14 +214,14 @@ class IssuesController < ApplicationController
def show
# 顶部导航
@project_menu_type = 2
# 打开编辑内容
@is_edit = true unless params[:edit].nil?
# 当前用户查看指派给他的缺陷消息,则设置消息为已读
query = ForgeMessage.where("forge_message_type =? and user_id =? and forge_message_id =?", "Issue", User.current, @issue).first
query.update_attribute(:viewed, true) unless query.nil?
# issue 关联的commit
commit_issues = CommitIssues.where(:issue_id => @issue.id, :project_id => @issue.project_id)
@issue_commit_ids = commit_issues.map{|commit_issue| commit_issue.commit_id}
# issue 新建的at消息
User.current.at_messages.unviewed('Issue', @issue.id).each {|x| x.viewed!}
# 回复的at消息
@ -238,6 +289,8 @@ class IssuesController < ApplicationController
@issue.fixed_version_id = nil if @issue.fixed_version_id == 0
@issue.assigned_to_id = nil if @issue.assigned_to_id == 0
if @issue.save
# 关联commmit
update_issue_commit params[:commit_ids]
#params[:issue][:assigned_to_id] = nil if params[:issue][:assigned_to_id].to_i == 0
senduser = User.find(params[:issue][:assigned_to_id])
issue_id = @issue.id
@ -276,6 +329,9 @@ class IssuesController < ApplicationController
def edit
# 修改实例变量的值
return unless update_issue_from_params
# issue 关联的commit
commit_issues = CommitIssues.where(:issue_id => @issue.id, :project_id => @issue.project_id)
@issue_commit_ids = commit_issues.map{|commit_issue| commit_issue.commit_id}
respond_to do |format|
format.html {render :layout => 'base_projects' }#added by young
@ -309,9 +365,9 @@ class IssuesController < ApplicationController
end
end
end
if @saved
# 更新commit关联情况
update_issue_commit params[:commit_ids]
#修改界面增加跟踪者
watcherlist = @issue.watcher_users
select_users = []
@ -356,6 +412,26 @@ class IssuesController < ApplicationController
end
end
# 保存issue的时候相关的commit操作
# commit_ids => "9b9845ff,poor56el"
def update_issue_commit commit_ids
# 关联commmit
commit_ids = params[:commit_ids]
unless commit_ids.blank?
commit_ids = commit_ids.split(",").uniq
if params[:action] == "update"
exist_commit_ids = CommitIssues.where(:issue_id => @issue, :project_id => @issue.project_id)
unless exist_commit_ids.blank?
exist_commit_ids = exist_commit_ids.map{|commit| commit.commit_id}
commit_ids = commit_ids - exist_commit_ids
end
end
commit_ids.each do |commit_id|
CommitIssues.create(:commit_id => commit_id, :project_id => @issue.project_id, :issue_id => @issue.id)
end
end
end
def update_user_issue_detail(issue, params)
case params[:type]
when "status"
@ -794,7 +870,6 @@ class IssuesController < ApplicationController
# 更新issue状态时journal表产生记录返回@current_journal
@issue.init_journal(User.current)
issue_attributes = params[:issue]
if issue_attributes && params[:conflict_resolution]
case params[:conflict_resolution]
@ -809,18 +884,18 @@ class IssuesController < ApplicationController
end
end
senduser = User.find(params[:issue][:assigned_to_id])
if senduser.id != User.current.id && @issue.assigned_to_id != params[:issue][:assigned_to_id].to_i
issue_id = @issue.id
issue_title = params[:issue][:subject]
priority_id = params[:issue][:priority_id]
ps = ProjectsService.new
ps.send_wechat_project_issue_notice senduser,@issue.project,issue_id,issue_title,priority_id
if params[:action] == "update"
senduser = User.find(params[:issue][:assigned_to_id])
if senduser.id != User.current.id && @issue.assigned_to_id != params[:issue][:assigned_to_id].to_i
issue_id = @issue.id
issue_title = params[:issue][:subject]
priority_id = params[:issue][:priority_id]
ps = ProjectsService.new
ps.send_wechat_project_issue_notice senduser,@issue.project,issue_id,issue_title,priority_id
end
end
@issue.safe_attributes = issue_attributes
@priorities = IssuePriority.active
@allowed_statuses = @issue.new_statuses_allowed_to(User.current)
true

View File

@ -77,12 +77,36 @@ module ApplicationHelper
user.nil? ? User.find(2) : user
end
# 通过邮件查找用户,能查到返回用户,否则返回邮件地址
def user_by_mail mail
user = User.find_by_mail(mail)
user.nil? ? mail : user.try(:show_name)
end
def link_to_user_mail(mail, css_class)
user = User.find_by_mail(mail)
user = user.nil? ? mail : user
if user.is_a?(User)
name = user.show_name
link_to name, {:controller=> 'users', :action => 'show', id: user.id}, :class => css_class, :target => "_blank"
else
"<a class='#{css_class}'>#{h(user.to_s)}</a>".html_safe
end
end
# 通过系统外部用户名查找用户,如果用户不存在则用邮箱替换
def get_user_by_login_and login
user = User.find_by_login(login)
(user.nil? || login == "root") ? User.find(2) : user
end
# 登录名来自外部系统
# 通过登录名查找用户,如果用户存在则显示用户姓名,否则显示登录名
def get_user_by_login login
user = User.find_by_login(login)
user.nil? ? login : user.show_name
end
# 重置user_path目的是将id转换成用户名
def user_path(resource, parameters = {})
if Fixnum === resource

View File

@ -27,6 +27,21 @@ module RepositoriesHelper
REPO_IP_ADDRESS = Setting.host_repository
REPO_GITLAB_ADDRESS = "git.trustie.net"
# 获取某次提交的关联Issue
# REDO:一次关联查询
# type为true则为详情页面全部显示
def get_commit_issues commit_id, project_id, type
commit_issues = CommitIssues.where(:commit_id => commit_id, :project_id => project_id)
unless commit_issues.blank?
if commit_issues.count > 2 && type != 1
result = commit_issues.map{|commit_issue| commit_issue.issue_id}.first(2) << "more"
else
result = commit_issues.map{|commit_issue| commit_issue.issue_id}
end
end
return result unless result.blank?
end
# 因为gitlab的提交总数不是实时同步的说以取总数用两种方法
def choise_commit_count git_count, pro_count
git_count > pro_count ? git_count : pro_count

View File

@ -0,0 +1,5 @@
class CommitIssues < ActiveRecord::Base
attr_accessible :commit_id, :issue_id, :project_id
# 之所以没建立关联表主要是应为commit_id是直接通过api获取的不存在trustie端
has_many :issues
end

View File

@ -56,6 +56,8 @@ class Issue < ActiveRecord::Base
has_one :praise_tread_cache, as: :object, dependent: :destroy
# ForgeMessage虚拟关联(多态)
has_many :forge_messages, :class_name => 'ForgeMessage',:as =>:forge_message ,:dependent => :destroy
# 该关联不能关联删除因为commit记录没有存在Trustie数据库中
has_many :commit_issueses
has_many :at_messages, class_name: 'AtMessage', as: :at_message ,:dependent => :destroy

View File

@ -2,5 +2,6 @@
<%#= watcher_link_issue(@issue, User.current) %>
<%= link_to l(:button_copy), project_copy_issue_path(@project, @issue), :class => 'talk_edit fr' if User.current.allowed_to?(:add_issues, @project) %>
<%= link_to l(:button_delete), issue_path(@issue.id), :data => {:confirm => issues_destroy_confirmation_message(@issue)}, :method => :delete, :class => 'talk_edit fr' if User.current.allowed_to?(:delete_issues, @project) %>
<%= link_to l(:button_edit), 'javascript:void(0);', :onclick => 'issueEditShow();', :class => 'talk_edit fr', :accesskey => accesskey(:edit) if @issue.editable? && User.current.allowed_to?(:edit_issues, @project) %>
<%#= link_to l(:button_edit), 'javascript:void(0);', :onclick => 'issueEditShow();', :class => 'talk_edit fr', :accesskey => accesskey(:edit) if @issue.editable? && User.current.allowed_to?(:edit_issues, @project) %>
<%= link_to l(:button_edit), edit_issue_path(@issue), :class => 'talk_edit fr', :accesskey => accesskey(:edit) if @issue.editable? && User.current.allowed_to?(:edit_issues, @project) %>
<%#= link_to l(:label_user_newfeedback), edit_issue_path(@issue.id), :onclick => 'showAndScrollTo("update", "issue_journal_kind_reply"); return false;', :class => 'talk_edit fr', :accesskey => accesskey(:edit) if @issue.editable? && User.current.allowed_to?(:add_issue_notes, @project) %>

View File

@ -1,4 +1,4 @@
<div id="issue_edit" style="display: none">
<div id="issue_edit">
<%= content_for(:header_tags) do %>
<%= import_ke(enable_at: true, prettify: false, init_activity: false) %>
<% end %>

View File

@ -63,7 +63,7 @@
<% end %>
<!--<a href="javascript:void(0);" class="sy_btn_blue mr5 fr"> 保存并继续</a>-->
<!--<a href="javascript:void(0);" onclick="issue_desc_editor.sync();$('#issue-form').submit();" class="sy_btn_blue mr5 fr" id="issue_confirm"> 保存</a>-->
<input onclick="issue_desc_editor.sync();$('#issue-form').submit();" class="sy_btn_blue fr mr5" onfocus="this.blur()" id="issue_confirm" style="width: 28px;color: #FFF" value="保存">
<input onclick="issue_create();" class="sy_btn_blue fr mr5" onfocus="this.blur()" id="issue_confirm" style="width: 28px;color: #FFF" value="保存">
</li>
</ul>
<ul class="fl pro_new_conbox_right ml10 mb10">
@ -74,28 +74,28 @@
<label class="fl ml5" for="issue_is_private" id="issue_is_private_tips"><%= l(:field_set_private_tips)%></label>
<% end %>
</li>
<li class=" clear" id="versions_assigned_id">
<li class="clear" id="versions_assigned_id">
<% if @issue.safe_attribute? 'assigned_to_id' %>
<%= f.select :assigned_to_id, assigned_options_for_select(@issue.assignable_users, @issue.assigned_to),
{:required => @issue.required_attribute?('assigned_to_id'), :no_label => true},
{:onchange => "change_assigned_tip();",:class => "w150"} %>
<% end %>
</li>
<li class=" clear" id="assigned_to_tips">
<li class="clear" id="assigned_to_tips">
<%= @issue.assigned_to.nil? ? "未指派" : "已指派" %>
</li>
<li class=" clear" >
<li class="clear" >
<%= f.select :fixed_version_id, version_options_for_select(@issue.assignable_versions, @issue.fixed_version),
{:include_blank => true, :required => @issue.required_attribute?('fixed_version_id'), :no_label => true},
{:onchange => "change_milestone_tip();", :class => "w150"} %>
</li>
<li class=" clear" id="milestone_option_tips">
<li class="clear" id="milestone_option_tips">
<%= @issue.fixed_version.nil? ? "未选择里程碑" : "已选择里程碑" %>
<% if params[:action] == "new" %>
<%= link_to "", new_project_version_path(@project, :is_issue => true, :issue_project_id => @project.id), :class => "pic_add mt5 ml5 fr", :remote => true %>
<% end %>
</li>
<li class=" clear" style="border:1px solid #c8c8c8;">
<li class="clear" style="border:1px solid #c8c8c8;">
<% if @issue.safe_attribute? 'start_date' %>
<%= f.text_field :start_date, :size => 22, :disabled => !@issue.leaf?, :no_label => true,
:required => @issue.required_attribute?('start_date'), :onchange => "issue_start_date_change();",
@ -103,41 +103,86 @@
<%= calendar_for('issue_start_date', 'start_date') if @issue.leaf? %>
<% end %>
</li>
<li class=" clear" id="option_start_date_tips">
<li class="clear" id="option_start_date_tips">
<%= @issue.start_date.nil? ? "未选择开始日期" : "已选择开始日期" %>
</li>
<li class=" clear" style="border:1px solid #c8c8c8;">
<li class="clear" style="border:1px solid #c8c8c8;">
<label class="label02" ></label>
<% if @issue.safe_attribute? 'due_date' %>
<%= f.text_field :due_date, :size => 22, :disabled => !@issue.leaf?, :no_label => true,
:required => @issue.required_attribute?('due_date'), :onchange => "issue_end_date_change();",
:class => "fl calendar_input",:style => "width: 170px;", :placeholder => "请选择结束日期" %>
:required => @issue.required_attribute?('due_date'), :onchange => "issue_end_date_change();",
:class => "fl calendar_input",:style => "width: 170px;", :placeholder => "请选择结束日期" %>
<%= calendar_for('issue_due_date', 'start_date') if @issue.leaf? %>
<% end %>
</li>
<li class=" clear " id="option_end_date_tips">
<li class="clear " id="option_end_date_tips">
<%= @issue.due_date.nil? ? "未选择结束日期" : "已选择结束日期" %>
</li>
<li class=" clear">
<li class="clear">
<% if @issue.safe_attribute? 'estimated_hours' %>
<%= f.text_field :estimated_hours, :size => 22, :disabled => !@issue.leaf?, :no_label => true,
:required => @issue.required_attribute?('estimated_hours'), :placeholder => "请填写预计工时" %>
:required => @issue.required_attribute?('estimated_hours'), :placeholder => "请填写预计工时" %>
<% end %>
</li>
<li class=" clear"><%= l(:field_estimated_hours) %></li>
<li class="clear"><%= l(:field_estimated_hours) %></li>
<li class=" clear">
<li class="clear">
<% if @issue.safe_attribute?('done_ratio') && @issue.leaf? && Issue.use_field_for_done_ratio? %>
<%= f.select :done_ratio, ((0..10).to_a.collect { |r| ["#{r*10} %", r*10] }),
{:required => @issue.required_attribute?('done_ratio'), :no_label => true},
:onchange => "PrecentChange(this.value)",
:class => "w150" %>
{:required => @issue.required_attribute?('done_ratio'), :no_label => true},
:onchange => "PrecentChange(this.value)",
:class => "w150" %>
<% end %>
<li class=" clear">完成度</li>
</li>
<li class="clear">完成度</li>
<% if @project.gpid %>
<%#= hidden_field_tag @issue_commit_ids %>
<input value="" name="commit_ids" id="commit_ids" type="hidden">
<li class="clear"><span>关联Commit</span>
<a href="javascript:void(0)" onclick="get_issue_commit_ids('issue_commit_ids','<%= @project.id %>');">
<span class='btn-commit btn-blue mt-2 fr'>+</span>
</a>
</li>
<div id="issue_commit_ids">
<%= render :partial => "issues/issue_commit_ids", :locals => {:f => f} %>
</div>
<% end %>
</ul>
<% end %>
<script>
function issue_create(){
var issue_commit_ids = $("#issue_commit_ids .commit_id_value");
var str = "";
for(var i=0; i < issue_commit_ids.length; i++){
str += $(issue_commit_ids[i]).html();
if(i != issue_commit_ids.length -1){
str += ",";
}
}
issue_desc_editor.sync();
$('#commit_ids').val(str);
$('#issue-form').submit();
}
function get_issue_commit_ids(id, project_id){
var issue_commit_ids = $("#issue_commit_ids .commit_id_value");
var str = "";
for(var i=0; i < issue_commit_ids.length; i++){
str += $(issue_commit_ids[i]).html();
if(i != issue_commit_ids.length -1){
str += ",";
}
}
$.ajax({
url: '<%= url_for(:controller => 'issues', :action => 'issue_commits') %>',
type:'get',
data:{
project_id: project_id,
issue_commit_ids: str
}
})
}
function change_assigned_tip() {
if( document.getElementById('issue_assigned_to_id').options[document.getElementById('issue_assigned_to_id').selectedIndex].value == 0 ){
$('#assigned_to_tips').html("未指派");

View File

@ -0,0 +1,10 @@
<% if @issue_commit_ids %>
<% @issue_commit_ids.each do |commit_id| %>
<div class="btn btn-blue mb5">
<%= link_to commit_id[0,8], {:controller => 'repositories', :action => 'commit_diff', :id => @project.id, :changeset => commit_id}, :target => "_blank", :class => "commit_id_value" %>
<%= link_to "×", issue_commit_delete_issues_path(:commit_id => commit_id, :project_id => @project.id, :issue_commit_ids => @issue_commit_ids, :issue_id => @issue.try(:id)), :remote => true, :style => "color:#fff;" %>
</div>
<% end %>
<% else %>
<div class="c_grey">暂无</div>
<% end %>

View File

@ -0,0 +1,42 @@
<div style="width:745px;">
<div class="muban_popup_top">
<h3 class="fl">关联Commit</h3>
<a href="javascript:void(0);" class="muban_icons_close fr"></a>
<div class="cl"></div>
</div>
<div class="muban_popup_con " >
<div class="newupload_conbox " >
<% if @commits.blank? %>
<%= render :partial => "projects/no_data" %>
<% else %>
<div class=" clear">
<div class="cl"></div>
<%= form_tag(url_for(:controller => 'issues', :action => 'issue_commits', :project_id => @project.id, :type => "search"),
:remote => true, :method => 'get', :id => 'issue_commit_form', :class => "fl") do %>
<ul class="clear lightheight28 fl mr100">
<li class="mb10 clear fl">
<span class=" fl">&nbsp;分支&nbsp;&nbsp;:&nbsp;</span>
<%= select_tag :branch, options_for_select(["#{@default_branch}"]+ @branch_names, @rev),
:class => "fl newupload_select", :style => "width:180px;height:28px;",
:onchange => "$('#issue_commit_form').submit();" %>
</li>
</ul>
<div class="hw_search_box fr mb10" >
<input type="text" name="search" placeholder="输入资源关键词进行搜索" class="hw_search-input" style="width:300px;">
<%= submit_tag '', :class => 'hw_btn_search', :onfocus => 'this.blur();', :style => 'border-style:none' %>
</div>
<% end %>
</div>
<div id="issue_commit_list">
<%= render :partial => "issues/issue_commits_list" %>
</div>
<% end %>
</div>
</div>
</div>
<script>
function remote_function(id) {
$(id).submit();
}
</script>

View File

@ -0,0 +1,59 @@
<%= form_tag(url_for(:controller => 'issues', :action => 'commit_for_issue', :project_id => @project.id), :remote => true, :method => 'get', :id => 'commit_for_issue', :class => "fl") do %>
<table class="newupload_table " cellspacing="0" cellpadding="0">
<thead>
<tr>
<th class="newupload_td01">&nbsp;</th>
<th class="newupload_td04">修订号</th>
<th>描述</th>
<th class="newupload_td04">提交者</th>
<th class="newupload_td05">提交日期</th>
</tr>
</thead>
<tbody>
<% @commits.each do |commit| %>
<tr>
<td class="newupload_td01"><input type="checkbox" value="<%= commit.short_id %>" name="checkbox1[]"> </td>
<td class="newupload_td04"><span class="newupload_table_name">
<%= link_to commit.id[0,8], {:controller => 'repositories', :action => 'commit_diff', :id => @project.id, :changeset => commit.id}, :target => "_blank" %></span>
</td>
<td class="newupload_td02"><p><%= commit.title %></p></td>
<td class="newupload_td04"><span class="newupload_table_name"><%= link_to_user_mail(commit.author_email, "") %></span></td>
<td class="newupload_td05"><%= format_date(commit.created_at) %></td>
</tr>
<% end %>
</tbody>
<input value="" name="issue_for_commit_ids" id="issue_for_commit_ids" type="hidden">
</table>
<div class="clear">
<div class="clear fl mt10 mb10">
<a href="javascript:void(0);" class="sy_btn_blue fl" onclick="search_and_branch_for_commit_ids();">确&nbsp;&nbsp;定</a>
<a href="javascript:void(0);" class="sy_btn_grey fl ml10" onclick="hideModal()">取&nbsp;&nbsp;消</a>
</div>
<div style="text-align:center;">
<div class="pages" style="width:auto; display:inline-block;">
<ul id="homework_pository_ref_pages">
<%= pagination_links_full @commits_pages, @commits_count, :per_page_links => false, :remote => true, :flag => true, :is_new => true %>
</ul>
<div class="cl"></div>
</div>
</div>
<div class="cl"></div>
</div>
<% end %>
<script>
function search_and_branch_for_commit_ids(){
var issue_commit_ids = $("#issue_commit_ids .commit_id_value");
var str = "";
for(var i=0; i < issue_commit_ids.length; i++){
str += $(issue_commit_ids[i]).html();
if(i != issue_commit_ids.length -1){
str += ",";
}
}
alert(str);
$('#issue_for_commit_ids').val(str);
$('#commit_for_issue').submit();
hideModal();
}
</script>

View File

@ -0,0 +1 @@
$("#issue_commit_ids").html('<%= escape_javascript(render :partial => 'issues/issue_commit_ids') %>');

View File

@ -1,6 +1,7 @@
<h3><%=h "#{@issue.tracker.name} ##{@issue.id}" %></h3>
<div id="issue_edit_show" class="mt10 pro_newissue_con">
<%= render :partial => 'issues/edit' %>
<% content_for :header_tags do %>
<%= robot_exclusion_tag %>
<% end %>
<%= render :partial => 'edit' %>
<% content_for :header_tags do %>
<%= robot_exclusion_tag %>
<% end %>
</div>

View File

@ -0,0 +1 @@
$("#issue_commit_ids").html('<%= escape_javascript(render :partial => 'issues/issue_commit_ids') %>');

View File

@ -0,0 +1,7 @@
<% if @type %>
$("#issue_commit_list").html('<%= escape_javascript(render :partial => 'issues/issue_commits_list') %>');
<% else %>
var htmlvalue = "<%= escape_javascript(render :partial => 'issues/issue_commits') %>";
pop_box_new(htmlvalue,760,600);
<% end %>

View File

@ -5,16 +5,7 @@
<script>
sd_create_editor_from_data(<%= @issue.id%>, null, "100%", "<%= @issue.class.name %>");
</script>
<script type="text/javascript">
$(function(){
$("#RSide").removeAttr("id");
$("#Container").css("width","1000px");
is_edit = <%= @is_edit.present? && @is_edit == true %>
if(is_edit) {
issueEditShow();
}
});
</script>
<div class="mt10 mb10" id =issue_show_total"">
<div class="banner-big f16 fontGrey3">
问题跟踪
@ -46,9 +37,6 @@
</div>
</div>
<div id="issue_edit_show" class="mt10 pro_newissue_con">
<%= render :partial => 'issues/edit'%>
</div>
<ul class="fr pro_new_conbox_right" id="project_issue_info_show">
<li class="clear">
<span class="pro_new_conbox_leftspan fl">当前状态</span>
@ -86,6 +74,11 @@
<span class="pro_new_conbox_rightspan fl ml10"><%= @issue.done_ratio %>%</span>
</li>
<% end %>
<li class="clear"><span class="pro_new_conbox_leftspan mb5">关联Commit</span>
<div id="issue_commit_ids">
<%= render :partial => "issues/issue_commit_ids" %>
</div>
</li>
</ul>
<div class="cl"></div>
</div>

View File

@ -14,9 +14,19 @@
<% commits.each do |commit| %>
<li class="clear">
<span class="fl c_grey ml15 "><%= time_tag(commit.created_at) %>前</span>
<%= link_to get_user_by_mail(commit.author_email).show_name, user_path(get_user_by_mail(commit.author_email)), :target => "_blank", :class => "pullreques_pull_name fl ml10" %>
<%= link_to_user_mail(commit.author_email, "pullreques_pull_name fl ml10") %>
<p class="pullreques_pull_txt ml10 fl"><%= commit.title %></p>
<%= link_to truncate(commit.short_id, :length => 20), {:controller => 'repositories', :action => 'commit_diff', :id => @project.id, :changeset => commit.id}, :target => "_blank", :class => "fr mr15 c_grey" %>
<% get_commit_issues(commit.short_id, @project.id, 0).each do |issue_id| %>
<div class="btn-commit-issue btn-blue mb5 mr5 fr">
<% if issue_id == "more" %>
<%= link_to "更多", {:controller => 'repositories', :action => 'commit_diff', :id => @project.id, :changeset => commit.id}, :target => "_blank", :class => "commit_id_value mr5" %>
<% else %>
<%= link_to "##{issue_id}", issue_path(issue_id), :target => "_blank", :class => "commit_id_value mr5" %>
<% end %>
</div>
<% end %>
<div class="cl"></div>
</li>
<% end %>
</ul>

View File

@ -8,12 +8,18 @@
<div class="c_grey02 mb10">
<p><%= @commit_details.message %></p>
</div>
<!--<div class=" clear mb10">-->
<!--<p class="fb">关联Issue:</p>-->
<!--<a href="javascript:void(0);" class="btn-small fl mr10">#123</a>-->
<!--<a href="javascript:void(0);" class="btn-small fl mr10">#123</a>-->
<!--<a href="javascript:void(0);" class="btn-small fl mr10">#123</a>-->
<!--</div>-->
<div class=" clear mb10">
<p class="fb c_grey">关联Issue:</p>
<% get_commit_issues(@commit_details.short_id, @project.id, 1).each do |issue_id| %>
<div class="btn-commit-issue btn-blue mb5 mr5">
<% if issue_id == "more" %>
<%= link_to "更多", {:controller => 'repositories', :action => 'commit_diff', :id => @project.id, :changeset => @commit_details.id}, :target => "_blank", :class => "commit_id_value mr5" %>
<% else %>
<%= link_to "##{issue_id}", issue_path(issue_id), :target => "_blank", :class => "commit_id_value mr5" %>
<% end %>
</div>
<% end %>
</div>
<li class="commit js-toggle-container">
<%= render :partial => 'commit_details', :locals => {:changeset => @commit_details} %>
</li>

View File

@ -952,6 +952,9 @@ RedmineApp::Application.routes.draw do
collection do
match 'bulk_edit', :via => [:get, :post]
post 'bulk_update'
get 'issue_commits'
get 'commit_for_issue'
get 'issue_commit_delete'
end
member do
post 'add_journal'

View File

@ -0,0 +1,11 @@
class CreateCommitIssues < ActiveRecord::Migration
def change
create_table :commit_issues do |t|
t.string :commit_id
t.integer :issue_id
t.integer :project_id
t.timestamps
end
end
end

View File

@ -52,6 +52,7 @@ class Gitlab::Client
# @option options [String] :ref_name The branch or tag name of a project repository.
# @option options [Integer] :page The page number.
# @option options [Integer] :per_page The number of results per page.
# @option options [String] :search The obj of results's search value.
# @return [Array<Gitlab::ObjectifiedHash>]
def commits(project, options={})
get("/projects/#{project}/repository/commits", :query => options)

View File

@ -1488,6 +1488,8 @@ function pop_up_box(value,tWidth,tTop,tLeft){
}
// 公共弹框样式
// 建议左右栏的Width460Height190
// 建议宽屏对应值Width760Height500
function pop_box_new(value, Width, Height){
w = ($(window).width() - Width)/2;
h = ($(window).height() - Height)/2;

View File

@ -20,6 +20,8 @@ input.radio-width90{ width: 90px; }
.muban_icons_blue{font-size: 12px;padding: 0 5px;border-radius: 3px;line-height: 14px;color: #3b94d6;border: 1px solid #3b94d6;}
/*模板buttons 20161013byLB*/
.btn{display: inline-block;border:none; padding:0 10px;color: #333;background: #e1e1e1; text-align:center;font-size: 12px; height: 30px;line-height: 30px;-webkit-border-radius: 3px;-moz-border-radius: 3px; -o-border-radius: 3px; border-radius: 3px; }
.btn-commit-issue{display: inline-block;border:none; padding:0 5px;color: #333;background: #e1e1e1; text-align:center;font-size: 12px; height: 20px;line-height: 20px;-webkit-border-radius: 3px;-moz-border-radius: 3px; -o-border-radius: 3px; border-radius: 3px; margin-top: 6px;}
.btn-commit{display: inline-block;border:none; padding:0 10px;color: #333;background: #e1e1e1; text-align:center;font-size: 12px; height: 20px;-webkit-border-radius: 3px;-moz-border-radius: 3px; -o-border-radius: 3px; border-radius: 3px; }
.btn:hover{background: #c3c3c3; color: #333;}
.btn-grey{background: #d9d9d9; color: #656565;}
.btn-grey:hover{background: #717171; color: #fff;}

View File

@ -788,6 +788,7 @@ a:hover.issues_list_title{color:#3b94d6;}
.hw_search_box{ position:relative; }
.hw_search_box input.hw_search-input{ width:293px; height:28px; border:none; border:1px solid #e7e7e7; background:#fff; padding-left:5px;padding-right: 25px;}
.hw_search_box a.hw_btn_search{display:block; width:20px; height:20px; background:url(/images/hw/icons_hw.png) 0 -57px no-repeat; position:absolute; right:5px; top:5px; cursor:pointer;}
.hw_search_box input.hw_btn_search{display:block; width:20px; height:20px; background:url(/images/hw/icons_hw.png) 0 -57px no-repeat; position:absolute; right:5px; top:5px; cursor:pointer;}
.hw_search_box a:hover.hw_btn_search{background:url(/images/hw/icons_hw.png) -40px -57px no-repeat;}
.hw_files_icon{display:block; width:17px; height:14px; background:url(../images/hw/icons_hw.png) 0 -135px no-repeat;}
/* 编辑删除 与课程相同 */
@ -1001,8 +1002,8 @@ a.pullreques_reply_name{ font-weight: bold; color: #333;}
.pullreques_reply_txt{ width: 900px;color: #666;}
.pullreques_pull_top { width: 100%; height: 40px; line-height: 40px; background: #f4f4f4; border-top:1px solid #e1e1e1;border-bottom:1px solid #e1e1e1;}
a.pullreques_pull_name{display: block; margin-left: 5px;max-width:80px; color:#3b94d6 !important; overflow:hidden;white-space: nowrap; text-overflow:ellipsis;}
.pullreques_pull_list li{ height: 30px; line-height: 30px; }
.pullreques_pull_txt{display: block; margin-left: 10px;max-width:740px; overflow:hidden;white-space: nowrap; text-overflow:ellipsis;}
.pullreques_pull_list li{ height: 35px; line-height: 35px; }
.pullreques_pull_txt{display: block; margin-left: 10px;max-width:640px; overflow:hidden;white-space: nowrap; text-overflow:ellipsis;}
.pullreques_change_list li{height: 40px; line-height: 40px;border-bottom:1px solid #e1e1e1; }
.pullreques_change_list li:last-child{ border-bottom: none;}
.pullreques_icons_add{background: url(/images/new_project/icons_issue.png) 0 -374px no-repeat; display: inline-block; width: 19px; height: 16px;}
@ -1056,4 +1057,5 @@ table.text-file{}
.old{ background:#ffecec; }
.old:hover{ background:#fffaf1; }
.new{ background: #eaffea;}
.new:hover{ background:#fffaf1; }
.new:hover{ background:#fffaf1; }
.commit_id_value{color: white !important;}

View File

@ -0,0 +1,8 @@
FactoryGirl.define do
factory :commit_issue, :class => 'CommitIssues' do
commit_id "MyString"
issue_id 1
project_id 1
end
end

View File

@ -0,0 +1,5 @@
require 'rails_helper'
RSpec.describe CommitIssues, :type => :model do
pending "add some examples to (or delete) #{__FILE__}"
end