Commit 23d950855d6d2524d00b1f0618c008e2529f06a4

Authored by Dmitriy Zaporozhets
1 parent 667edcdd

Milestone basic scaffold

app/assets/javascripts/issues.js
... ... @@ -2,6 +2,7 @@ function switchToNewIssue(form){
2 2 $(".issues_content").hide("fade", { direction: "left" }, 150, function(){
3 3 $(".issues_content").after(form);
4 4 $('select#issue_assignee_id').chosen();
  5 + $('select#issue_milestone_id').chosen();
5 6 $("#new_issue_dialog").show("fade", { direction: "right" }, 150);
6 7 $('.top-tabs .add_new').hide();
7 8 });
... ... @@ -11,6 +12,7 @@ function switchToEditIssue(form){
11 12 $(".issues_content").hide("fade", { direction: "left" }, 150, function(){
12 13 $(".issues_content").after(form);
13 14 $('select#issue_assignee_id').chosen();
  15 + $('select#issue_milestone_id').chosen();
14 16 $("#edit_issue_dialog").show("fade", { direction: "right" }, 150);
15 17 $('.add_new').hide();
16 18 });
... ...
app/assets/stylesheets/common.scss
... ... @@ -45,6 +45,13 @@ a {
45 45  
46 46 &:hover {
47 47 }
  48 +
  49 + &.primary {
  50 + background:$link_color;
  51 + &:hover {
  52 + background:$blue_link;
  53 + }
  54 + }
48 55 }
49 56  
50 57 a:focus {
... ...
app/assets/stylesheets/jquery_ui.scss 0 → 100644
... ... @@ -0,0 +1,31 @@
  1 +/**
  2 + * JQUERY UI datepicker
  3 + *
  4 + */
  5 +.ui-datepicker {
  6 + border-color:#eee;
  7 + padding:20px;
  8 +
  9 + .ui-state-default {
  10 + background:#f1f1f1;
  11 + padding:5px;
  12 + }
  13 + .ui-state-active {
  14 + background:#fff;
  15 + }
  16 +}
  17 +
  18 +/**
  19 + * JQUERY UI progressbar
  20 + *
  21 + */
  22 +.ui-progressbar {
  23 + border:1px solid #ddd;
  24 + height:6px;
  25 +
  26 + .ui-progressbar-value {
  27 + background-color: #62C462;//$blue_link;
  28 + margin:0;
  29 + }
  30 +}
  31 +
... ...
app/assets/stylesheets/main.scss
... ... @@ -116,3 +116,9 @@ $hover: #FDF5D9;
116 116 *
117 117 */
118 118 @import "highlight.black.scss";
  119 +
  120 +/**
  121 + * JQUERY UI ext
  122 + *
  123 + */
  124 +@import "jquery_ui.scss";
... ...
app/controllers/issues_controller.rb
... ... @@ -15,7 +15,7 @@ class IssuesController < ApplicationController
15 15 before_filter :authorize_write_issue!, :only => [:new, :create]
16 16  
17 17 # Allow modify issue
18   - before_filter :authorize_modify_issue!, :only => [:close, :edit, :update, :sort]
  18 + before_filter :authorize_modify_issue!, :only => [:close, :edit, :update]
19 19  
20 20 # Allow destroy issue
21 21 before_filter :authorize_admin_issue!, :only => [:destroy]
... ... @@ -28,8 +28,10 @@ class IssuesController < ApplicationController
28 28 when 2 then @project.issues.closed
29 29 when 3 then @project.issues.opened.assigned(current_user)
30 30 else @project.issues.opened
31   - end.page(params[:page]).per(20)
  31 + end
32 32  
  33 + @issues = @issues.where(:milestone_id => params[:milestone_id]) if params[:milestone_id].present?
  34 + @issues = @issues.page(params[:page]).per(20)
33 35 @issues = @issues.includes(:author, :project).order("critical, updated_at")
34 36  
35 37 respond_to do |format|
... ... @@ -51,13 +53,6 @@ class IssuesController < ApplicationController
51 53 def show
52 54 @note = @project.notes.new(:noteable => @issue)
53 55  
54   - @commits = if @issue.branch_name && @project.repo.heads.map(&:name).include?(@issue.branch_name)
55   - @project.repo.commits_between("master", @issue.branch_name)
56   - else
57   - []
58   - end
59   -
60   -
61 56 respond_to do |format|
62 57 format.html
63 58 format.js
... ... @@ -102,6 +97,8 @@ class IssuesController < ApplicationController
102 97 end
103 98  
104 99 def sort
  100 + return render_404 unless can?(current_user, :admin_issue, @project)
  101 +
105 102 @issues = @project.issues.where(:id => params['issue'])
106 103 @issues.each do |issue|
107 104 issue.position = params['issue'].index(issue.id.to_s) + 1
... ...
app/controllers/milestones_controller.rb 0 → 100644
... ... @@ -0,0 +1,94 @@
  1 +class MilestonesController < ApplicationController
  2 + before_filter :authenticate_user!
  3 + before_filter :project
  4 + before_filter :module_enabled
  5 + before_filter :milestone, :only => [:edit, :update, :destroy, :show]
  6 + layout "project"
  7 +
  8 + # Authorize
  9 + before_filter :add_project_abilities
  10 +
  11 + # Allow read any milestone
  12 + before_filter :authorize_read_milestone!
  13 +
  14 + # Allow admin milestone
  15 + before_filter :authorize_admin_milestone!, :except => [:index, :show]
  16 +
  17 + respond_to :html
  18 +
  19 + def index
  20 + @milestones = case params[:f].to_i
  21 + when 1; @project.milestones
  22 + else @project.milestones.active
  23 + end
  24 +
  25 + @milestones = @milestones.includes(:project).order("due_date")
  26 + @milestones = @milestones.page(params[:page]).per(20)
  27 + end
  28 +
  29 + def new
  30 + @milestone = @project.milestones.new
  31 + respond_with(@milestone)
  32 + end
  33 +
  34 + def edit
  35 + respond_with(@milestone)
  36 + end
  37 +
  38 + def show
  39 + respond_to do |format|
  40 + format.html
  41 + format.js
  42 + end
  43 + end
  44 +
  45 + def create
  46 + @milestone = @project.milestones.new(params[:milestone])
  47 +
  48 + if @milestone.save
  49 + redirect_to project_milestone_path(@project, @milestone)
  50 + else
  51 + render "new"
  52 + end
  53 + end
  54 +
  55 + def update
  56 + @milestone.update_attributes(params[:milestone])
  57 +
  58 + respond_to do |format|
  59 + format.js
  60 + format.html do
  61 + if @milestone.valid?
  62 + redirect_to [@project, @milestone]
  63 + else
  64 + render :edit
  65 + end
  66 + end
  67 + end
  68 + end
  69 +
  70 + def destroy
  71 + return access_denied! unless can?(current_user, :admin_milestone, @milestone)
  72 +
  73 + @milestone.destroy
  74 +
  75 + respond_to do |format|
  76 + format.html { redirect_to project_milestones_path }
  77 + format.js { render :nothing => true }
  78 + end
  79 + end
  80 +
  81 + protected
  82 +
  83 + def milestone
  84 + @milestone ||= @project.milestones.find(params[:id])
  85 + end
  86 +
  87 + def authorize_admin_milestone!
  88 + return render_404 unless can?(current_user, :admin_milestone, @project)
  89 + end
  90 +
  91 + def module_enabled
  92 + return render_404 unless @project.issues_enabled
  93 + end
  94 +end
... ...
app/decorators/milestone_decorator.rb 0 → 100644
... ... @@ -0,0 +1,4 @@
  1 +class MilestoneDecorator < ApplicationDecorator
  2 + decorates :milestone
  3 +
  4 +end
... ...
app/models/ability.rb
... ... @@ -17,6 +17,7 @@ class Ability
17 17 :read_project,
18 18 :read_wiki,
19 19 :read_issue,
  20 + :read_milestone,
20 21 :read_snippet,
21 22 :read_team_member,
22 23 :read_merge_request,
... ... @@ -42,6 +43,7 @@ class Ability
42 43 :modify_merge_request,
43 44 :admin_project,
44 45 :admin_issue,
  46 + :admin_milestone,
45 47 :admin_snippet,
46 48 :admin_team_member,
47 49 :admin_merge_request,
... ...
app/models/issue.rb
1 1 class Issue < ActiveRecord::Base
2 2 belongs_to :project
  3 + belongs_to :milestone
3 4 belongs_to :author, :class_name => "User"
4 5 belongs_to :assignee, :class_name => "User"
5 6 has_many :notes, :as => :noteable, :dependent => :destroy
... ...
app/models/milestone.rb 0 → 100644
... ... @@ -0,0 +1,29 @@
  1 +class Milestone < ActiveRecord::Base
  2 + belongs_to :project
  3 + has_many :issues
  4 +
  5 + validates_presence_of :project_id
  6 + validates_presence_of :title
  7 +
  8 + def self.active
  9 + where("due_date > ? ", Date.today)
  10 + end
  11 +
  12 + def percent_complete
  13 + @percent_complete ||= begin
  14 + total_i = self.issues.count
  15 + closed_i = self.issues.closed.count
  16 + if total_i > 0
  17 + (closed_i * 100) / total_i
  18 + else
  19 + 100
  20 + end
  21 + rescue => ex
  22 + 0
  23 + end
  24 + end
  25 +
  26 + def expires_at
  27 + "expires at #{due_date.stamp("Aug 21, 2011")}" if due_date
  28 + end
  29 +end
... ...
app/models/project.rb
... ... @@ -12,6 +12,7 @@ class Project &lt; ActiveRecord::Base
12 12 has_many :events, :dependent => :destroy
13 13 has_many :merge_requests, :dependent => :destroy
14 14 has_many :issues, :dependent => :destroy, :order => "position"
  15 + has_many :milestones, :dependent => :destroy
15 16 has_many :users_projects, :dependent => :destroy
16 17 has_many :notes, :dependent => :destroy
17 18 has_many :snippets, :dependent => :destroy
... ...
app/views/issues/_form.html.haml
... ... @@ -9,18 +9,25 @@
9 9 %li= msg
10 10  
11 11 .clearfix
12   - = f.label :title, "Issue Subject"
13   - .input= f.text_field :title, :maxlength => 255, :class => "xxlarge"
14   -
  12 + = f.label :title, "Issue Subject *"
  13 + .input
  14 + = f.text_field :title, :maxlength => 255, :class => "xxlarge"
  15 +
  16 + .clearfix
  17 + = f.label :assignee_id, "Assign to *"
  18 + .input= f.select(:assignee_id, @project.users.all.collect {|p| [ p.name, p.id ] }, { :include_blank => "Assign to user" })
  19 +
15 20 .clearfix
16 21 = f.label :description, "Issue Details"
17 22 .input
18 23 = f.text_area :description, :maxlength => 2000, :class => "xxlarge", :rows => 10
19 24 %p.hint Markdown is enabled.
20 25  
  26 +
21 27 .clearfix
22   - = f.label :assignee_id
23   - .input= f.select(:assignee_id, @project.users.all.collect {|p| [ p.name, p.id ] }, { :include_blank => "Assign to user" })
  28 + = f.label :milestone_id
  29 + .input= f.select(:milestone_id, @project.milestones.active.all.collect {|p| [ p.title, p.id ] }, { :include_blank => "Select milestone" })
  30 +
24 31  
25 32 .clearfix
26 33 = f.label :critical, "Critical"
... ...
app/views/issues/_head.html.haml
1 1 .tabs
2 2 %li{:class => "#{'active' if current_page?(project_issues_path(@project))}"}
3 3 = link_to project_issues_path(@project), :class => "tab" do
4   - Issues
  4 + Browse Issues
  5 + %li{:class => "#{'active' if current_page?(project_milestones_path(@project))}"}
  6 + = link_to project_milestones_path(@project), :class => "tab" do
  7 + Milestones
... ...
app/views/issues/_issues.html.haml
... ... @@ -10,3 +10,6 @@
10 10 .span10= paginate @issues, :remote => true, :theme => "gitlab"
11 11 .span4.right
12 12 %span.cgray.right #{@issues.total_count} issues for this filter
  13 +- else
  14 + %li
  15 + %p.padded Nothing to show here
... ...
app/views/issues/edit.html.haml
... ... @@ -3,5 +3,6 @@
3 3 :javascript
4 4 $(function(){
5 5 $('select#issue_assignee_id').chosen();
  6 + $('select#issue_milestone_id').chosen();
6 7 });
7 8  
... ...
app/views/issues/index.html.haml
  1 += render "issues/head"
1 2 .issues_content
2 3 %h3
3 4 Issues
... ... @@ -5,14 +6,22 @@
5 6 = link_to project_issues_path(@project, :atom, { :private_token => current_user.private_token }) do
6 7 = image_tag "Rss-UI.PNG", :width => 16, :title => "feed"
7 8  
8   - - if can? current_user, :write_issue, @project
9   - = link_to new_project_issue_path(@project), :class => "right btn small", :title => "New Issue", :remote => true do
10   - New Issue
  9 + .right
  10 + .span4.left
  11 + = form_tag search_project_issues_path(@project), :method => :get, :remote => true, :id => "issue_search_form", :class => :left do
  12 + = hidden_field_tag :project_id, @project.id, { :id => 'project_id' }
  13 + = hidden_field_tag :status, params[:f]
  14 + = search_field_tag :issue_search, nil, { :placeholder => 'Search', :class => 'issue_search' }
  15 +
  16 + - if can? current_user, :write_issue, @project
  17 + .span2.left
  18 + = link_to new_project_issue_path(@project), :class => "right btn small", :title => "New Issue", :remote => true do
  19 + New Issue
11 20 %br
12 21 %div#issues-table-holder.ui-box
13 22 .title
14 23 .row
15   - .span8
  24 + .span6
16 25 %ul.pills.left
17 26 %li{:class => ("active" if (params[:f] == "0" || !params[:f]))}
18 27 = link_to project_issues_path(@project, :f => 0) do
... ... @@ -27,17 +36,13 @@
27 36 = link_to project_issues_path(@project, :f => 1) do
28 37 All
29 38  
30   - .span3.right
31   - = form_tag search_project_issues_path(@project), :method => :get, :remote => true, :id => "issue_search_form", :class => :right do
32   - = hidden_field_tag :project_id, @project.id, { :id => 'project_id' }
33   - = hidden_field_tag :status, params[:f]
34   - = search_field_tag :issue_search, nil, { :placeholder => 'Search', :class => 'issue_search' }
  39 + .span6.right
  40 + = form_tag project_issues_path(@project), :method => :get, :class => :right do
  41 + = select_tag(:milestone_id, options_from_collection_for_select(@project.milestones.order("id desc").all, "id", "title", params[:milestone_id]), :prompt => "Select milestone")
35 42  
36 43 %ul#issues-table.unstyled
37 44 = render "issues"
38   - - if @issues.blank?
39   - %li
40   - %p.padded Nothing to show here
  45 +
41 46 :javascript
42 47 var href = $('.issue_search').parent().attr('action');
43 48 var last_terms = '';
... ... @@ -65,9 +70,8 @@
65 70 $('#issues-table').sortable({
66 71 axis: 'y',
67 72 dropOnEmpty: false,
68   - handle: '.handle',
69   - cursor: 'crosshair',
70   - items: 'tr',
  73 + handle: '.avatar',
  74 + items: 'li',
71 75 opacity: 0.4,
72 76 scroll: true,
73 77 update: function(){
... ... @@ -85,4 +89,8 @@
85 89  
86 90 $(function(){
87 91 setSortable();
  92 + $("#milestone_id").chosen();
  93 + $("#milestone_id").live("change", function(){
  94 + $(this).closest("form").submit();
  95 + });
88 96 });
... ...
app/views/issues/new.html.haml
... ... @@ -3,5 +3,6 @@
3 3 :javascript
4 4 $(function(){
5 5 $('select#issue_assignee_id').chosen();
  6 + $('select#issue_milestone_id').chosen();
6 7 });
7 8  
... ...
app/views/milestones/_form.html.haml 0 → 100644
... ... @@ -0,0 +1,54 @@
  1 +%h3= @milestone.new_record? ? "New Milestone" : "Edit Milestone ##{@milestone.id}"
  2 +.back_link
  3 + = link_to project_milestones_path(@project) do
  4 + &larr; To milestones
  5 +
  6 +%hr
  7 +
  8 += form_for [@project, @milestone] do |f|
  9 + -if @milestone.errors.any?
  10 + .alert-message.block-message.error
  11 + %ul
  12 + - @milestone.errors.full_messages.each do |msg|
  13 + %li= msg
  14 + .row
  15 + .span7
  16 + .clearfix
  17 + = f.label :title, "Title"
  18 + .input
  19 + = f.text_field :title, :maxlength => 255, :class => "xlarge"
  20 + %p.hint Required
  21 + .clearfix
  22 + = f.label :description, "Description"
  23 + .input
  24 + = f.text_area :description, :maxlength => 2000, :class => "xlarge", :rows => 10
  25 + %p.hint Markdown is enabled.
  26 + .span8
  27 + .clearfix
  28 + = f.label :due_date, "Due Date"
  29 + .input= f.hidden_field :due_date
  30 + .input
  31 + .datepicker
  32 +
  33 +
  34 + .actions
  35 + - if @milestone.new_record?
  36 + = f.submit 'Create milestone', :class => "primary btn"
  37 + -else
  38 + = f.submit 'Save changes', :class => "primary btn"
  39 +
  40 + - if request.xhr?
  41 + = link_to "Cancel", "#back", :onclick => "backToIssues();", :class => "btn"
  42 + - else
  43 + - if @milestone.new_record?
  44 + = link_to "Cancel", project_milestones_path(@project), :class => "btn"
  45 + - else
  46 + = link_to "Cancel", project_milestone_path(@project, @milestone), :class => "btn"
  47 +
  48 +:javascript
  49 + $(function() {
  50 + $( ".datepicker" ).datepicker({
  51 + dateFormat: "yy-mm-dd",
  52 + onSelect: function(dateText, inst) { $("#milestone_due_date").val(dateText) }
  53 + });
  54 + });
... ...
app/views/milestones/_milestone.html.haml 0 → 100644
... ... @@ -0,0 +1,21 @@
  1 +%li{:class => "wll", :id => dom_id(milestone) }
  2 + .right
  3 + - if milestone.issues.count > 0
  4 + = link_to 'Browse Issues', project_issues_path(milestone.project, :milestone_id => milestone.id), :class => "btn small"
  5 + - if milestone.issues.any?
  6 + %span.btn.small.disabled.padded= pluralize milestone.issues.count, 'issues'
  7 + - if can? current_user, :admin_milestone, milestone.project
  8 + = link_to 'Edit', edit_project_milestone_path(milestone.project, milestone), :class => "btn small edit-milestone-link"
  9 + = link_to project_milestone_path(milestone.project, milestone) do
  10 + %h4.row_title
  11 + = truncate(milestone.title, :length => 100)
  12 + %small= milestone.expires_at
  13 +
  14 + .progress.span4
  15 +
  16 + :javascript
  17 + $(function() {
  18 + $( "##{dom_id(milestone)} .progress" ).progressbar({
  19 + value: #{milestone.percent_complete}
  20 + });
  21 + });
... ...
app/views/milestones/edit.html.haml 0 → 100644
... ... @@ -0,0 +1,7 @@
  1 += render "form"
  2 +
  3 +:javascript
  4 + $(function(){
  5 + $('select#issue_assignee_id').chosen();
  6 + });
  7 +
... ...
app/views/milestones/index.html.haml 0 → 100644
... ... @@ -0,0 +1,25 @@
  1 += render "issues/head"
  2 +.milestones_content
  3 + %h3
  4 + Milestones
  5 + - if can? current_user, :admin_milestone, @project
  6 + = link_to "New Milestone", new_project_milestone_path(@project), :class => "right btn small", :title => "New Milestone"
  7 + %br
  8 + %div.ui-box
  9 + .title
  10 + %ul.pills
  11 + %li{:class => ("active" if (params[:f] == "0" || !params[:f]))}
  12 + = link_to project_milestones_path(@project, :f => 0) do
  13 + Active
  14 + %li{:class => ("active" if params[:f] == "1")}
  15 + = link_to project_milestones_path(@project, :f => 1) do
  16 + All
  17 +
  18 + %ul.unstyled
  19 + = render @milestones
  20 +
  21 + - if @milestones.present?
  22 + %li.bottom= paginate @milestones, :remote => true, :theme => "gitlab"
  23 + - else
  24 + %li
  25 + %p.padded Nothing to show here
... ...
app/views/milestones/new.html.haml 0 → 100644
... ... @@ -0,0 +1 @@
  1 += render "form"
... ...
app/views/milestones/show.html.haml 0 → 100644
... ... @@ -0,0 +1,50 @@
  1 +%h3
  2 + Milestone ##{@milestone.id}
  3 + %small
  4 + = @milestone.expires_at
  5 +
  6 + %span.right
  7 + - if can?(current_user, :admin_milestone, @project)
  8 + = link_to edit_project_milestone_path(@project, @milestone), :class => "btn" do
  9 + Edit
  10 +
  11 +.back_link
  12 + = link_to project_milestones_path(@project) do
  13 + &larr; To milestones list
  14 +
  15 +.main_box
  16 + .top_box_content
  17 + %h5
  18 + - if @milestone.closed
  19 + .alert-message.error.status_info Closed
  20 + - else
  21 + .alert-message.success.status_info Open
  22 + = @milestone.title
  23 +
  24 + .middle_box_content
  25 + .row
  26 + .span2
  27 + = link_to 'Browse Issues', project_issues_path(@milestone.project, :milestone_id => @milestone.id), :class => "btn small edit-milestone-link"
  28 + .span4
  29 + %span
  30 + = @milestone.expires_at
  31 +
  32 + .span4.right
  33 + .progress
  34 + %br
  35 + %span
  36 + #{@milestone.issues.opened.count} open
  37 + &ndash;
  38 + #{@milestone.issues.closed.count} closed
  39 +
  40 + - if @milestone.description.present?
  41 + .bottom_box_content
  42 + = markdown @milestone.description
  43 +
  44 +
  45 +:javascript
  46 + $(function() {
  47 + $( ".progress" ).progressbar({
  48 + value: #{@milestone.percent_complete}
  49 + });
  50 + });
... ...
config/routes.rb
... ... @@ -122,6 +122,7 @@ Gitlab::Application.routes.draw do
122 122 end
123 123 end
124 124 resources :team_members
  125 + resources :milestones
125 126 resources :issues do
126 127 collection do
127 128 post :sort
... ...
db/migrate/20120408180246_create_milestones.rb 0 → 100644
... ... @@ -0,0 +1,12 @@
  1 +class CreateMilestones < ActiveRecord::Migration
  2 + def change
  3 + create_table :milestones do |t|
  4 + t.string :title, :null => false
  5 + t.integer :project_id, :null => false
  6 + t.text :description
  7 + t.date :due_date
  8 + t.boolean :closed, :default => false, :null => false
  9 + t.timestamps
  10 + end
  11 + end
  12 +end
... ...
db/migrate/20120408181910_add_milestone_id_to_issue.rb 0 → 100644
... ... @@ -0,0 +1,5 @@
  1 +class AddMilestoneIdToIssue < ActiveRecord::Migration
  2 + def change
  3 + add_column :issues, :milestone_id, :integer, :null => true
  4 + end
  5 +end
... ...
db/schema.rb
... ... @@ -11,7 +11,7 @@
11 11 #
12 12 # It's strongly recommended to check this file into your version control system.
13 13  
14   -ActiveRecord::Schema.define(:version => 20120405211750) do
  14 +ActiveRecord::Schema.define(:version => 20120408181910) do
15 15  
16 16 create_table "events", :force => true do |t|
17 17 t.string "target_type"
... ... @@ -30,13 +30,14 @@ ActiveRecord::Schema.define(:version =&gt; 20120405211750) do
30 30 t.integer "assignee_id"
31 31 t.integer "author_id"
32 32 t.integer "project_id"
33   - t.datetime "created_at", :null => false
34   - t.datetime "updated_at", :null => false
35   - t.boolean "closed", :default => false, :null => false
36   - t.integer "position", :default => 0
37   - t.boolean "critical", :default => false, :null => false
  33 + t.datetime "created_at", :null => false
  34 + t.datetime "updated_at", :null => false
  35 + t.boolean "closed", :default => false, :null => false
  36 + t.integer "position", :default => 0
  37 + t.boolean "critical", :default => false, :null => false
38 38 t.string "branch_name"
39 39 t.text "description"
  40 + t.integer "milestone_id"
40 41 end
41 42  
42 43 add_index "issues", ["project_id"], :name => "index_issues_on_project_id"
... ... @@ -69,6 +70,15 @@ ActiveRecord::Schema.define(:version =&gt; 20120405211750) do
69 70  
70 71 add_index "merge_requests", ["project_id"], :name => "index_merge_requests_on_project_id"
71 72  
  73 + create_table "milestones", :force => true do |t|
  74 + t.string "title", :null => false
  75 + t.text "description"
  76 + t.date "due_date", :null => false
  77 + t.integer "project_id", :null => false
  78 + t.datetime "created_at", :null => false
  79 + t.datetime "updated_at", :null => false
  80 + end
  81 +
72 82 create_table "notes", :force => true do |t|
73 83 t.text "note"
74 84 t.string "noteable_id"
... ...
spec/models/milestone_spec.rb 0 → 100644
... ... @@ -0,0 +1,5 @@
  1 +require 'spec_helper'
  2 +
  3 +describe Milestone do
  4 + pending "add some examples to (or delete) #{__FILE__}"
  5 +end
... ...