From 1b1e77c728e575a110e204e142e81bdff2737536 Mon Sep 17 00:00:00 2001
From: Dmitriy Zaporozhets <dzaporozhets@sphereconsultinginc.com>
Date: Wed, 27 Jun 2012 21:20:35 +0300
Subject: [PATCH] Issue Labels: Edit, show, index + filter

---
 Gemfile                                       |  2 +-
 Gemfile.lock                                  |  6 +--
 app/assets/stylesheets/gitlab_bootstrap.scss  |  8 ++++
 app/controllers/issues_controller.rb          |  1 +
 app/helpers/issues_helper.rb                  |  4 ++
 app/models/issue.rb                           |  2 +
 app/views/issues/_form.html.haml              |  6 +++
 app/views/issues/_show.html.haml              |  5 ++
 app/views/issues/index.html.haml              | 46 ++++++++++---------
 app/views/issues/show.html.haml               |  8 ++--
 features/projects/issues/issues.feature       | 12 +++++
 .../step_definitions/project_issues_steps.rb  | 22 +++++++++
 12 files changed, 93 insertions(+), 29 deletions(-)
 create mode 100644 features/step_definitions/project_issues_steps.rb

diff --git a/Gemfile b/Gemfile
index 44bdb39265c81..4c977dde0a9f1 100644
--- a/Gemfile
+++ b/Gemfile
@@ -29,7 +29,7 @@ gem "thin"
 gem "unicorn"
 gem "git"
 gem "acts_as_list"
-gem "acts-as-taggable-on", "~> 2.1.0"
+gem "acts-as-taggable-on", "2.3.1"
 gem "drapper"
 gem "resque", "~> 1.20.0"
 gem "httparty"
diff --git a/Gemfile.lock b/Gemfile.lock
index 8265641f139c2..d50a8d1e5d7c0 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -89,8 +89,8 @@ GEM
     activesupport (3.2.5)
       i18n (~> 0.6)
       multi_json (~> 1.0)
-    acts-as-taggable-on (2.1.1)
-      rails
+    acts-as-taggable-on (2.3.1)
+      rails (~> 3.0)
     acts_as_list (0.1.6)
     addressable (2.2.8)
     ansi (1.4.2)
@@ -351,7 +351,7 @@ PLATFORMS
   ruby
 
 DEPENDENCIES
-  acts-as-taggable-on (~> 2.1.0)
+  acts-as-taggable-on (= 2.3.1)
   acts_as_list
   annotate!
   autotest
diff --git a/app/assets/stylesheets/gitlab_bootstrap.scss b/app/assets/stylesheets/gitlab_bootstrap.scss
index a347eeb2fc527..c4491b3caedd1 100644
--- a/app/assets/stylesheets/gitlab_bootstrap.scss
+++ b/app/assets/stylesheets/gitlab_bootstrap.scss
@@ -177,6 +177,14 @@ a:focus {
   &.label-important { 
     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 {
diff --git a/app/controllers/issues_controller.rb b/app/controllers/issues_controller.rb
index 48e8d72ad1ed2..35a30ca080787 100644
--- a/app/controllers/issues_controller.rb
+++ b/app/controllers/issues_controller.rb
@@ -139,6 +139,7 @@ def issues_filtered
 
     @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.tagged_with(params[:label_name]) if params[:label_name].present?
     @issues = @issues.includes(:author, :project).order("critical, updated_at")
     @issues
   end
diff --git a/app/helpers/issues_helper.rb b/app/helpers/issues_helper.rb
index 31d862ef72577..148048a969836 100644
--- a/app/helpers/issues_helper.rb
+++ b/app/helpers/issues_helper.rb
@@ -33,4 +33,8 @@ def issue_css_classes issue
     classes << " today" if issue.today?
     classes
   end
+
+  def issue_tags 
+    @project.issues.tag_counts_on(:labels).map(&:name)
+  end
 end
diff --git a/app/models/issue.rb b/app/models/issue.rb
index 40e14dac0d685..c961bbe2eeebd 100644
--- a/app/models/issue.rb
+++ b/app/models/issue.rb
@@ -1,6 +1,8 @@
 class Issue < ActiveRecord::Base
   include Upvote
 
+  acts_as_taggable_on :labels
+
   belongs_to :project
   belongs_to :milestone
   belongs_to :author, :class_name => "User"
diff --git a/app/views/issues/_form.html.haml b/app/views/issues/_form.html.haml
index 444fbd768feff..94a621c2d262c 100644
--- a/app/views/issues/_form.html.haml
+++ b/app/views/issues/_form.html.haml
@@ -35,6 +35,12 @@
             = f.text_area :description, :maxlength => 2000, :class => "xxlarge", :rows => 14
             %p.hint Markdown is enabled.
 
+        .clearfix
+          = f.label :label_list, "Labels"
+          .input
+            = f.text_field :label_list, :maxlength => 2000, :class => "xxlarge"
+            %p.hint Separate with comma.
+
     .actions
       - if @issue.new_record?
         = f.submit 'Submit new issue', :class => "primary btn"
diff --git a/app/views/issues/_show.html.haml b/app/views/issues/_show.html.haml
index fe9b6b37c42bb..797d2387e31c4 100644
--- a/app/views/issues/_show.html.haml
+++ b/app/views/issues/_show.html.haml
@@ -2,6 +2,11 @@
   .list_legend
     .icon
   .right
+    - issue.labels.each do |label|
+      %span.label.label-issue
+        %i.icon-tag
+        = label.name
+      &nbsp;
     - if issue.notes.any?
       %span.btn.small.disabled.padded
         %i.icon-comment
diff --git a/app/views/issues/index.html.haml b/app/views/issues/index.html.haml
index e49c9513844ea..ebe432bc7a827 100644
--- a/app/views/issues/index.html.haml
+++ b/app/views/issues/index.html.haml
@@ -31,28 +31,29 @@
 
   %div#issues-table-holder.ui-box
     .title
-      .row
-        .span4
-          %ul.nav.nav-pills.left
-            %li{:class => ("active" if (params[:f] == "0" || !params[:f]))}
-              = link_to project_issues_path(@project, :f => 0, :milestone_id => params[:milestone_id]) do
-                Open
-            %li{:class => ("active" if params[:f] == "2")}
-              = link_to project_issues_path(@project, :f => 2, :milestone_id => params[:milestone_id]) do
-                Closed
-            %li{:class => ("active" if params[:f] == "3")}
-              = link_to project_issues_path(@project, :f => 3, :milestone_id => params[:milestone_id]) do
-                To Me
-            %li{:class => ("active" if params[:f] == "1")}
-              = link_to project_issues_path(@project, :f => 1, :milestone_id => params[:milestone_id]) do
-                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]
+      .left
+        %ul.nav.nav-pills.left
+          %li{:class => ("active" if (params[:f] == "0" || !params[:f]))}
+            = link_to project_issues_path(@project, :f => 0, :milestone_id => params[:milestone_id]) do
+              Open
+          %li{:class => ("active" if params[:f] == "2")}
+            = link_to project_issues_path(@project, :f => 2, :milestone_id => params[:milestone_id]) do
+              Closed
+          %li{:class => ("active" if params[:f] == "3")}
+            = link_to project_issues_path(@project, :f => 3, :milestone_id => params[:milestone_id]) do
+              To Me
+          %li{:class => ("active" if params[:f] == "1")}
+            = link_to project_issues_path(@project, :f => 1, :milestone_id => params[:milestone_id]) do
+              All
 
+      .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
       = render "issues"
 
@@ -60,9 +61,10 @@
   $(function(){
     initIssuesSearch();
     setSortable();
+    $("#label_name").chosen();
     $("#assignee_id").chosen();
     $("#milestone_id").chosen();
-    $("#milestone_id, #assignee_id").live("change", function(){
+    $("#milestone_id, #assignee_id, #label_name").live("change", function(){
       $(this).closest("form").submit();
     });
   })
diff --git a/app/views/issues/show.html.haml b/app/views/issues/show.html.haml
index 1bb4e04d2b606..cd7ad57a7e8b4 100644
--- a/app/views/issues/show.html.haml
+++ b/app/views/issues/show.html.haml
@@ -51,9 +51,11 @@
           = truncate(milestone.title, :length => 20)
 
     .right
-      - if @issue.critical
-        %span.label.label-important
-          Critical
+      - @issue.labels.each do |label|
+        %span.label.label-issue
+          %i.icon-tag
+          = label.name
+        &nbsp;
 
   - if @issue.description.present?
     .bottom_box_content
diff --git a/features/projects/issues/issues.feature b/features/projects/issues/issues.feature
index e69de29bb2d1d..0ca0792dd8ab0 100644
--- a/features/projects/issues/issues.feature
+++ b/features/projects/issues/issues.feature
@@ -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   
+
diff --git a/features/step_definitions/project_issues_steps.rb b/features/step_definitions/project_issues_steps.rb
new file mode 100644
index 0000000000000..e83c0e7f399d3
--- /dev/null
+++ b/features/step_definitions/project_issues_steps.rb
@@ -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
+
-- 
GitLab