Added "Issues" dashboard

This shows issues assigned to you, across all your projects, in one
place.

References #173
This commit is contained in:
Ariejan de Vroom 2011-12-08 00:31:06 +01:00
parent 2552a877df
commit f512418b27
14 changed files with 165 additions and 20 deletions

View file

@ -0,0 +1,3 @@
# Place all the behaviors and hooks related to the matching controller here.
# All this logic will automatically be available in application.js.
# You can use CoffeeScript in this file: http://jashkenas.github.com/coffee-script/

View file

@ -351,7 +351,7 @@ header h1.logo a{
text-indent: -1000em; text-indent: -1000em;
} }
header nav{border-radius: 4px; box-shadow: 0 1px 2px black; width: 294px; margin: auto; header nav{border-radius: 4px; box-shadow: 0 1px 2px black; width: 392px; margin: auto;
background-image: -webkit-gradient(linear, 0 0, 0 30, color-stop(0.066, #595d63), to(#31363e)); background-image: -webkit-gradient(linear, 0 0, 0 30, color-stop(0.066, #595d63), to(#31363e));
background-image: -webkit-linear-gradient(#595d63 6.6%, #31363e); background-image: -webkit-linear-gradient(#595d63 6.6%, #31363e);
background-image: -moz-linear-gradient(#595d63 6.6%, #31363e); background-image: -moz-linear-gradient(#595d63 6.6%, #31363e);
@ -398,6 +398,7 @@ header nav a span{width: 20px; height: 20px; display: inline-block; background:
header nav a.dashboard span{background: url('images.png') no-repeat -161px 0;} header nav a.dashboard span{background: url('images.png') no-repeat -161px 0;}
header nav a.admin span{background: url('images.png') no-repeat -184px 0;} header nav a.admin span{background: url('images.png') no-repeat -184px 0;}
header nav a.project span{background: url('images.png') no-repeat -209px -1px; top: 7px} header nav a.project span{background: url('images.png') no-repeat -209px -1px; top: 7px}
header nav a.issues span{background: url('images.png') no-repeat -209px -1px; top: 7px}
header .login-top{float: right; width: 180px; header .login-top{float: right; width: 180px;
background-image: -webkit-gradient(linear, 0 0, 0 62, color-stop(0.032, #464c56), to(#363c45)); background-image: -webkit-gradient(linear, 0 0, 0 62, color-stop(0.032, #464c56), to(#363c45));

View file

@ -0,0 +1,3 @@
// Place all the styles related to the user_issues controller here.
// They will automatically be included in application.css.
// You can use Sass (SCSS) here: http://sass-lang.com/

View file

@ -0,0 +1,25 @@
class UserIssuesController < ApplicationController
before_filter :authenticate_user!
layout "user"
respond_to :js, :html
def index
@user = current_user
@issues = current_user.assigned_issues.opened
@issues = @issues.includes(:author, :project)
respond_to do |format|
format.html
format.js
format.atom { render :layout => false }
end
end
def search
end
end

View file

@ -0,0 +1,2 @@
module UserIssuesHelper
end

View file

@ -1,5 +1,5 @@
- @issues.critical.each do |issue| - @issues.critical.each do |issue|
= render(:partial => 'show', :locals => {:issue => issue}) = render(:partial => 'issues/show', :locals => {:issue => issue})
- @issues.non_critical.each do |issue| - @issues.non_critical.each do |issue|
= render(:partial => 'show', :locals => {:issue => issue}) = render(:partial => 'issues/show', :locals => {:issue => issue})

View file

@ -1,4 +1,4 @@
%tr{ :id => dom_id(issue), :class => "issue #{issue.critical ? "critical" : ""}", :url => project_issue_path(@project, issue) } %tr{ :id => dom_id(issue), :class => "issue #{issue.critical ? "critical" : ""}", :url => project_issue_path(issue.project, issue) }
%td %td
%strong.issue-number{:class => sort_class}= "##{issue.id}" %strong.issue-number{:class => sort_class}= "##{issue.id}"
%span %span
@ -6,6 +6,9 @@
%br %br
%br %br
%div.note-author %div.note-author
- if not @project.present?
%strong= issue.project.name
= '-'
%strong= issue.assignee.name %strong= issue.assignee.name
%cite.cgray %cite.cgray
= time_ago_in_words(issue.created_at) = time_ago_in_words(issue.created_at)
@ -17,10 +20,10 @@
.right.action-links .right.action-links
- if can? current_user, :write_issue, issue - if can? current_user, :write_issue, issue
- if issue.closed - if issue.closed
= link_to 'Reopen', project_issue_path(@project, issue, :issue => {:closed => false }, :status_only => true), :method => :put, :class => "cgray", :remote => true = link_to 'Reopen', project_issue_path(issue.project, issue, :issue => {:closed => false }, :status_only => true), :method => :put, :class => "cgray", :remote => true
- else - else
= link_to 'Resolve', project_issue_path(@project, issue, :issue => {:closed => true }, :status_only => true), :method => :put, :class => "cgray", :remote => true = link_to 'Resolve', project_issue_path(issue.project, issue, :issue => {:closed => true }, :status_only => true), :method => :put, :class => "cgray", :remote => true
- if can? current_user, :write_issue, issue - if can? current_user, :write_issue, issue
= link_to 'Edit', edit_project_issue_path(@project, issue), :class => "cgray edit-issue-link", :remote => true = link_to 'Edit', edit_project_issue_path(issue.project, issue), :class => "cgray edit-issue-link", :remote => true
- if can?(current_user, :admin_issue, @project) || issue.author == current_user - if can?(current_user, :admin_issue, @project) || issue.author == current_user
= link_to 'Remove', [@project, issue], :confirm => 'Are you sure?', :method => :delete, :remote => true, :class => "cred delete-issue negative", :id => "destroy_issue_#{issue.id}" = link_to 'Remove', [issue.project, issue], :confirm => 'Are you sure?', :method => :delete, :remote => true, :class => "cred delete-issue negative", :id => "destroy_issue_#{issue.id}"

View file

@ -25,6 +25,9 @@
<%= link_to dashboard_path, :class => current_page?(root_path) ? "current dashboard" : "dashboard" do %> <%= link_to dashboard_path, :class => current_page?(root_path) ? "current dashboard" : "dashboard" do %>
<span></span>Dashboard <span></span>Dashboard
<% end %> <% end %>
<%= link_to issues_path, :class => current_page?(issues_path) ? "current issues" : "issues" do %>
<span></span>Issues
<% end %>
<%= link_to projects_path, :class => current_page?(projects_path) ? "current project" : "project" do %> <%= link_to projects_path, :class => current_page?(projects_path) ? "current project" : "project" do %>
<span></span>Projects <span></span>Projects
<% end %> <% end %>

View file

@ -0,0 +1,27 @@
!!!
%html
%head
%title
GitLab #{" - #{current_user.name}"}
= stylesheet_link_tag "application"
= javascript_include_tag "application"
= csrf_meta_tags
= javascript_tag do
REQ_URI = "#{request.env["REQUEST_URI"]}";
REQ_REFFER = "#{request.env["HTTP_REFERER"]}";
%body{ :class => body_class('project-page'), :id => yield(:boyd_id)}
= render :partial => "layouts/flash"
#container
= render :partial => "layouts/head_panel"
.project-container
.project-sidebar
.fixed
%aside
= link_to issues_path, :class => current_page?(:controller => "user_issues", :action => "index") ? "current" : nil do
Issues
- unless current_user.assigned_issues.empty?
%span{ :class => "number" }= current_user.assigned_issues.count
.project-content
= yield

View file

@ -0,0 +1,24 @@
xml.instruct!
xml.feed "xmlns" => "http://www.w3.org/2005/Atom", "xmlns:media" => "http://search.yahoo.com/mrss/" do
xml.title "#{@user.name} issues"
xml.link :href => issues_url(:atom, :private_token => @user.private_token), :rel => "self", :type => "application/atom+xml"
xml.link :href => issues_url(:private_token => @user.private_token), :rel => "alternate", :type => "text/html"
xml.id issues_url(:private_token => @user.private_token)
xml.updated @issues.first.created_at.strftime("%Y-%m-%dT%H:%M:%SZ") if @issues.any?
@issues.each do |issue|
xml.entry do
xml.id project_issue_url(issue.project, issue)
xml.link :href => project_issue_url(issue.project, issue)
xml.title truncate(issue.title, :length => 80)
xml.updated issue.created_at.strftime("%Y-%m-%dT%H:%M:%SZ")
xml.media :thumbnail, :width => "40", :height => "40", :url => gravatar_icon(issue.author_email)
xml.author do |author|
xml.name issue.author_name
xml.email issue.author_email
end
xml.summary issue.title
end
end
end

View file

@ -0,0 +1,9 @@
%div#issues-table-holder
%table.round-borders#issues-table
%thead
%th
.top_panel_issues
%h2 Issues assigned to me
= render 'issues/issues'
%br

View file

@ -1,5 +1,7 @@
Gitlab::Application.routes.draw do Gitlab::Application.routes.draw do
get "user_issues/index"
get 'tags'=> 'tags#index' get 'tags'=> 'tags#index'
get 'tags/:tag' => 'projects#index' get 'tags/:tag' => 'projects#index'
@ -21,6 +23,8 @@ Gitlab::Application.routes.draw do
put "profile/edit", :to => "profile#social_update" put "profile/edit", :to => "profile#social_update"
get "profile", :to => "profile#show" get "profile", :to => "profile#show"
get "dashboard", :to => "dashboard#index" get "dashboard", :to => "dashboard#index"
get "issues", :to => "user_issues#index", :as => "issues"
#get "profile/:id", :to => "profile#show" #get "profile/:id", :to => "profile#show"
resources :projects, :only => [:new, :create, :index] resources :projects, :only => [:new, :create, :index]

View file

@ -13,18 +13,6 @@
ActiveRecord::Schema.define(:version => 20111206222316) do ActiveRecord::Schema.define(:version => 20111206222316) do
create_table "features", :force => true do |t|
t.string "name"
t.string "branch_name"
t.integer "assignee_id"
t.integer "author_id"
t.integer "project_id"
t.datetime "created_at"
t.datetime "updated_at"
t.string "version"
t.integer "status", :default => 0, :null => false
end
create_table "issues", :force => true do |t| create_table "issues", :force => true do |t|
t.string "title" t.string "title"
t.integer "assignee_id" t.integer "assignee_id"

View file

@ -0,0 +1,53 @@
require 'spec_helper'
describe "User Issues Dashboard" do
describe "GET /issues" do
before do
login_as :user
@project1 = Factory :project,
:path => "project1",
:code => "TEST1"
@project2 = Factory :project,
:path => "project2",
:code => "TEST2"
@project1.add_access(@user, :read, :write)
@project2.add_access(@user, :read, :write)
@issue1 = Factory :issue,
:author => @user,
:assignee => @user,
:project => @project1
@issue2 = Factory :issue,
:author => @user,
:assignee => @user,
:project => @project2
visit issues_path
end
subject { page }
it { should have_content(@issue1.title) }
it { should have_content(@issue1.project.name) }
it { should have_content(@issue1.assignee.name) }
it { should have_content(@issue2.title) }
it { should have_content(@issue2.project.name) }
it { should have_content(@issue2.assignee.name) }
it "should render atom feed via private token" do
logout
visit issues_path(:atom, :private_token => @user.private_token)
page.response_headers['Content-Type'].should have_content("application/atom+xml")
page.body.should have_selector("title", :text => "#{@user.name} issues")
page.body.should have_selector("author email", :text => @issue1.author_email)
page.body.should have_selector("entry summary", :text => @issue1.title)
end
end
end