Commit 7ef18060 authored by Dmitriy Zaporozhets's avatar Dmitriy Zaporozhets

Merge branch 'feature/issue_tags' of dev.gitlabhq.com:gitlabhq

parents 4c1f435a 5f356d69
...@@ -29,7 +29,7 @@ gem "thin" ...@@ -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 ...@@ -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 ...@@ -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() { ...@@ -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 { ...@@ -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 { ...@@ -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 { ...@@ -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 ...@@ -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 ...@@ -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 ...@@ -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 ...@@ -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
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 ...@@ -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 ...@@ -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 @@ ...@@ -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 @@ ...@@ -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
= f.label :closed
.input= f.check_box :closed
.clearfix .clearfix
= f.label :description, "Issue Details" = f.label :description, "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"
......
- @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 @@ ...@@ -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
&nbsp;
- 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 @@ ...@@ -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] == issues_filter[:open] || !params[:f]))}
%li{:class => ("active" if (params[:f] == "0" || !params[:f]))} = link_to project_issues_path(@project, :f => issues_filter[:open], :milestone_id => params[:milestone_id]) do
= link_to project_issues_path(@project, :f => 0, :milestone_id => params[:milestone_id]) do Open
Open %li{:class => ("active" if params[:f] == issues_filter[:closed])}
%li{:class => ("active" if params[:f] == "2")} = link_to project_issues_path(@project, :f => issues_filter[:closed], :milestone_id => params[:milestone_id]) do
= link_to project_issues_path(@project, :f => 2, :milestone_id => params[:milestone_id]) do Closed
Closed %li{:class => ("active" if params[:f] == issues_filter[:to_me])}
%li{:class => ("active" if params[:f] == "3")} = link_to project_issues_path(@project, :f => issues_filter[:to_me], :milestone_id => params[:milestone_id]) do
= link_to project_issues_path(@project, :f => 3, :milestone_id => params[:milestone_id]) do To Me
To Me %li{:class => ("active" if params[:f] == issues_filter[:all])}
%li{:class => ("active" if params[:f] == "1")} = link_to project_issues_path(@project, :f => issues_filter[:all], :milestone_id => params[:milestone_id]) do
= link_to project_issues_path(@project, :f => 1, :milestone_id => params[:milestone_id]) do All
All
.span6.right
= form_tag project_issues_path(@project), :method => :get, :class => :right do
= 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")
= hidden_field_tag :f, params[:f]
.right
= 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(: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]
.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 @@ ...@@ -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
&nbsp;
- if @issue.description.present? - if @issue.description.present?
.bottom_box_content .bottom_box_content
......
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 @@ ...@@ -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 ...@@ -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"
......
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
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
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment