Merge branch 'feature/issue_tags' of dev.gitlabhq.com:gitlabhq
This commit is contained in:
commit
7ef180608f
2
Gemfile
2
Gemfile
|
@ -29,7 +29,7 @@ gem "thin"
|
||||||
gem "unicorn"
|
gem "unicorn"
|
||||||
gem "git"
|
gem "git"
|
||||||
gem "acts_as_list"
|
gem "acts_as_list"
|
||||||
gem "acts-as-taggable-on", "~> 2.1.0"
|
gem "acts-as-taggable-on", "2.3.1"
|
||||||
gem "drapper"
|
gem "drapper"
|
||||||
gem "resque", "~> 1.20.0"
|
gem "resque", "~> 1.20.0"
|
||||||
gem "httparty"
|
gem "httparty"
|
||||||
|
|
|
@ -89,8 +89,8 @@ GEM
|
||||||
activesupport (3.2.5)
|
activesupport (3.2.5)
|
||||||
i18n (~> 0.6)
|
i18n (~> 0.6)
|
||||||
multi_json (~> 1.0)
|
multi_json (~> 1.0)
|
||||||
acts-as-taggable-on (2.1.1)
|
acts-as-taggable-on (2.3.1)
|
||||||
rails
|
rails (~> 3.0)
|
||||||
acts_as_list (0.1.6)
|
acts_as_list (0.1.6)
|
||||||
addressable (2.2.8)
|
addressable (2.2.8)
|
||||||
ansi (1.4.2)
|
ansi (1.4.2)
|
||||||
|
@ -351,7 +351,7 @@ PLATFORMS
|
||||||
ruby
|
ruby
|
||||||
|
|
||||||
DEPENDENCIES
|
DEPENDENCIES
|
||||||
acts-as-taggable-on (~> 2.1.0)
|
acts-as-taggable-on (= 2.3.1)
|
||||||
acts_as_list
|
acts_as_list
|
||||||
annotate!
|
annotate!
|
||||||
autotest
|
autotest
|
||||||
|
|
|
@ -61,3 +61,18 @@ function initIssuesSearch() {
|
||||||
$(this).closest('tr').fadeOut(); updatePage();
|
$(this).closest('tr').fadeOut(); updatePage();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Init issues page
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
function issuesPage(){
|
||||||
|
initIssuesSearch();
|
||||||
|
setSortable();
|
||||||
|
$("#label_name").chosen();
|
||||||
|
$("#assignee_id").chosen();
|
||||||
|
$("#milestone_id").chosen();
|
||||||
|
$("#milestone_id, #assignee_id, #label_name").on("change", function(){
|
||||||
|
$(this).closest("form").submit();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
|
@ -622,10 +622,6 @@ li.note {
|
||||||
margin-right:5px;
|
margin-right:5px;
|
||||||
margin-top: 2px;
|
margin-top: 2px;
|
||||||
@include border-radius(4px);
|
@include border-radius(4px);
|
||||||
&.critical {
|
|
||||||
background: #EAA;
|
|
||||||
border:1px solid #B88;
|
|
||||||
}
|
|
||||||
&.today{
|
&.today{
|
||||||
background: #ADA;
|
background: #ADA;
|
||||||
border:1px solid #8B8;
|
border:1px solid #8B8;
|
||||||
|
@ -664,14 +660,6 @@ li.note {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&.critical {
|
|
||||||
background: #FEE;
|
|
||||||
border-color:#ECC;
|
|
||||||
.icon {
|
|
||||||
background: #EAA;
|
|
||||||
border:1px solid #B88;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
&.today{
|
&.today{
|
||||||
background: #EFE;
|
background: #EFE;
|
||||||
border-color:#CEC;
|
border-color:#CEC;
|
||||||
|
|
|
@ -177,6 +177,14 @@ a:focus {
|
||||||
&.label-important {
|
&.label-important {
|
||||||
background-color: #B94A48;
|
background-color: #B94A48;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&.label-issue {
|
||||||
|
background-color: #eee;
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
padding:4px 6px;
|
||||||
|
color:#444;
|
||||||
|
text-shadow:0 0 1px #fff;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.nav-tabs > li > a, .nav-pills > li > a {
|
.nav-tabs > li > a, .nav-pills > li > a {
|
||||||
|
|
|
@ -3,6 +3,8 @@ class IssuesController < ApplicationController
|
||||||
before_filter :project
|
before_filter :project
|
||||||
before_filter :module_enabled
|
before_filter :module_enabled
|
||||||
before_filter :issue, :only => [:edit, :update, :destroy, :show]
|
before_filter :issue, :only => [:edit, :update, :destroy, :show]
|
||||||
|
helper_method :issues_filter
|
||||||
|
|
||||||
layout "project"
|
layout "project"
|
||||||
|
|
||||||
# Authorize
|
# Authorize
|
||||||
|
@ -130,16 +132,26 @@ class IssuesController < ApplicationController
|
||||||
end
|
end
|
||||||
|
|
||||||
def issues_filtered
|
def issues_filtered
|
||||||
@issues = case params[:f].to_i
|
@issues = case params[:f]
|
||||||
when 1 then @project.issues
|
when issues_filter[:all] then @project.issues
|
||||||
when 2 then @project.issues.closed
|
when issues_filter[:closed] then @project.issues.closed
|
||||||
when 3 then @project.issues.opened.assigned(current_user)
|
when issues_filter[:to_me] then @project.issues.opened.assigned(current_user)
|
||||||
else @project.issues.opened
|
else @project.issues.opened
|
||||||
end
|
end
|
||||||
|
|
||||||
@issues = @issues.where(:assignee_id => params[:assignee_id]) if params[:assignee_id].present?
|
@issues = @issues.where(:assignee_id => params[:assignee_id]) if params[:assignee_id].present?
|
||||||
@issues = @issues.where(:milestone_id => params[:milestone_id]) if params[:milestone_id].present?
|
@issues = @issues.where(:milestone_id => params[:milestone_id]) if params[:milestone_id].present?
|
||||||
@issues = @issues.includes(:author, :project).order("critical, updated_at")
|
@issues = @issues.tagged_with(params[:label_name]) if params[:label_name].present?
|
||||||
|
@issues = @issues.includes(:author, :project).order("updated_at")
|
||||||
@issues
|
@issues
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def issues_filter
|
||||||
|
{
|
||||||
|
all: "1",
|
||||||
|
closed: "2",
|
||||||
|
to_me: "3",
|
||||||
|
open: "0"
|
||||||
|
}
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -30,7 +30,7 @@ class MergeRequestsController < ApplicationController
|
||||||
else @merge_requests.opened
|
else @merge_requests.opened
|
||||||
end.page(params[:page]).per(20)
|
end.page(params[:page]).per(20)
|
||||||
|
|
||||||
@merge_requests = @merge_requests.includes(:author, :project).order("created_at desc")
|
@merge_requests = @merge_requests.includes(:author, :project).order("closed, created_at desc")
|
||||||
end
|
end
|
||||||
|
|
||||||
def show
|
def show
|
||||||
|
|
|
@ -28,9 +28,12 @@ module IssuesHelper
|
||||||
|
|
||||||
def issue_css_classes issue
|
def issue_css_classes issue
|
||||||
classes = "issue"
|
classes = "issue"
|
||||||
classes << " critical" if issue.critical
|
|
||||||
classes << " closed" if issue.closed
|
classes << " closed" if issue.closed
|
||||||
classes << " today" if issue.today?
|
classes << " today" if issue.today?
|
||||||
classes
|
classes
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def issue_tags
|
||||||
|
@project.issues.tag_counts_on(:labels).map(&:name)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
class Issue < ActiveRecord::Base
|
class Issue < ActiveRecord::Base
|
||||||
include Upvote
|
include Upvote
|
||||||
|
|
||||||
|
acts_as_taggable_on :labels
|
||||||
|
|
||||||
belongs_to :project
|
belongs_to :project
|
||||||
belongs_to :milestone
|
belongs_to :milestone
|
||||||
belongs_to :author, :class_name => "User"
|
belongs_to :author, :class_name => "User"
|
||||||
|
@ -31,9 +33,6 @@ class Issue < ActiveRecord::Base
|
||||||
validates :description,
|
validates :description,
|
||||||
:length => { :within => 0..2000 }
|
:length => { :within => 0..2000 }
|
||||||
|
|
||||||
scope :critical, where(:critical => true)
|
|
||||||
scope :non_critical, where(:critical => false)
|
|
||||||
|
|
||||||
scope :opened, where(:closed => false)
|
scope :opened, where(:closed => false)
|
||||||
scope :closed, where(:closed => true)
|
scope :closed, where(:closed => true)
|
||||||
scope :assigned, lambda { |u| where(:assignee_id => u.id)}
|
scope :assigned, lambda { |u| where(:assignee_id => u.id)}
|
||||||
|
|
|
@ -13,7 +13,7 @@ class Project < ActiveRecord::Base
|
||||||
has_many :users, :through => :users_projects
|
has_many :users, :through => :users_projects
|
||||||
has_many :events, :dependent => :destroy
|
has_many :events, :dependent => :destroy
|
||||||
has_many :merge_requests, :dependent => :destroy
|
has_many :merge_requests, :dependent => :destroy
|
||||||
has_many :issues, :dependent => :destroy, :order => "position"
|
has_many :issues, :dependent => :destroy, :order => "closed, position"
|
||||||
has_many :milestones, :dependent => :destroy
|
has_many :milestones, :dependent => :destroy
|
||||||
has_many :users_projects, :dependent => :destroy
|
has_many :users_projects, :dependent => :destroy
|
||||||
has_many :notes, :dependent => :destroy
|
has_many :notes, :dependent => :destroy
|
||||||
|
|
|
@ -3,15 +3,6 @@
|
||||||
%small (assigned to you)
|
%small (assigned to you)
|
||||||
%small.right #{@issues.total_count} issues
|
%small.right #{@issues.total_count} issues
|
||||||
|
|
||||||
%br
|
|
||||||
.issues_legend
|
|
||||||
.list_legend
|
|
||||||
.icon.critical
|
|
||||||
.text Critical
|
|
||||||
|
|
||||||
.list_legend
|
|
||||||
.icon.today
|
|
||||||
.text Today
|
|
||||||
.clearfix
|
.clearfix
|
||||||
- if @issues.any?
|
- if @issues.any?
|
||||||
- @issues.group_by(&:project).each do |group|
|
- @issues.group_by(&:project).each do |group|
|
||||||
|
|
|
@ -9,32 +9,38 @@
|
||||||
.issue_form_box
|
.issue_form_box
|
||||||
.issue_title
|
.issue_title
|
||||||
.clearfix
|
.clearfix
|
||||||
= f.label :title, "Issue Subject *"
|
= f.label :title do
|
||||||
|
%strong= "Subject *"
|
||||||
.input
|
.input
|
||||||
= f.text_field :title, :maxlength => 255, :class => "xxlarge"
|
= f.text_field :title, :maxlength => 255, :class => "xxlarge"
|
||||||
.issue_middle_block
|
.issue_middle_block
|
||||||
.issue_assignee
|
.issue_assignee
|
||||||
= f.label :assignee_id, "Assign to"
|
= f.label :assignee_id do
|
||||||
.input= f.select(:assignee_id, @project.users.all.collect {|p| [ p.name, p.id ] }, { :include_blank => "Assign to user" })
|
%i.icon-user
|
||||||
|
Assign to
|
||||||
|
.input= f.select(:assignee_id, @project.users.all.collect {|p| [ p.name, p.id ] }, { :include_blank => "Select a user" })
|
||||||
.issue_milestone
|
.issue_milestone
|
||||||
= f.label :milestone_id
|
= f.label :milestone_id do
|
||||||
|
%i.icon-time
|
||||||
|
Milestone
|
||||||
.input= f.select(:milestone_id, @project.milestones.active.all.collect {|p| [ p.title, p.id ] }, { :include_blank => "Select milestone" })
|
.input= f.select(:milestone_id, @project.milestones.active.all.collect {|p| [ p.title, p.id ] }, { :include_blank => "Select milestone" })
|
||||||
|
|
||||||
.issue_description
|
.issue_description
|
||||||
.clearfix
|
.clearfix
|
||||||
= f.label :critical, "Critical"
|
= f.label :label_list do
|
||||||
.input= f.check_box :critical
|
%i.icon-tag
|
||||||
|
Labels
|
||||||
|
.input
|
||||||
|
= f.text_field :label_list, :maxlength => 2000, :class => "xxlarge"
|
||||||
|
%p.hint Separate with comma.
|
||||||
|
|
||||||
- unless @issue.new_record?
|
|
||||||
.clearfix
|
.clearfix
|
||||||
= f.label :closed
|
= f.label :description, "Details"
|
||||||
.input= f.check_box :closed
|
|
||||||
.clearfix
|
|
||||||
= f.label :description, "Issue Details"
|
|
||||||
.input
|
.input
|
||||||
= f.text_area :description, :maxlength => 2000, :class => "xxlarge", :rows => 14
|
= f.text_area :description, :maxlength => 2000, :class => "xxlarge", :rows => 14
|
||||||
%p.hint Markdown is enabled.
|
%p.hint Markdown is enabled.
|
||||||
|
|
||||||
|
|
||||||
.actions
|
.actions
|
||||||
- if @issue.new_record?
|
- if @issue.new_record?
|
||||||
= f.submit 'Submit new issue', :class => "primary btn"
|
= f.submit 'Submit new issue', :class => "primary btn"
|
||||||
|
|
|
@ -1,7 +1,4 @@
|
||||||
- @issues.select(&:critical).each do |issue|
|
- @issues.each do |issue|
|
||||||
= render(:partial => 'issues/show', :locals => {:issue => issue})
|
|
||||||
|
|
||||||
- @issues.reject(&:critical).each do |issue|
|
|
||||||
= render(:partial => 'issues/show', :locals => {:issue => issue})
|
= render(:partial => 'issues/show', :locals => {:issue => issue})
|
||||||
|
|
||||||
- if @issues.present?
|
- if @issues.present?
|
||||||
|
|
|
@ -2,6 +2,11 @@
|
||||||
.list_legend
|
.list_legend
|
||||||
.icon
|
.icon
|
||||||
.right
|
.right
|
||||||
|
- issue.labels.each do |label|
|
||||||
|
%span.label.label-issue
|
||||||
|
%i.icon-tag
|
||||||
|
= label.name
|
||||||
|
|
||||||
- if issue.notes.any?
|
- if issue.notes.any?
|
||||||
%span.btn.small.disabled.padded
|
%span.btn.small.disabled.padded
|
||||||
%i.icon-comment
|
%i.icon-comment
|
||||||
|
|
|
@ -13,58 +13,38 @@
|
||||||
= hidden_field_tag :status, params[:f]
|
= hidden_field_tag :status, params[:f]
|
||||||
= search_field_tag :issue_search, nil, { :placeholder => 'Search', :class => 'issue_search span3 right neib' }
|
= search_field_tag :issue_search, nil, { :placeholder => 'Search', :class => 'issue_search span3 right neib' }
|
||||||
|
|
||||||
%br
|
|
||||||
|
|
||||||
.issues_legend
|
|
||||||
.list_legend
|
|
||||||
.icon.today
|
|
||||||
.text Today
|
|
||||||
|
|
||||||
.list_legend
|
|
||||||
.icon.critical
|
|
||||||
.text Critical
|
|
||||||
|
|
||||||
.list_legend
|
|
||||||
.icon.closed
|
|
||||||
.text Closed
|
|
||||||
.clearfix
|
.clearfix
|
||||||
|
|
||||||
%div#issues-table-holder.ui-box
|
%div#issues-table-holder.ui-box
|
||||||
.title
|
.title
|
||||||
.row
|
.left
|
||||||
.span4
|
|
||||||
%ul.nav.nav-pills.left
|
%ul.nav.nav-pills.left
|
||||||
%li{:class => ("active" if (params[:f] == "0" || !params[:f]))}
|
%li{:class => ("active" if (params[:f] == issues_filter[:open] || !params[:f]))}
|
||||||
= link_to project_issues_path(@project, :f => 0, :milestone_id => params[:milestone_id]) do
|
= link_to project_issues_path(@project, :f => issues_filter[:open], :milestone_id => params[:milestone_id]) do
|
||||||
Open
|
Open
|
||||||
%li{:class => ("active" if params[:f] == "2")}
|
%li{:class => ("active" if params[:f] == issues_filter[:closed])}
|
||||||
= link_to project_issues_path(@project, :f => 2, :milestone_id => params[:milestone_id]) do
|
= link_to project_issues_path(@project, :f => issues_filter[:closed], :milestone_id => params[:milestone_id]) do
|
||||||
Closed
|
Closed
|
||||||
%li{:class => ("active" if params[:f] == "3")}
|
%li{:class => ("active" if params[:f] == issues_filter[:to_me])}
|
||||||
= link_to project_issues_path(@project, :f => 3, :milestone_id => params[:milestone_id]) do
|
= link_to project_issues_path(@project, :f => issues_filter[:to_me], :milestone_id => params[:milestone_id]) do
|
||||||
To Me
|
To Me
|
||||||
%li{:class => ("active" if params[:f] == "1")}
|
%li{:class => ("active" if params[:f] == issues_filter[:all])}
|
||||||
= link_to project_issues_path(@project, :f => 1, :milestone_id => params[:milestone_id]) do
|
= link_to project_issues_path(@project, :f => issues_filter[:all], :milestone_id => params[:milestone_id]) do
|
||||||
All
|
All
|
||||||
|
|
||||||
.span6.right
|
.right
|
||||||
= form_tag project_issues_path(@project), :method => :get, :class => :right do
|
= form_tag project_issues_path(@project), :method => :get, :class => :right do
|
||||||
|
= select_tag(:label_name, options_for_select(issue_tags, params[:label_name]), :prompt => "Labels")
|
||||||
= select_tag(:assignee_id, options_from_collection_for_select(@project.users.all, "id", "name", params[:assignee_id]), :prompt => "Assignee")
|
= select_tag(:assignee_id, options_from_collection_for_select(@project.users.all, "id", "name", params[:assignee_id]), :prompt => "Assignee")
|
||||||
= select_tag(:milestone_id, options_from_collection_for_select(@project.milestones.order("id desc").all, "id", "title", params[:milestone_id]), :prompt => "Milestone")
|
= select_tag(:milestone_id, options_from_collection_for_select(@project.milestones.order("id desc").all, "id", "title", params[:milestone_id]), :prompt => "Milestone")
|
||||||
= hidden_field_tag :f, params[:f]
|
= hidden_field_tag :f, params[:f]
|
||||||
|
.clearfix
|
||||||
|
|
||||||
%ul#issues-table.unstyled.issues_table
|
%ul#issues-table.unstyled.issues_table
|
||||||
= render "issues"
|
= render "issues"
|
||||||
|
|
||||||
:javascript
|
:javascript
|
||||||
$(function(){
|
$(function(){
|
||||||
initIssuesSearch();
|
issuesPage();
|
||||||
setSortable();
|
|
||||||
$("#assignee_id").chosen();
|
|
||||||
$("#milestone_id").chosen();
|
|
||||||
$("#milestone_id, #assignee_id").live("change", function(){
|
|
||||||
$(this).closest("form").submit();
|
|
||||||
});
|
|
||||||
})
|
})
|
||||||
|
|
||||||
function setSortable(){
|
function setSortable(){
|
||||||
|
|
|
@ -51,9 +51,11 @@
|
||||||
= truncate(milestone.title, :length => 20)
|
= truncate(milestone.title, :length => 20)
|
||||||
|
|
||||||
.right
|
.right
|
||||||
- if @issue.critical
|
- @issue.labels.each do |label|
|
||||||
%span.label.label-important
|
%span.label.label-issue
|
||||||
Critical
|
%i.icon-tag
|
||||||
|
= label.name
|
||||||
|
|
||||||
|
|
||||||
- if @issue.description.present?
|
- if @issue.description.present?
|
||||||
.bottom_box_content
|
.bottom_box_content
|
||||||
|
|
9
db/migrate/20120627145613_remove_critical_from_issue.rb
Normal file
9
db/migrate/20120627145613_remove_critical_from_issue.rb
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
class RemoveCriticalFromIssue < ActiveRecord::Migration
|
||||||
|
def up
|
||||||
|
remove_column :issues, :critical
|
||||||
|
end
|
||||||
|
|
||||||
|
def down
|
||||||
|
add_column :issues, :critical, :boolean, :null => true, :default => false
|
||||||
|
end
|
||||||
|
end
|
|
@ -11,7 +11,7 @@
|
||||||
#
|
#
|
||||||
# It's strongly recommended to check this file into your version control system.
|
# It's strongly recommended to check this file into your version control system.
|
||||||
|
|
||||||
ActiveRecord::Schema.define(:version => 20120413135904) do
|
ActiveRecord::Schema.define(:version => 20120627145613) do
|
||||||
|
|
||||||
create_table "events", :force => true do |t|
|
create_table "events", :force => true do |t|
|
||||||
t.string "target_type"
|
t.string "target_type"
|
||||||
|
@ -34,7 +34,6 @@ ActiveRecord::Schema.define(:version => 20120413135904) do
|
||||||
t.datetime "updated_at", :null => false
|
t.datetime "updated_at", :null => false
|
||||||
t.boolean "closed", :default => false, :null => false
|
t.boolean "closed", :default => false, :null => false
|
||||||
t.integer "position", :default => 0
|
t.integer "position", :default => 0
|
||||||
t.boolean "critical", :default => false, :null => false
|
|
||||||
t.string "branch_name"
|
t.string "branch_name"
|
||||||
t.text "description"
|
t.text "description"
|
||||||
t.integer "milestone_id"
|
t.integer "milestone_id"
|
||||||
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
Feature: Issues
|
||||||
|
Background:
|
||||||
|
Given I signin as a user
|
||||||
|
And I own project "Shop"
|
||||||
|
And project "Shop" have "Release 0.4" open issue
|
||||||
|
And project "Shop" have "Release 0.3" closed issue
|
||||||
|
And I visit project "Shop" issues page
|
||||||
|
|
||||||
|
Scenario: I should see open issues
|
||||||
|
Given I should see "Release 0.4" open issue
|
||||||
|
And I should not see "Release 0.3" closed issue
|
||||||
|
|
22
features/step_definitions/project_issues_steps.rb
Normal file
22
features/step_definitions/project_issues_steps.rb
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
Given /^project "(.*?)" have "(.*?)" open issue$/ do |arg1, arg2|
|
||||||
|
project = Project.find_by_name(arg1)
|
||||||
|
Factory.create(:issue, :title => arg2, :project => project, :author => project.users.first)
|
||||||
|
end
|
||||||
|
|
||||||
|
Given /^project "(.*?)" have "(.*?)" closed issue$/ do |arg1, arg2|
|
||||||
|
project = Project.find_by_name(arg1)
|
||||||
|
Factory.create(:issue, :title => arg2, :project => project, :author => project.users.first, :closed => true)
|
||||||
|
end
|
||||||
|
|
||||||
|
Given /^I visit project "(.*?)" issues page$/ do |arg1|
|
||||||
|
visit project_issues_path(Project.find_by_name(arg1))
|
||||||
|
end
|
||||||
|
|
||||||
|
Given /^I should see "(.*?)" open issue$/ do |arg1|
|
||||||
|
page.should have_content arg1
|
||||||
|
end
|
||||||
|
|
||||||
|
Given /^I should not see "(.*?)" closed issue$/ do |arg1|
|
||||||
|
page.should_not have_content arg1
|
||||||
|
end
|
||||||
|
|
Loading…
Reference in a new issue