├── LICENSE ├── LICENSE.simply_agile ├── README.rdoc ├── VERSION ├── app ├── controllers │ ├── acceptance_criteria_controller.rb │ ├── active_iterations_controller.rb │ ├── application_controller.rb │ ├── burndowns_controller.rb │ ├── easy_agile_common_controller.rb │ ├── easy_agile_controller.rb │ ├── iterations_controller.rb │ ├── stories_controller.rb │ └── story_team_members_controller.rb ├── helpers │ ├── acceptance_criteria_helper.rb │ ├── active_iterations_helper.rb │ ├── application_helper.rb │ ├── burndowns_helper.rb │ ├── easy_agile_helper.rb │ ├── iterations_helper.rb │ ├── stories_helper.rb │ └── story_team_members_helper.rb ├── models │ ├── acceptance_criterion.rb │ ├── acceptance_criterion_observer.rb │ ├── burndown.rb │ ├── burndown_data_point.rb │ ├── iteration.rb │ ├── story.rb │ ├── story_action.rb │ ├── story_action_observer.rb │ └── story_team_member.rb └── views │ ├── acceptance_criteria │ ├── _criterion.erb │ ├── _list.erb │ ├── edit.html.erb │ └── edit.js.erb │ ├── easy_agile │ ├── show.html.erb │ └── show_guidance.html.erb │ ├── iterations │ ├── _form.erb │ ├── _iteration.erb │ ├── _list_item.erb │ ├── edit.html.erb │ ├── finished.html.erb │ ├── index.html.erb │ ├── new.html.erb │ ├── new_guidance.html.erb │ ├── planned.html.erb │ ├── show.html.erb │ └── show_active.html.erb │ ├── layouts │ ├── ea_base.html.erb │ └── request.html.erb │ ├── my │ └── blocks │ │ ├── _active_work.erb │ │ └── _easy_agile_home.erb │ ├── stories │ ├── _estimating_story.erb │ ├── _form.erb │ ├── _list_item.erb │ ├── _prioritising_story.erb │ ├── _status_form.erb │ ├── _story.html.erb │ ├── backlog.html.erb │ ├── backlog_guidance.html.erb │ ├── edit.html.erb │ ├── index.html.erb │ ├── new_with_iteration.html.erb │ ├── new_with_project.html.erb │ ├── show.feature.erb │ └── show.html.erb │ └── story_team_members │ └── _story_team_member.erb ├── assets ├── images │ ├── a_simple_tool_for_effective_agile_teams.png │ ├── active_iteration.png │ ├── arrow_from_grey.png │ ├── arrow_large_left.png │ ├── arrow_large_left_highlighted.png │ ├── arrow_large_right.png │ ├── arrow_large_right_highlighted.png │ ├── arrow_small_right.gif │ ├── arrow_small_right.png │ ├── arrow_small_right_green_background.png │ ├── arrow_small_right_grey_background.png │ ├── arrow_small_right_orange_background.png │ ├── burndown.png │ ├── button_background.png │ ├── fella_in_progress.gif │ ├── fella_in_progress.png │ ├── fella_testing.gif │ ├── fella_testing.png │ ├── new_story.png │ ├── new_story_highlight.png │ ├── planning_iteration.png │ ├── simply_agile.png │ ├── simply_agile_large.png │ ├── simply_agile_twitter.png │ ├── story_card.png │ ├── try_it_free.png │ └── underline_green.png ├── javascripts │ ├── acceptance_criteria.js │ ├── application.js │ ├── backlog_prioritisation.js │ ├── flash.js │ ├── iteration_active.js │ ├── iteration_planning.js │ ├── jquery-1.3.2.min.js │ ├── jquery-ui-1.7.custom.min.js │ ├── jquery.form.js │ ├── request.js │ └── story.js └── stylesheets │ ├── application │ ├── colours.css │ ├── layout.css │ └── typography.css │ ├── iteration │ ├── colours.css │ ├── layout.css │ └── typography.css │ ├── iteration_active │ ├── colours.css │ ├── layout.css │ └── typography.css │ ├── iteration_planning │ ├── colours.css │ ├── layout.css │ └── typography.css │ ├── landing │ ├── colours.css │ ├── layout.css │ └── typography.css │ └── story │ ├── colours.css │ ├── layout.css │ └── typography.css ├── config ├── locales │ ├── activerecord.yml │ ├── en.yml │ ├── it.yml │ ├── numbers.yml │ ├── pt-BR.yml │ └── ru.yml └── routes.rb ├── db └── migrate │ ├── 20090303213012_create_iterations.rb │ ├── 20090304004418_create_stories.rb │ ├── 20090304193819_create_acceptance_criteria.rb │ ├── 20090310175005_create_burndown_data_points.rb │ ├── 20090325133236_create_story_team_members.rb │ └── 20090327110522_create_story_actions.rb ├── init.rb └── lib ├── my_controller_patch.rb ├── project_patch.rb └── user_patch.rb /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2010, Sphere Consulting inc. 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. -------------------------------------------------------------------------------- /LICENSE.simply_agile: -------------------------------------------------------------------------------- 1 | Copyright © 2010 Andrew Bruce and John Cinnamond. All Rights Reserved. 2 | 3 | Redistribution and use in source and binary forms, with or without modification, 4 | are permitted provided that the following conditions are met: 5 | 6 | 1. Redistributions of source code must retain the above copyright notice, this 7 | list of conditions and the following disclaimer. 8 | 9 | 2. Redistributions in binary form must reproduce the above copyright notice, 10 | this list of conditions and the following disclaimer in the documentation and/or 11 | other materials provided with the distribution. 12 | 13 | 3. The name of the author may not be used to endorse or promote products derived 14 | from this software without specific prior written permission. 15 | 16 | THIS SOFTWARE IS PROVIDED BY ANDREW BRUCE AND JOHN CINNAMOND "AS IS" AND ANY 17 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20 | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 21 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 22 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 23 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 24 | OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 25 | ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | 27 | 28 | -------------------------------------------------------------------------------- /README.rdoc: -------------------------------------------------------------------------------- 1 | = easy_agile 2 | 3 | Easy Agile is a Redmine[http://www.redmine.org] plugin for agile development teams. Based on the original {Simply Agile}[http://github.com/camelpunch/simply_agile]. 4 | 5 | == Install 6 | {Install Redmine}[http://www.redmine.org/wiki/redmine/RedmineInstall]. Follow the Redmine plugin installation manual[http://www.redmine.org/wiki/redmine/Plugins]. Or go this way (inside the Redmine directory). Make sure you have git installed: 7 | ./script/plugin install git@github.com:SphereConsultingInc/easy_agile.git 8 | or: 9 | cd vendor/plugins 10 | git clone git://github.com/SphereConsultingInc/easy_agile.git 11 | Start migration: 12 | rake db:migrate_plugins RAILS_ENV=production (or simply "rake db:migrate_plugins" for development mode) 13 | 14 | Install nested_layouts[https://github.com/jwigal/nested_layouts] plugin (from Redmine root directory): 15 | ./script/plugin install git://github.com/jwigal/nested_layouts.git 16 | 17 | Install ImageMagick and RMagick. See the RMagick's {Installation FAQ}[http://rmagick.rubyforge.org/install-faq.html] for details. Windows users might need to reinstall RMagick and ImageMagick in case of any problems. 18 | 19 | Install {gruffs library}[https://github.com/topfunky/gruff] (if you want your Redmine installation to be portable): 20 | gem install gruff 21 | cd vendor/plugins && gem unpack gruff 22 | or (if you want to use gruff from gems): 23 | gem install gruff 24 | and add the following line to your config/environment.rb file: 25 | config.gem "gruff" 26 | 27 | Then restart Redmine. In project's setting in Modules include 'Easy Agile' or enable it globally for all projects from Administration area. It will be available under 'Easy Agile' tab. 28 | 29 | Recent activities summary is available inside 'My Page' area. 30 | 31 | == Description 32 | Easy Agile is a simple task board which allows you to define stories and track their statuses through iteration. The application is quite straigtforward for the people familiar with the SCRUM and Agile methodology. 33 | 34 | == Credits 35 | Easy Agile based on the original {Simply Agile}[http://github.com/camelpunch/simply_agile] standalone application by {Jandaweb}[http://www.jandaweb.com/] (see LICENSE.simply_agile). 36 | 37 | === Project team 38 | * Sphere Consulting Inc Development Team 39 | 40 | Copyright (c) 2010 {Sphere Consulting Inc.}[http://www.sphereinc.com], released under the MIT license (see LICENSE). 41 | -------------------------------------------------------------------------------- /VERSION: -------------------------------------------------------------------------------- 1 | 1.0.5 -------------------------------------------------------------------------------- /app/controllers/acceptance_criteria_controller.rb: -------------------------------------------------------------------------------- 1 | class AcceptanceCriteriaController < ApplicationController 2 | before_filter :find_optional_project 3 | before_filter :get_story 4 | before_filter :new_acceptance_criterion, :only => :create 5 | before_filter :get_acceptance_criterion, :only => [:edit, :update] 6 | 7 | layout :decide_layout 8 | 9 | def create 10 | respond_to do |format| 11 | format.html do 12 | if @acceptance_criterion.update_attributes(params[:acceptance_criterion]) 13 | redirect_to [@project, @story] 14 | else 15 | render(:template => 'stories/show') 16 | end 17 | end 18 | 19 | format.js do 20 | if @acceptance_criterion.update_attributes(params[:acceptance_criterion]) 21 | render(:partial => 'acceptance_criteria/list') 22 | else 23 | render(:text => @acceptance_criterion.errors.full_messages.join("\n"), 24 | :status => :unprocessable_entity) 25 | end 26 | end 27 | end 28 | end 29 | 30 | def update 31 | previous_story_status = @story.status 32 | previous_story_users_empty = @story.users.empty? 33 | 34 | if @acceptance_criterion.update_attributes(params[:acceptance_criterion]) 35 | @story.reload 36 | if previous_story_status != @story.status 37 | new_status = ActiveSupport::Inflector.titleize(@story.status) 38 | message = "Story status has changed to '#{new_status}'. " 39 | end 40 | 41 | if !previous_story_users_empty && @story.users.empty? 42 | message ||= '' 43 | message << "Story team members have been removed." 44 | end 45 | 46 | respond_to do |format| 47 | format.html do 48 | flash[:notice] = message 49 | redirect_to project_story_url(@story.project, @story) 50 | end 51 | 52 | format.js do 53 | render :text => message 54 | end 55 | end 56 | 57 | else 58 | render(:text => @acceptance_criterion.errors.full_messages.join("\n"), 59 | :status => :unprocessable_entity) 60 | end 61 | end 62 | 63 | def destroy 64 | @story.acceptance_criteria.find(params[:id]).destroy 65 | respond_to do |format| 66 | format.html do 67 | redirect_to [@project, @story] 68 | end 69 | 70 | format.js do 71 | render :partial => 'acceptance_criteria/list' 72 | end 73 | end 74 | end 75 | 76 | def edit 77 | respond_to do |format| 78 | format.html 79 | format.js 80 | end 81 | end 82 | 83 | protected 84 | 85 | def decide_layout 86 | layout = '' 87 | respond_to do |format| 88 | format.js do 89 | layout = 'request' 90 | end 91 | end 92 | 93 | layout 94 | end 95 | 96 | def get_story 97 | @story = @project.stories.find(params[:story_id]) 98 | end 99 | 100 | def get_acceptance_criterion 101 | @acceptance_criterion = @story.acceptance_criteria.find(params[:id]) 102 | end 103 | 104 | def new_acceptance_criterion 105 | @acceptance_criterion = @story.acceptance_criteria.build 106 | end 107 | 108 | end 109 | -------------------------------------------------------------------------------- /app/controllers/active_iterations_controller.rb: -------------------------------------------------------------------------------- 1 | class ActiveIterationsController < ApplicationController 2 | 3 | helper :stories 4 | before_filter :get_iteration 5 | 6 | def create 7 | if @iteration.start 8 | redirect_to [@iteration.project, @iteration] 9 | else 10 | @project = @iteration.project 11 | render :template => 'iterations/show' 12 | end 13 | end 14 | 15 | protected 16 | 17 | def get_iteration 18 | @iteration = Iteration.find(params[:iteration_id]) 19 | end 20 | end 21 | -------------------------------------------------------------------------------- /app/controllers/application_controller.rb: -------------------------------------------------------------------------------- 1 | class ApplicationController < ActionController::Base 2 | end 3 | -------------------------------------------------------------------------------- /app/controllers/burndowns_controller.rb: -------------------------------------------------------------------------------- 1 | class BurndownsController < ApplicationController 2 | before_filter :get_iteration 3 | before_filter :get_burndown 4 | 5 | def show 6 | send_data( 7 | @burndown.to_png, 8 | :disposition => 'inline', 9 | :type => 'image/png', 10 | :filename => "#{@iteration.name} Burndown.png" 11 | ) 12 | end 13 | 14 | protected 15 | 16 | def get_iteration 17 | @iteration = Iteration.find(params[:iteration_id]) 18 | end 19 | 20 | def get_burndown 21 | @burndown = @iteration.burndown(params[:width]) 22 | end 23 | end 24 | -------------------------------------------------------------------------------- /app/controllers/easy_agile_common_controller.rb: -------------------------------------------------------------------------------- 1 | class EasyAgileCommonController < ApplicationController 2 | layout 'ea_base' 3 | helper :easy_agile 4 | 5 | alias_method :tab_name, :controller_name 6 | 7 | def controller_name 8 | "easy_agile" 9 | end 10 | 11 | # show tabs in a layout? 12 | def has_tabs? 13 | true 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /app/controllers/easy_agile_controller.rb: -------------------------------------------------------------------------------- 1 | class EasyAgileController < EasyAgileCommonController 2 | before_filter :find_optional_project 3 | 4 | helper :stories 5 | 6 | def show 7 | if @project.stories.empty? 8 | render :template => 'easy_agile/show_guidance' 9 | end 10 | end 11 | 12 | def my_page 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /app/controllers/iterations_controller.rb: -------------------------------------------------------------------------------- 1 | class IterationsController < EasyAgileCommonController 2 | before_filter :find_optional_project 3 | before_filter :get_iterations, :only => [:index] 4 | before_filter :get_finished_iterations, :only => [:finished] 5 | before_filter :get_pending_iterations, :only => [:planned] 6 | before_filter :get_iteration, :only => [:edit, :show, :update] 7 | before_filter :new_iteration, :only => [:new, :create] 8 | before_filter :get_stories, :only => [:edit, :new] 9 | 10 | helper :stories 11 | 12 | def create 13 | @iteration.save_with_planned_stories_attributes! params[:stories] 14 | redirect_to [@project, @iteration] 15 | 16 | rescue ActiveRecord::RecordInvalid => e 17 | @stories = @iteration.planned_stories 18 | render :template => 'iterations/new' 19 | end 20 | 21 | def new 22 | if @stories.empty? 23 | render :template => 'iterations/new_guidance' 24 | end 25 | end 26 | 27 | def update 28 | @iteration.attributes = params[:iteration] 29 | @iteration.save_with_planned_stories_attributes! params[:stories] 30 | redirect_to [@project, @iteration] 31 | 32 | rescue ActiveRecord::RecordInvalid => e 33 | @stories = e.record.planned_stories 34 | render :template => 'iterations/edit' 35 | end 36 | 37 | def show 38 | if @iteration.active? 39 | render :template => 'iterations/show_active' 40 | end 41 | end 42 | 43 | protected 44 | 45 | def get_iterations 46 | @iterations = @project.iterations.active 47 | end 48 | 49 | def get_pending_iterations 50 | @iterations = @project.iterations.pending 51 | end 52 | 53 | def get_finished_iterations 54 | @iterations = @project.iterations.finished 55 | end 56 | 57 | def get_iteration 58 | @iteration = @project.iterations.find(params[:id]) 59 | end 60 | 61 | def get_stories 62 | @stories = @project.stories.assigned_or_available_for(@iteration) 63 | end 64 | 65 | def new_iteration 66 | @iteration = @project.iterations.build(params[:iteration]) 67 | end 68 | end 69 | -------------------------------------------------------------------------------- /app/controllers/stories_controller.rb: -------------------------------------------------------------------------------- 1 | class StoriesController < EasyAgileCommonController 2 | before_filter :find_optional_project 3 | before_filter :get_iteration, :only => [:new, :create] 4 | before_filter :get_story, :only => [:edit, :update, :show, :estimate] 5 | before_filter :new_story, :only => [:new, :create] 6 | 7 | helper :easy_agile 8 | 9 | 10 | def backlog 11 | @has_tabs = true 12 | if @project.stories.backlog.empty? 13 | render :template => 'stories/backlog_guidance', :layout => 'ea_base' 14 | return 15 | end 16 | render :template => 'stories/backlog', :layout => 'ea_base' 17 | end 18 | 19 | def show 20 | respond_to do |format| 21 | format.html do 22 | if params[:iteration_id] 23 | redirect_to [@project, @story], :status => 301 24 | end 25 | end 26 | 27 | format.feature 28 | end 29 | end 30 | 31 | def create 32 | if @story.save 33 | respond_to do |format| 34 | format.html do 35 | redirect_to [@project, @story] 36 | end 37 | 38 | format.js do 39 | head :created, :location => project_story_url(@project, @story) 40 | end 41 | end 42 | 43 | elsif @story.iteration_id? 44 | @iteration = @story.iteration 45 | render(:status => :unprocessable_entity, 46 | :template => 'stories/new_with_iteration') 47 | else 48 | render(:status => :unprocessable_entity, 49 | :template => 'stories/new_with_project') 50 | end 51 | end 52 | 53 | def estimate 54 | @body_classes = [controller_name, 'iteration_planning'] 55 | render :partial => 'stories/story', :object => @story 56 | end 57 | 58 | def index 59 | respond_to do |format| 60 | format.html 61 | format.json do 62 | get_iteration 63 | render :json => @iteration.stories.to_json(:only => [:status, :id]) 64 | end 65 | end 66 | end 67 | 68 | def new 69 | @story.content = "As a 70 | I want 71 | So that " 72 | 73 | if @iteration 74 | render :template => 'stories/new_with_iteration' 75 | elsif @project 76 | render :template => 'stories/new_with_project' 77 | else 78 | render :template => 'stories/new_guidance' 79 | end 80 | end 81 | 82 | def update 83 | if params[:iteration_id] 84 | @story.update_attributes! params[:story] 85 | 86 | respond_to do |format| 87 | format.html do 88 | if params[:story][:status] 89 | redirect_to project_iteration_url(@project, params[:iteration_id]) 90 | else 91 | redirect_to [@project, @story] 92 | end 93 | end 94 | 95 | format.js do 96 | head :ok 97 | end 98 | end 99 | 100 | else 101 | @story.update_attributes! params[:story] 102 | redirect_to [@project, @story] 103 | end 104 | 105 | rescue ActiveRecord::RecordInvalid => e 106 | render :template => 'stories/edit' 107 | end 108 | 109 | def has_tabs? 110 | @has_tabs 111 | end 112 | 113 | protected 114 | 115 | def get_iteration 116 | if params[:iteration_id] && @project 117 | @iteration = @project.iterations.find(params[:iteration_id]) 118 | end 119 | end 120 | 121 | def get_story 122 | @story = @project.stories.find(params[:id]) 123 | end 124 | 125 | def new_story 126 | if @iteration 127 | @story = @iteration.stories.build(params[:story]) 128 | elsif @project 129 | @story = @project.stories.build(params[:story]) 130 | else 131 | @story = Story.new 132 | end 133 | end 134 | 135 | end 136 | -------------------------------------------------------------------------------- /app/controllers/story_team_members_controller.rb: -------------------------------------------------------------------------------- 1 | class StoryTeamMembersController < ApplicationController 2 | before_filter :find_optional_project 3 | before_filter :new_story_team_member, :only => [:create] 4 | before_filter :get_story_team_member, :only => [:destroy] 5 | 6 | helper :stories 7 | 8 | def create 9 | if @story_team_member.save 10 | redirect_to [ 11 | @story_team_member.story.project, 12 | @story_team_member.story 13 | ] 14 | else 15 | @story = @story_team_member.story 16 | render :template => 'stories/show' 17 | end 18 | end 19 | 20 | def destroy 21 | @story_team_member.destroy 22 | redirect_to [ 23 | @story_team_member.story.project, 24 | @story_team_member.story 25 | ] 26 | end 27 | 28 | protected 29 | 30 | def new_story_team_member 31 | @story_team_member = 32 | StoryTeamMember.new(params[:story_team_member]. 33 | merge(:user => User.current)) 34 | 35 | end 36 | 37 | def get_story_team_member 38 | @story_team_member = 39 | StoryTeamMember.find(params[:id], 40 | :conditions => ['user_id = ?', User.current.id]) 41 | end 42 | end 43 | -------------------------------------------------------------------------------- /app/helpers/acceptance_criteria_helper.rb: -------------------------------------------------------------------------------- 1 | module AcceptanceCriteriaHelper 2 | end 3 | -------------------------------------------------------------------------------- /app/helpers/active_iterations_helper.rb: -------------------------------------------------------------------------------- 1 | module ActiveIterationsHelper 2 | end 3 | -------------------------------------------------------------------------------- /app/helpers/application_helper.rb: -------------------------------------------------------------------------------- 1 | module ApplicationHelper 2 | 3 | def javascript_includes 4 | javascript_include_tag('jquery-1.3.2.min.js', 5 | 'jquery-ui-1.7.custom.min.js', 6 | 'jquery.form.js', 7 | 'application', 8 | 'flash', 9 | 'story', 10 | 'request', 11 | 'acceptance_criteria', 12 | 'iteration_planning', 13 | 'iteration_active', 14 | 'backlog_prioritisation', 15 | :plugin => 'easy_agile') 16 | end 17 | 18 | def next_steps(&block) 19 | content = '
5 | <%= hidden_field_tag "acceptance_criterion[complete]", 6 | ! criterion.complete?, :id => "complete_#{criterion.id}" %> 7 | <%= f.submit criterion.complete? ? l(:uncomplete) : l(:complete), :id => nil, :class => 'submit_complete' %> 8 |
9 | <% end -%> 10 |3 | <%= l(:story_no_acceptance_criteria) %> 4 |
5 | <% else %> 6 |6 | <%= f.label :criterion %> 7 | <%= f.text_field :criterion, :class => 'auto_focus' %> 8 | <%= f.submit 'Update' %> 9 |
10 | <% end %> 11 | 12 | -------------------------------------------------------------------------------- /app/views/acceptance_criteria/edit.js.erb: -------------------------------------------------------------------------------- 1 |5 | <%= 6 | f.text_field :criterion, 7 | :id => 'edit_acceptance_criterion_criterion', 8 | :class => 'auto_focus' 9 | %> 10 | <%= f.submit l(:button_update) %> 11 |
12 | <% end %> 13 |9 | <%= l(:project_has_no_backlog) %> 10 |
11 | <% else %> 12 |17 | <%= l(:the_rest_stories) %> <%= @project.stories.backlog.size - 10 %> <%= l(:in) %> 18 | <%= link_to l(:full_backlog), 19 | backlog_project_stories_path(@project) %>. 20 |
21 | <% end %> 22 | <% end -%> 23 |32 | <%= l(:no_active_or_planned_iterations) %> 33 |
34 | <% unless @project.iterations.finished.empty? %> 35 |36 | <%= link_to l(:finished_iterations), finished_project_iterations_path(@project) %> 37 |
38 | <% end %> 39 |9 | <%= l(:you_can_start_by_new_story) %> <%= link_to l(:creating_new_story), [:new, @project, :story] %>. 10 |
11 | -------------------------------------------------------------------------------- /app/views/iterations/_form.erb: -------------------------------------------------------------------------------- 1 |<%= l(:iteration_plan_guidance) %>
2 | <%= form.error_messages %> 3 |4 | <%= form.label :name %> 5 | <%= form.text_field :name %> 6 |
7 |8 | <%= form.label :duration, l(:duration_days) %> 9 | <%= form.text_field :duration, :class => 'numeric', :size => 2 %> 10 |
11 | 12 |8 | <%= form.submit l(:update_iteration) %> 9 |
10 | <% end %> 11 | -------------------------------------------------------------------------------- /app/views/iterations/finished.html.erb: -------------------------------------------------------------------------------- 1 | <% content_for :title, l(:finished_iterations) %> 2 | <% content_for :h2, l(:finished_iterations) %> 3 | <% content_for :actions do %> 4 |10 | <%= l(:page_only_finished_iterations) %> 11 |
12 |13 | <%= l(:no_finished_iterations) %> 14 |
15 | <% else -%> 16 |10 | <%= l(:page_only_active_iterations) %> 11 |
12 |13 | <%= l(:no_active_iterations) %> 14 |
15 | <% else -%> 16 |8 | <%= form.submit l(:create_iteration) %> 9 |
10 | <% end %> 11 | -------------------------------------------------------------------------------- /app/views/iterations/new_guidance.html.erb: -------------------------------------------------------------------------------- 1 | <% content_for :title, l(:new_iteration_for) + " #{@project}" %> 2 | <% content_for :h2, l(:no_stories_for) + " #{h(@project)}" %> 3 | <% body_classes << 'guidance' %> 4 | 5 |6 | <%= l(:no_stories_no_iteration) %> 7 |
8 |9 | <%= l(:you_might_want) %> <%= link_to l(:create_story_for_project), new_project_story_path(@project) %>. 10 |
11 | -------------------------------------------------------------------------------- /app/views/iterations/planned.html.erb: -------------------------------------------------------------------------------- 1 | <% content_for :title, l(:planned_iterations) %> 2 | <% content_for :h2, l(:planned_iterations) %> 3 | <% content_for :actions do %> 4 |10 | <%= l(:page_only_planned_iterations) %> 11 |
12 |13 | <%= l(:no_planned_iterations) %> 14 |
15 | <% else -%> 16 |11 | <%= f.submit l(:start_iteration) %> 12 |
13 | <%= f.error_messages %> 14 | <% end %> 15 | 16 |<%= l(:iteration_no_stories) %>
21 | <% else %> 22 |23 | <%= l(:total_story_points) %>: <%= @iteration.stories.sum(:estimate) %> 24 |
25 |<%= l(:iteration_drag_stories) %>
18 | <% if @iteration.finished? %> 19 | <%= l(:iteration_finished_on) %> <%= @iteration.end_date %> 20 | <% else %> 21 | <%= @iteration.start_date %> - <%= @iteration.end_date %>. <%= l(:iteration_days_left) %>: <%= @iteration.days_remaining.to_s %>. 22 | <% end %> 23 |
24 |2 | <%= form.label :name %> 3 | <%= form.text_field :name, :class => 'auto_focus' %> 4 |
5 |6 | <%= form.label :content %> 7 | <%= form.text_area :content, :rows => 5, :cols => 28 %> 8 |
9 | -------------------------------------------------------------------------------- /app/views/stories/_list_item.erb: -------------------------------------------------------------------------------- 1 |2 | <%= label_tag "priorities_#{prioritising_story.id}", 'Priority' %> 3 | <%= text_field_tag("project[priorities[#{prioritising_story.id}]]", 4 | prioritising_story.priority, 5 | :id => "priorities_#{prioritising_story.id}", 6 | :class => 'numeric', 7 | :size => 2) %> 8 |
9 | -------------------------------------------------------------------------------- /app/views/stories/_status_form.erb: -------------------------------------------------------------------------------- 1 |24 | <%= status_form.submit l(:update_status), :id => nil %> 25 |
26 | -------------------------------------------------------------------------------- /app/views/stories/_story.html.erb: -------------------------------------------------------------------------------- 1 |<%= l(:story_points) %>: <%= story.estimate %>
20 | <% end %> 21 | <% end %> 22 |<%= l(:backlog_drag_stories) %>
7 |11 | <%= f.submit 'Save Priorities' %> 12 |
13 | <% end %> 14 | 15 |7 | <%= l(:new_story_in_backlog) %> 8 | <%= link_to l(:new_story_accusative), new_project_story_path(@project) %>. 9 |
10 | -------------------------------------------------------------------------------- /app/views/stories/edit.html.erb: -------------------------------------------------------------------------------- 1 | <% content_for :title, "#{l(:editing)} #{@story}" %> 2 | <% content_for :h2, h("#{l(:editing)} #{@story}") %> 3 | <% form_for [@project, @story] do |form| %> 4 | <%= form.error_messages %> 5 | <%= render form %> 6 |7 | <%= form.submit l(:update_story) %> 8 |
9 | <% end %> 10 | -------------------------------------------------------------------------------- /app/views/stories/index.html.erb: -------------------------------------------------------------------------------- 1 | <% content_for :title, "#{l(:story_plural)} #{@project}" %> 2 | <% content_for :h2, h("#{l(:story_plural)} #{@project}") %> 3 | <% unless @project.stories.empty? %> 4 |6 | <%= form.check_box :iteration_id, {}, @iteration.id, nil %> 7 | <%= form.label :iteration_id, l(:add_to_iteration) + " '#{h(@iteration)}'" %> 8 |
9 | <%= render form %> 10 |11 | <%= form.submit l(:create_story) %> 12 |
13 | <% end %> 14 | -------------------------------------------------------------------------------- /app/views/stories/new_with_project.html.erb: -------------------------------------------------------------------------------- 1 | <% content_for :title, l(:new_story) %> 2 | <% content_for :h2, l(:new_story) %> 3 | <% form_for @story, :url => project_stories_path do |form| %> 4 | <%= form.error_messages %> 5 | <%= render form %> 6 |7 | <%= form.submit l(:create_story) %> 8 |
9 | <% end %> 10 | -------------------------------------------------------------------------------- /app/views/stories/show.feature.erb: -------------------------------------------------------------------------------- 1 | <%= l(:feature) %>: <%= @story.name %> 2 | <%= @story.content.gsub(/^/, ' ') %> 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/views/stories/show.html.erb: -------------------------------------------------------------------------------- 1 | <% content_for :title, "#{@story} | #{@project} " + l(:story_plural) %> 2 | <% content_for :h2, l(:story) + " ##{@story.id}" %> 3 | <% content_for :actions do %> 4 |Story Points: <%= @story.estimate %>
15 | <% end %> 16 |34 | <%= f.hidden_field :story_id %> 35 | <%= f.submit l(:work_on_story) %> 36 |
37 | <% end %> 38 | <% end %> 39 |47 | <%= f.label :criterion, l(:new_criterion) %> 48 | <%= f.text_field :criterion, :class => 'auto_focus', :size => 20 %> 49 | <%= f.submit l(:button_add) %> 50 |
51 | <% end %> 52 | 53 |Your browser does not support modern web standards. "+ 5 | "Please upgrade to a more recent browser for a better experience.
"; 6 | 7 | if ($('.important_message')[0]) { 8 | $('.important_message div').prepend(message); 9 | } else { 10 | $('#content').after(' '); 11 | } 12 | 13 | $('.important_message') 14 | .css({position: 'absolute', textAlign: 'center', opacity:0.9}); 15 | $('.important_message div') 16 | .css({width:'auto', 17 | margin:0}); 18 | return false; 19 | } 20 | $('div.ea_container').addClass('javascript'); 21 | 22 | // highlight first erroneous field / auto focus field 23 | var first_error_field = $('.field_with_errors')[0]; 24 | if (first_error_field) first_error_field.focus(); 25 | else $('.auto_focus').focus(); 26 | 27 | // stories/show 28 | if ($('div#stories_show')) AcceptanceCriteria.init(); 29 | 30 | // iterations/new 31 | if ($('#stories_available')[0]) { 32 | // start swapper 33 | StorySwapper.init(); 34 | } 35 | 36 | // iterations/show when active 37 | if ($('div').hasClass('iteration_active')) { 38 | new DraggableStories(); 39 | // don't enhance stories 40 | } else if (!$('div#home_show')[0]) { 41 | // normal story enhancements 42 | $('#content .story').each( function() { new Story(this) }); 43 | } 44 | 45 | // backlog 46 | if ($('div#stories_backlog')[0]) { 47 | BacklogPrioritisation.init(); 48 | } 49 | 50 | }); 51 | 52 | // source: http://www.hunlock.com/blogs/Mastering_Javascript_Arrays 53 | Array.prototype.compare = function(testArr) { 54 | if (this.length != testArr.length) return false; 55 | for (var i = 0; i < testArr.length; i++) { 56 | if (this[i].compare) { 57 | if (!this[i].compare(testArr[i])) return false; 58 | } 59 | if (this[i] !== testArr[i]) return false; 60 | } 61 | return true; 62 | } 63 | 64 | // add header to AJAX requests to play nice with Rails' content negotiation 65 | jQuery.ajaxSetup({ 66 | 'beforeSend': function(xhr) { 67 | xhr.setRequestHeader("Accept", "text/javascript") 68 | } 69 | }); 70 | -------------------------------------------------------------------------------- /assets/javascripts/backlog_prioritisation.js: -------------------------------------------------------------------------------- 1 | var BacklogPrioritisation = { 2 | init: function() { 3 | // enable sorting 4 | $('ol.stories').sortable({ 5 | axis: 'y', 6 | stop: function(event, ui) { 7 | var ids = $(this).sortable('toArray'); 8 | $(ids).each( function(i) { 9 | var priority = i + 1; 10 | var field = $('#' + this + ' input[type="text"]'); 11 | 12 | // set new field value 13 | $(field).val(priority); 14 | }); 15 | 16 | // submit form 17 | $('form.edit_project').ajaxSubmit(); 18 | } 19 | }); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /assets/javascripts/flash.js: -------------------------------------------------------------------------------- 1 | function Flash(messages) { 2 | this.messages = messages; 3 | this.draw(); 4 | } 5 | 6 | Flash.prototype = { 7 | draw: function() { 8 | var insert_after, actions; 9 | actions = $('#actions'); 10 | insert_after = actions[0] ? actions : $('h1'); 11 | 12 | // remove previous messages 13 | this.remove(); 14 | 15 | insert_after.after('') 16 | if (this.messages.notice && $.trim(this.messages.notice) != '') { 17 | $('.flash').append(''+this.messages.notice+'
k))&&((e>=g&&e<=c)||(d>=g&&d<=c)||(e';
37 | element.find('.story_header').append(html);
38 | }
39 | }
40 | Story.prototype = {
41 | createContainer: function() {
42 | this.element.find('.less_more').remove();
43 | this.element.find('.story_header h4').before('');
44 | this.container = this.element.find('.less_more');
45 | },
46 |
47 | createMoreAnchor: function() {
48 | var instance = this;
49 |
50 | this.container
51 | .append('More »')
52 |
53 | .find('a.more').click(function() {
54 | instance.acceptance_criteria.toggle();
55 | instance.setMoreHtml();
56 | return false;
57 | });
58 |
59 | this.more = this.container.find('a.more');
60 | this.setMoreHtml();
61 | },
62 |
63 | setMoreHtml: function() {
64 | var html;
65 |
66 | if (this.acceptance_criteria.is(':visible')) {
67 | html = '« Less'
68 | this.less.hide();
69 | } else if (!this.story_content.is(':visible')) {
70 | this.more.hide();
71 | } else {
72 | html = 'More »';
73 | this.less.show();
74 | }
75 | this.more.html(html);
76 | },
77 |
78 | createLessAnchor: function() {
79 | var instance = this;
80 |
81 | this.container.find('a.less').remove();
82 | this.container.append('« Less');
83 | this.less = this.container.find('a.less');
84 |
85 | this.less.click(function() {
86 | instance.story_content.toggle();
87 | instance.setLessHtml();
88 | return false;
89 | });
90 |
91 | this.setLessHtml();
92 | },
93 |
94 | setLessHtml: function() {
95 | var html;
96 |
97 | if (this.story_content.is(':visible')) {
98 | html = '« Less';
99 | if (this.more) this.more.show();
100 | } else {
101 | html = 'More »';
102 | if (this.more) this.more.hide();
103 | }
104 |
105 | this.less.html(html);
106 | }
107 | }
108 |
--------------------------------------------------------------------------------
/assets/stylesheets/application/colours.css:
--------------------------------------------------------------------------------
1 |
2 | #actions a { color:#444; display:block; background:url(../../images/button_background.png) no-repeat }
3 |
4 | div.section, div.section h3 { border:2px solid #e4e5f3 }
5 | div.section .errorExplanation h3 { border: none }
6 | div.section h3 { background:#fff }
7 |
8 | #headings .complete { background:#3dfd4f }
9 | #acceptance_criteria #completed, .aside { color: #aaa }
10 |
11 | /* /\* home/show *\/ */
12 | div#home_show #recent_work .section>ol>li { background:#e4e5f3;
13 | border-bottom:2px solid #fff }
14 | div#home_show #recent_work .section>ol>li:last-child { border:none }
15 | /* /\* end home/show *\/ */
16 |
17 |
--------------------------------------------------------------------------------
/assets/stylesheets/application/layout.css:
--------------------------------------------------------------------------------
1 | /* /\* basic layout *\/ */
2 | /* #container { margin:0 0 0 0; position:relative } */
3 | /* #header { width:100%; padding-bottom:5px } */
4 | /* #contextual_new_story { position:absolute; width:118px; height:99px; */
5 | /* right:30px; top:2px } */
6 | /* #footer { clear:both; padding:0 0 30px 0 } */
7 | /* #footer p { max-width:none } */
8 |
9 | /* .important_message { position:absolute; top:0; left:0; z-index:11; width:100% } */
10 | /* .important_message div { margin:0 auto; width:52em; padding:4px 0 } */
11 | /* .important_message p { margin:0; max-width:none } */
12 |
13 | /* #errorExplanation { margin-bottom:15px } */
14 | /* /\* end basic layout *\/ */
15 |
16 | /* /\* navigation *\/ */
17 | /* #navigation { height:67px; position:relative; width:30.05em } */
18 | /* #header>#navigation { margin:0 auto } */
19 | /* #navigation ol { position:absolute; left:0; bottom:0; height:2.5em } */
20 | /* #navigation li { float:left; height:2.5em; line-height:2.5em; width:6em } */
21 | /* #navigation li a { display:block; width:6em } */
22 | /* /\* end navigation *\/ */
23 |
24 | /* javascript request */
25 | .javascript #request_container { position:fixed; top:140px; height:100%; width:100%; z-index:11 }
26 | .javascript #request { margin:0 auto; width:40%; height:60%;
27 | min-height:340px; overflow:auto; position:relative }
28 | .javascript #request #request_body { padding:5px 15px 0 15px }
29 | .javascript #request h2 { margin-top:1em }
30 | .javascript #request h2#request_header { margin:0; padding:5px 15px }
31 | .javascript #request a#close_request { position:absolute; top:5px; right:8px }
32 |
33 | .javascript #request .edit_acceptance_criterion,
34 | .javascript #request .edit a,
35 | .javascript #request .delete form,
36 | .javascript #request #add_to_iteration,
37 | .javascript #request #next_steps { display:none }
38 | /* end javascript request */
39 |
40 |
41 | /* content */
42 | #actions { position:relative; float:right; width:124px; z-index:20 }
43 | #actions li { width:104px; display:block; margin:0 auto 1em auto }
44 | #actions a { width:104px; height:29px }
45 |
46 | div.section { position:relative; padding:40px 36px 22px 36px;
47 | margin:23px 0 0 11px }
48 | div.with_subsections div.section { padding:0 }
49 | form div.with_subsections div.section { padding-bottom:5px }
50 | form div.with_subsections div.section div.subsection { padding-left:15px }
51 | .section .subsection { position:relative; overflow:hidden }
52 | div.section h3 { position:absolute; z-index:10; top:-25px; padding:12px 23px;
53 | /*ie6*/ left:-50px }
54 | div.section>h3 { left:-13px }
55 | div.section .errorExplanation h3 { position: relative; padding: 0; margin: 0;
56 | top:0; left: 0 }
57 |
58 | .section_container { position:relative; overflow:hidden }
59 | .section_container a.section,
60 | .section_container ul.section_links { position:absolute; right:9px; top:6px; z-index:20 }
61 | .section_container ul.section_links li { float:left; margin-left:1em }
62 | /* end content */
63 |
64 | /* /\* forms *\/ */
65 | /* form p { margin:5px 0 } */
66 | /* form p.submit { margin:15px 0 } */
67 | /* form p label { display:block; width:10em; float:left; line-height:1.5em } */
68 | /* form p.checkbox { overflow:hidden } */
69 | /* form p.checkbox input { float:left } */
70 | /* form p.checkbox label { display:inline; padding-left:5px; width:20em; */
71 | /* line-height:1.2em } */
72 | /* /\* end forms *\/ */
73 |
74 | /* home/show */
75 | .section_container.first { width:56%; max-width:472px;
76 | min-width:275px; float:left;
77 | margin-right:30px;
78 | margin-bottom:30px }
79 | div#home_show #iterations { min-width:345px }
80 | div#home_show #iterations div.active { padding-top:45px }
81 | div#home_show #recently_finished_iterations .finished ol,
82 | div#home_show #iterations ol { overflow:hidden }
83 | div#home_show #recent_work .section { padding:0 }
84 | div#home_show #recent_work .section>ol>li { padding:45px 30px 15px 30px }
85 | div#home_show #recent_work .section>ol>li,
86 | div#home_show #recent_work li div.stories { overflow:hidden }
87 | div#home_show #recent_work li div.iteration { margin-right:30px }
88 | /* /\* end home/show *\/ */
89 |
90 | /* iterations/index */
91 | div#iterations_index .active,
92 | div#iterations_planned .planned,
93 | div#iterations_finished .finished { padding:45px 30px 30px 30px;
94 | overflow:hidden }
95 | /* end iterations/index */
96 |
97 | /* stories/show */
98 | div#stories_show #users ul { width:20em }
99 | div#stories_show #users form.button-to { float:right; margin-top:-4px }
100 | div#stories_show #acceptance_criteria table { width:40%; margin-top:1em }
101 | div#stories_show #acceptance_criteria table td { padding:0 5px }
102 | div#stories_show #acceptance_criteria table td.edit,
103 | div#stories_show #acceptance_criteria table td.delete { width:4em }
104 | div#stories_show #acceptance_criteria table td.complete { width:1em }
105 |
106 | div#stories_show .javascript #acceptance_criteria table .submit_complete { display:none }
107 | div#stories_show #acceptance_criteria form { display:inline }
108 | /* end stories/show */
109 |
110 | /* stories/backlog */
111 | div#stories_backlog .ea_container.javascript p.submit,
112 | div#stories_backlog .javascript .story label,
113 | div#stories_backlog .javascript .story input { display:none }
114 | /* end stories/backlog */
115 |
116 | ol.stories, ol.stories * { margin:0; padding:0 }
117 | .iterations_list, .iteration_active * { list-style:none; margin:0; padding:0 }
118 |
119 | .contextual { position:relative; z-index:50 }
120 |
121 | .col-left { float:left; width:48% }
122 | .clearer { clear:both }
123 |
124 | /* icons */
125 | .icon-new-task { background-image: url(../../../../images/ticket.png); }
126 | .icon-plan-iteration { background-image: url(../../../../images/table_multiple.png); }
127 | .icon-ea-dashboard { background-image: url(../../../../images/news.png); }
128 |
129 |
--------------------------------------------------------------------------------
/assets/stylesheets/application/typography.css:
--------------------------------------------------------------------------------
1 | p { margin:1em 0 1em 0 }
2 | table p { margin:0 }
3 | table th { font-weight:bold }
4 | a:hover { text-decoration:none }
5 |
6 | .numeric { text-align:right }
7 |
8 | legend { font-weight:bold; padding-top:2em }
9 |
10 | #container { text-align:center } /* largely for ie6 centring but reused */
11 | #content { text-align:left }
12 |
13 | .important_message { font-size:93%; font-weight:bold }
14 |
15 | #navigation { font-weight:bold; font-size:123.1%; text-align:center }
16 | #navigation a { text-decoration:none }
17 | #navigation a:hover,
18 | #navigation a:focus { text-decoration:underline }
19 |
20 | #actions a { line-height:29px; text-align:center; text-decoration:none;
21 | font-weight:bold }
22 |
23 | #footer { font-size:77% }
24 |
25 | div.section div.subsection h4 { text-align:right }
26 |
27 | /* iterations/new */
28 | div.iterations .include a { text-indent:-20000px; outline:none; text-underline:none }
29 | div.iterations .display h3 { font-weight:bold }
30 | .javascript #request_container { text-align:left }
31 | .javascript #stories span.estimate { text-align:center }
32 | /* end iterations/new */
33 |
34 | /* iterations/show */
35 | div#iterations_show .javascript #stories .guidance,
36 | div#iterations_show .javascript #headings ol li { text-align:center }
37 | /* end iterations/show */
38 |
--------------------------------------------------------------------------------
/assets/stylesheets/iteration/colours.css:
--------------------------------------------------------------------------------
1 | /* iteration lists */
2 | #content .iteration a img { border:2px solid #fff }
3 | #content .iteration a:hover img,
4 | #content .iteration a:focus img { border:2px solid #999 }
5 | #iterations .active { background:#e4e5f3 }
6 | #iterations .planned { background:#f1f1f8 }
7 | /* end iteration lists */
8 |
--------------------------------------------------------------------------------
/assets/stylesheets/iteration/layout.css:
--------------------------------------------------------------------------------
1 | /* iteration lists */
2 | #iterations div.section .guidance { padding:30px 0 0 15px }
3 | #content .iteration { padding:0 15px; float:left; margin-bottom:15px }
4 | #content .iteration a { display:block; margin:0 auto }
5 | /* end iteration lists */
6 |
--------------------------------------------------------------------------------
/assets/stylesheets/iteration/typography.css:
--------------------------------------------------------------------------------
1 | #content .iteration a { text-align:center }
2 |
--------------------------------------------------------------------------------
/assets/stylesheets/iteration_active/colours.css:
--------------------------------------------------------------------------------
1 | div.iteration_active #burndown p { background:#fff }
2 | div.iteration_active .draggables .ui-droppable { background:#fff; border-color:#fff }
3 |
4 | div.iteration_active #headings .pending { background:#ddd }
5 | div.iteration_active #headings .pending { border-color:#ddd }
6 | div.iteration_active #headings .in_progress { background:#3dc0fd }
7 | div.iteration_active #headings .in_progress { border-color:#3dc0fd }
8 | div.iteration_active #headings .testing { background:#fde03d }
9 | div.iteration_active #headings .testing { border-color:#fde03d }
10 | div.iteration_active #headings .complete { background:#3dfd4f }
11 | div.iteration_active #headings .complete { border-color:#3dfd4f }
12 |
13 |
--------------------------------------------------------------------------------
/assets/stylesheets/iteration_active/layout.css:
--------------------------------------------------------------------------------
1 | div.iteration_active #burndown { position:fixed; right:30px; top:180px }
2 |
3 | div.iteration_active .javascript #content .story,
4 | div.iteration_active .ui-droppable { height:10em }
5 |
6 | div.iteration_active #headings { overflow:hidden; margin-bottom:9px }
7 | div.iteration_active #headings ol { width:100% }
8 | div.iteration_active #headings li { height:2em; line-height:2em }
9 |
10 | div.iteration_active #headings li,
11 | div.iteration_active .ui-droppable { float:left; border-width:1px;
12 | border-style:solid }
13 |
14 | div.iteration_active #headings li,
15 | div.iteration_active .ui-droppable { width:24.5% }
16 |
17 | div.iteration_active .draggables,
18 | .draggables .story{ overflow:visible }
19 |
20 | div.iteration_active .javascript #stories h2,
21 | div.iteration_active .javascript ol.stories { display:none }
22 |
--------------------------------------------------------------------------------
/assets/stylesheets/iteration_active/typography.css:
--------------------------------------------------------------------------------
1 | div.iteration_active .javascript #stories .guidance p { max-width:none; margin:1em 0px }
2 | div.iteration_active .javascript #stories .guidance,
3 | div.iteration_active .javascript #burndown,
4 | div.iteration_active .javascript #headings ol li { text-align:center }
5 | div.iteration_active h1 { margin-bottom:0 }
6 | div.iteration_active #content .story li { font-size:93%; padding:2px 5px 1px }
7 |
--------------------------------------------------------------------------------
/assets/stylesheets/iteration_planning/colours.css:
--------------------------------------------------------------------------------
1 | div.iteration_planning .include a{ background-repeat:no-repeat }
2 | div.iteration_planning #stories_available .include a { background-image:url(../../images/arrow_large_left_highlighted.png) }
3 | div.iteration_planning #stories_iteration .include a { background-image:url(../../images/arrow_large_right_highlighted.png) }
4 | div.iteration_planning .display .content { background:#fff }
5 | div.iteration_planning .story .estimate { border:none }
6 |
--------------------------------------------------------------------------------
/assets/stylesheets/iteration_planning/layout.css:
--------------------------------------------------------------------------------
1 | div.iteration_planning #stories { clear:both; margin-top:30px;
2 | overflow:hidden; /*ie6*/ height:200px }
3 | div.iteration_planning form p.checkbox { margin:15px 0 }
4 | div.iteration_planning form>#stories,
5 | div.iteration_planning div>#stories { min-height:200px; height:auto }
6 | div.iteration_planning .javascript #stories_iteration_container { float:left }
7 | div.iteration_planning .javascript #stories_available_container { float:right }
8 | div.iteration_planning .javascript #stories_available_container,
9 | div.iteration_planning .javascript #stories_iteration_container { /*ie6*/ width:47% }
10 | div.iteration_planning .javascript div>#stories_available_container,
11 | div.iteration_planning .javascript div>#stories_iteration_container { width:49% }
12 | div.iteration_planning .javascript #stories_iteration,
13 | div.iteration_planning .javascript #stories_available { width:70%; height:auto }
14 | div.iteration_planning .javascript #stories_iteration { /*ie6*/ margin-right:6% }
15 | div.iteration_planning .javascript #stories_available { /*ie6*/ margin-left:1% }
16 | div.iteration_planning .javascript div>#stories_iteration { margin-right:11% }
17 | div.iteration_planning .javascript div>#stories_available { margin-left:11% }
18 |
19 | div.iteration_planning .javascript #stories span.estimate { position:absolute; top:15px; right:0;
20 | width:140px }
21 |
22 | div.iteration_planning .javascript #stories .include input,
23 | div.iteration_planning .javascript #stories .include label { display:none }
24 |
25 | div.iteration_planning .javascript .include a { display:block; width:60px; height:42px }
26 | div.iteration_planning .javascript .include>a { position:absolute; top:0 }
27 | div.iteration_planning .javascript #stories_available .include>a { left:-79px }
28 | div.iteration_planning .javascript #stories_iteration .include>a { right:-79px }
29 |
30 | div.iteration_planning .javascript #stories .estimate { float:right }
31 | div.iteration_planning .javascript #stories .estimate label { display:none }
32 |
33 | div.iteration_planning p.submit { clear:both }
34 |
--------------------------------------------------------------------------------
/assets/stylesheets/iteration_planning/typography.css:
--------------------------------------------------------------------------------
1 | div.iteration_planning .include a { text-indent:-20000px; outline:none;
2 | text-underline:none }
3 | div.iteration_planning .display h4 { font-weight:bold }
4 | div.iteration_planning .javascript #stories span.estimate { text-align:center }
5 |
--------------------------------------------------------------------------------
/assets/stylesheets/landing/colours.css:
--------------------------------------------------------------------------------
1 | #container { background:url(/images/simply_agile_large.png) center top no-repeat }
2 | #header { text-indent:-20000px;
3 | background:#ff7f2a url(/images/a_simple_tool_for_effective_agile_teams.png) center 19px no-repeat }
4 | #footer, #footer a { color:#666 }
5 | #existing_users,
6 | #new_users,
7 | #new_user { background:#e5e5e5 }
8 | .flash { background:#ffbe93 }
9 | #existing_users form,
10 | #new_users p,
11 | form.new_user .container,
12 | .flash p { background:#fff }
13 |
14 | ul li { list-style-type:square }
15 | ol li { list-style-type:decimal }
16 | ul#images li { list-style-type:none }
17 | ul#images li p { color:#444 }
18 | ul#images img { border:1px solid #ccc }
19 |
20 | #main p { color:#444 }
21 |
22 | #user_story_description { }
23 | #why_not_tasks { background:#e5e5e5 url(/images/arrow_from_grey.png) no-repeat }
24 |
--------------------------------------------------------------------------------
/assets/stylesheets/landing/layout.css:
--------------------------------------------------------------------------------
1 | #container { text-align:center; margin:20px 0 0 0; padding-top:148px }
2 | #header { height:60px }
3 | #content { width:950px; margin:27px auto }
4 | #footer { clear:both; padding:30px 0 }
5 | #main,
6 | #new_existing,
7 | body.non_session #content { text-align:left }
8 | #main { float:left; width:100% }
9 | #public_show #main,
10 | .sessions #main,
11 | .users #main{ width:38em }
12 | #sign_up_login { float:right; margin-right:40px }
13 | ul#images,
14 | #new_existing { width:40%; float:right }
15 | ul#images { margin-top:3em }
16 | ul#images li p { margin:0 0 1.5em 0 }
17 | .flash,
18 | #existing_users,
19 | #new_users,
20 | #new_user { padding:10px 15px 15px 15px; margin-bottom:15px }
21 | #new_user form,
22 | #existing_users form,
23 | #new_users p,
24 | form.new_user .container,
25 | .flash p { padding:10px 14px }
26 | label { display:block; margin-top:.5em }
27 |
28 | p.submit { margin-top:1em }
29 |
30 | #privacy_policies_show dt { float:left; clear:left; width:10em }
31 | #privacy_policies_show dd { display:block; margin-left:10em }
32 |
33 | ul#images li { margin:0 }
34 |
35 | .flash { clear:both; margin-top:15px; width:50% }
36 | body.sessions .flash { width:auto }
37 |
38 | .important_message { display:none }
39 |
40 | #user_story_description { float:left; clear:left; width:56% }
41 | #why_not_tasks { clear:right; float:right; width:40%; overflow:hidden; padding:10px 5px 0 30px }
42 |
--------------------------------------------------------------------------------
/assets/stylesheets/landing/typography.css:
--------------------------------------------------------------------------------
1 | h1 { font-size:267%; float:left; margin-bottom:.5em }
2 | h2 { font-size:197% }
3 | #main h2 { margin:2em 0 .5em 0; clear:left }
4 | #main .flash h2 { margin-top:0 }
5 | #footer { font-size:77% }
6 | .errorExplanation h2 { font-size:123.1%; font-weight:bold }
7 |
8 | #content p.back { float:right; margin:0; clear:none; margin-left:3em }
9 | #content p.bottom { clear:both }
10 | #content p.back a { display:block; text-align:right }
11 |
12 | li { margin:0 0 0 3em }
13 | .errorExplanation li { margin-left:1em }
14 |
15 | #main p { clear:left; margin:1em 0 }
16 | #main .flash p { margin:0 }
17 |
18 | #content p,
19 | li { font-size:138.5% }
20 | #main p,
21 | li { line-height:1.5em; max-width:28em }
22 |
23 | p.description { font-size:108%; margin-bottom:1em }
24 | strong { font-weight:bold }
25 | ul#images li p { font-size:85%; text-align:center; font-weight:bold }
26 |
27 | #sign_up_login p { text-align:center; margin-top:.2em }
28 |
29 | p a { white-space:nowrap }
30 |
31 | #why_not_tasks { font-size:75% }
32 | #why_not_tasks h2 { margin-top:0 }
33 |
34 | #have_a_go label { width:10em; float:left; margin-top:0 }
35 |
--------------------------------------------------------------------------------
/assets/stylesheets/story/colours.css:
--------------------------------------------------------------------------------
1 | .draggables .pending .story_header { border-color:#ddd }
2 | .draggables .in_progress .story_header { border-color:#3dc0fd }
3 | .draggables .testing .story_header { border-color:#fde03d }
4 | .draggables .complete .story_header { border-color:#3dfd4f }
5 | .draggables .story { cursor:pointer }
6 |
7 | .story .story_content { border-color:#aaa }
8 | .story,
9 | .story h4 { background:#fff }
10 | .story h4 a, .story h4 { color:#333 }
11 | .story .less_more a { outline:none }
12 |
13 | .story .story_header { border-bottom:2px solid #99f }
14 | .story ol li{ border-bottom:1px solid #ccf }
15 | .story ol li:last-child { border-bottom:none }
16 |
17 | .story .story_content p.estimate { background:#eee; border-color:#ddd }
18 |
19 |
--------------------------------------------------------------------------------
/assets/stylesheets/story/layout.css:
--------------------------------------------------------------------------------
1 | ol.stories{ list-style:none }
2 | body.iteration_planning ol.stories { overflow:visible }
3 | ol.stories li.story{ margin-bottom:15px }
4 |
5 | /* #content .story{ height:100%; max-width:400px; position:relative } */
6 | #content .story{ max-width:400px; position:relative }
7 | #content .story .story_content { border-width:1px; border-style:solid }
8 | #content .story ol, .story ul{ margin:4px 0 0 0 }
9 | #content .story li{ display:block; padding:0 5px; max-width:none }
10 |
11 | #content .story .story_header { position:relative }
12 | #content .story h4 { overflow:hidden }
13 | div.iteration_active .javascript #content .story h3 { margin-right:53px }
14 |
15 | #content .story img { position:absolute; bottom:1px; right:2.4em }
16 | div.iteration_active #content .story img { right:29px }
17 |
18 | .story .story_content * { margin:0; padding:0 }
19 |
20 | /* less/more links */
21 | div#stories_backlog #content .story .less_more,
22 | div#projects_show #backlog .story .less_more { margin-right:2.4em }
23 | #content .story .less_more { float:right; margin-top:6px; margin-right:45px; }
24 | #content .story .less_more a { display:block }
25 | #content .story .less_more a.less { margin-right:.5em; float:left }
26 | #content .story .less_more a.more { float:left }
27 | /* end less/more links */
28 |
29 | #content .story .estimate { margin:0; position:absolute; border-style:solid;
30 | border-width:1px; padding:0 3px; top:3px; right:3px }
31 | #content .story .estimate span { display:none }
32 | .story ol{ clear:both }
33 | .story h4 { border: none }
34 |
35 | div.iteration_active .javascript form.edit_story input,
36 | div.iteration_active .javascript form.edit_story label,
37 | div.iteration_active .javascript li .content,
38 | div.iteration_active .javascript form.edit_story p.submit{ display:none }
39 |
40 | /* page-dependent default states */
41 | #content .story .acceptance_criteria,
42 | div#stories_backlog #content .story ol,
43 | div#stories_show .story .less_more { display:none }
44 | #stories_available_container .story .less_more, #stories_iteration_container .story .less_more { margin-right:100px }
45 | /* end page-dependent default states */
46 |
47 |
48 |
--------------------------------------------------------------------------------
/assets/stylesheets/story/typography.css:
--------------------------------------------------------------------------------
1 | .story ol li { font-size:100%; margin:0 }
2 | .story h3, .story h4{ font-weight:bold }
3 | .story h3{ padding:4px }
4 | .story h4{ padding:6px 0 0 4px !important }
5 | #content .story p.estimate { margin:0; text-align:center;
6 | line-height:1.2em; font-weight:bold; font-size:100% }
7 |
--------------------------------------------------------------------------------
/config/locales/activerecord.yml:
--------------------------------------------------------------------------------
1 | en:
2 | activerecord:
3 | attributes:
4 | story:
5 | content: "Story content"
6 | errors:
7 | messages:
8 | invalid: "is invalid"
9 | not_routable: "does not appear to exist"
10 | taken: "has been taken"
11 | blank: "is blank"
12 | greater_than_or_equal_to: "must be at least {{count}}"
13 | not_a_number: "must be a number"
14 | expired: "has passed"
15 | models:
16 | iteration:
17 | attributes:
18 | stories:
19 | not_estimated: "must have some story points (estimations). You should re-plan this iteration and add story points."
20 | template:
21 | header:
22 | one: "Error"
23 | other: "{{count}} errors"
24 | body: ""
25 |
--------------------------------------------------------------------------------
/config/locales/en.yml:
--------------------------------------------------------------------------------
1 | # English strings go here for Rails i18n
2 | en:
3 | iteration: "Iteration"
4 | iteration_plural: "Iterations"
5 | plan_iteration: "Plan an iteration"
6 | create_iteration: "Create Iteration"
7 | re_plan: "Re-plan"
8 | start_iteration: "Start Iteration"
9 | active: "Active"
10 | planned: "Planned"
11 | finished: "Finished"
12 | active_iterations: "Active Iterations"
13 | planned_iterations: "Planned Iterations"
14 | finished_iterations: "Finished Iterations"
15 | page_only_active_iterations: "This page only shows active iterations."
16 | no_active_iterations: "There are currently no active iterations."
17 | page_only_planned_iterations: "This page only shows planned iterations."
18 | no_planned_iterations: "There are currently no planned iterations."
19 | page_only_finished_iterations: "This page only shows finished iterations."
20 | no_finished_iterations: "There are currently no finished iterations."
21 | no_active_or_planned_iterations: "This project has no active or planned iterations."
22 |
23 | add_to_iteration: "Add to the iteration"
24 | iteration_no_stories: "This iteration does not have any stories."
25 | update_iteration: "Update Iteration"
26 | planning_iteration: "Planning iteration"
27 | planning_iteration_for: "Planning iteration for"
28 | burndown_for: "Burndown chart for"
29 | iteration_days_left: "Days left till iteration end"
30 | iteration_finished_on: "This iteration finished on "
31 | new_iteration_for: "New iteration for"
32 | no_stories_for: "No available stories for"
33 | no_stories_no_iteration: "There are no available stories for this project, so you can't plan an iteration."
34 | you_might_want: "You might want to"
35 | create_story_for_project: "create a story for this project"
36 | iteration_plan_guidance: "Iteration should have a unique name, duration from 1 to 60 days. Story can have upto 100 points."
37 |
38 | new_story: "New story"
39 | new_story_accusative: "new story"
40 | the_rest_stories: "...and the rest"
41 | no_stories: "No Stories"
42 | you_can_start_by_new_story: "You should start by"
43 | creating_new_story: "creating new story"
44 | story: "Story"
45 | story_plural: "Stories"
46 | story_points: "Story Points"
47 | total_story_points: "Total Story Points"
48 | story_team: "Story Team"
49 | create_story: "Create Story"
50 | update_story: "Update Story"
51 | work_on_story: "Work on this story"
52 | feature: "Feature"
53 | story_no_acceptance_criteria: "This story has no acceptance criteria."
54 | backlog_drag_stories: "Drag stories to change priority"
55 | iteration_drag_stories: "Drag stories to set their statuses"
56 |
57 | status_pending: "Pending"
58 | status_in_progress: "In Progress"
59 | status_testing: "Testing"
60 | status_complete: "Complete"
61 | update_status: "Update Status"
62 |
63 | backlog: "Backlog"
64 | new_story_in_backlog: "You don't have a backlog! You might want to write a"
65 | project_has_no_backlog: "This project has no backlog."
66 | full_backlog: "full backlog"
67 | empty_backlog: "Empty Backlog"
68 |
69 | easy_agile_home: "Easy Agile Home"
70 | recent_work: "Recent Work"
71 | recently_finished_iterations: "Recently finished iterations"
72 |
73 | in: "in"
74 | ends_at: "Ends at"
75 | dashboard: "Dashboard"
76 | next_steps: "Next Steps"
77 | estimate: "Estimate"
78 | editing: "Editing"
79 | include: "Include"
80 | remove_me: "Remove Me"
81 | complete: "Complete"
82 | uncomplete: "Uncomplete"
83 | duration_days: "Duration (days)"
84 |
85 | new_criterion: "New Criterion"
86 | acceptance_criteria: "Acceptance Criteria"
87 |
88 | field_duration: "Duration"
89 | field_stories: "Stories"
90 | field_criterion: "Criterion"
--------------------------------------------------------------------------------
/config/locales/it.yml:
--------------------------------------------------------------------------------
1 | # Italiano
2 |
3 | it:
4 | iteration: "Iterazione"
5 | iteration_plural: "Iterazioni"
6 | plan_iteration: "Pianifica una iterazione"
7 | create_iteration: "Crea una iterazione"
8 | re_plan: "Pianifica di nuovo"
9 | start_iteration: "Inizia l'iterazione"
10 | active: "Attiva"
11 | planned: "Pianificata"
12 | finished: "Finita"
13 | active_iterations: "Iterazioni attive"
14 | planned_iterations: "Iterazioni pianificate"
15 | finished_iterations: "Iterazioni finite"
16 | page_only_active_iterations: "Questa pagina mostra solo le iterazioni attive."
17 | no_active_iterations: "Non ci sono al momento iterazioni attive."
18 | page_only_planned_iterations: "Questa pagina mostra solo le iterazioni pianificate."
19 | no_planned_iterations: "Non ci sono al momento iterazioni pianificate."
20 | page_only_finished_iterations: "Quest apagina mostra solo le iterazioni finite."
21 | no_finished_iterations: "Non ci sono al momento iterazioni finite."
22 | no_active_or_planned_iterations: "Il progetto non ha iterazioni attive o pianificate."
23 |
24 | add_to_iteration: "Aggiungi all'iterazione"
25 | iteration_no_stories: "Questa iterazione non ha storie."
26 | update_iteration: "Aggiorna l'iterazione"
27 | planning_iteration: "Pianifica l'iterazione."
28 | planning_iteration_for: "Pianifica l'iterazione per"
29 | burndown_for: "Burndown chart per"
30 | iteration_days_left: "Giorni alla fine dell'iterazione"
31 | iteration_finished_on: "Questa iterazione e' finita il"
32 | new_iteration_for: "Nuova iterazione per"
33 | no_stories_for: "Nessuna storia disponibile per"
34 | no_stories_no_iteration: "Non ci sono storie disponibili in questo progetto, quindi non puoi pianificare un'iterazione."
35 | you_might_want: "Forse vuoi"
36 | create_story_for_project: "creare una storia in questo progetto"
37 | iteration_plan_guidance: "Le iterazioni devono avere un nome univoco, una durata da 1 a 100 giorni. Ogni storia puIteration avere fino a 100 punti."
38 |
39 | new_story: "Nuova storia"
40 | new_story_accusative: "nuova storia"
41 | the_rest_stories: "...e tutto il resto"
42 | no_stories: "Nessuna storia"
43 | you_can_start_by_new_story: "Devi cominciare"
44 | creating_new_story: "creando una nuova storia"
45 | story: "Storia"
46 | story_plural: "Storie"
47 | story_points: "Story Points"
48 | total_story_points: "Story Points totali"
49 | story_team: "Story Team"
50 | create_story: "Crea Storia"
51 | update_story: "Aggiorna storia"
52 | work_on_story: "Lavora su questa storia"
53 | feature: "Feature"
54 | story_no_acceptance_criteria: "Questa storia non ha un criterio d'accettazione."
55 | backlog_drag_stories: "Trascina le storie per cambiarne la priorita'"
56 | iteration_drag_stories: "Trascina le storie per cambiarne lo stato."
57 |
58 | status_pending: "In attesa"
59 | status_in_progress: "In Progress"
60 | status_testing: "In test"
61 | status_complete: "Completata"
62 | update_status: "Aggiorna stato"
63 |
64 | backlog: "Backlog"
65 | new_story_in_backlog: "Non hai un backlog!. Forse vuoi scrivere"
66 | project_has_no_backlog: "Questo progetto non ha backlog."
67 | full_backlog: "tutto il backlog"
68 | empty_backlog: "Cancella Backlog"
69 |
70 | easy_agile_home: "Easy Agile Home"
71 | recent_work: "Lavoro recente"
72 | recently_finished_iterations: "Iterazioni completate di recente"
73 |
74 | in: "in"
75 | ends_at: "Finisce il"
76 | dashboard: "Dashboard"
77 | next_steps: "Prossimi passi"
78 | estimate: "Stima"
79 | editing: "Modifica"
80 | include: "Includi"
81 | remove_me: "Cancellami"
82 | complete: "Completa"
83 | uncomplete: "Non completa"
84 | duration_days: "Durata (giorni)"
85 |
86 | new_criterion: "Nuovo Criterio"
87 | acceptance_criteria: "Criterio d'accettazione"
88 |
89 | field_duration: "Durata"
90 | field_stories: "Storie"
91 | field_criterion: "Criterio"
--------------------------------------------------------------------------------
/config/locales/numbers.yml:
--------------------------------------------------------------------------------
1 | en:
2 | number:
3 | format:
4 | separator: "."
5 | delimiter: ","
6 | precision: 2
7 |
8 | currency:
9 | format:
10 | format: "%u%n"
11 | unit: "£"
12 | precision: 0
13 | date:
14 | abbr_day_names: [Sun, Mon, Tues, Wed, Thurs, Fri, Sat]
15 | day_names: [Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday]
16 | abbr_month_names: [~, Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec]
17 | month_names: [~, January, February, March, April, May, June, July, August, September, October, November, December]
18 | formats:
19 | default: "%A %d %B %Y"
20 | month: "%B %Y"
21 |
--------------------------------------------------------------------------------
/config/locales/pt-BR.yml:
--------------------------------------------------------------------------------
1 | # English strings go here for Rails i18n
2 | pt-BR:
3 | iteration: "Iteração"
4 | iteration_plural: "Iterações"
5 | plan_iteration: "Planejar uma iteração"
6 | create_iteration: "Criar Iteração"
7 | re_plan: "Re-planejar"
8 | start_iteration: "Iniciar Iteração"
9 | active: "Ativo"
10 | planned: "Planejado"
11 | finished: "Terminado"
12 | active_iterations: "Iterações Ativas"
13 | planned_iterations: "Iterações Planejadas"
14 | finished_iterations: "Iterações Terminadas"
15 | page_only_active_iterations: "Essa página só mostra iterações ativas."
16 | no_active_iterations: "Atualmente não existem iterações ativas."
17 | page_only_planned_iterations: "Essa página só mostra iterações planejadas."
18 | no_planned_iterations: "Atualmente não existem iterações planejadas."
19 | page_only_finished_iterations: "Essa página só mostra iterações terminadas."
20 | no_finished_iterations: "Atualmente não existem iterações terminadas."
21 | no_active_or_planned_iterations: "Esse projeto não tem iterações ativas ou planejadas."
22 |
23 | add_to_iteration: "Adicionar à iteração"
24 | iteration_no_stories: "Esta iteração não tem nenhuma estória."
25 | update_iteration: "Atualizar Iteração"
26 | planning_iteration: "Planejamento de Iteração"
27 | planning_iteration_for: "Planejamento de Iteração para"
28 | burndown_for: "Gráfico Burndown para"
29 | iteration_days_left: "Dias que restam até o fim da iteração"
30 | iteration_finished_on: "Esta iteração termina em "
31 | new_iteration_for: "Nova iteração para"
32 | no_stories_for: "Sem estórias para"
33 | no_stories_no_iteration: "Atualmente não existem estórias para esse projeto, então você não pode planejar uma iteração."
34 | you_might_want: "Você pode querer"
35 | create_story_for_project: "criar uma estória para esse projeto"
36 | iteration_plan_guidance: "A Iteração deve ter um nome único, duração de 1 até 60 dias. A Estória pode ter mais de 100 pontos."
37 |
38 | new_story: "Nova estória"
39 | new_story_accusative: "nova estória"
40 | the_rest_stories: "...e o resto"
41 | no_stories: "Sem estórias"
42 | you_can_start_by_new_story: "Você deve começar por"
43 | creating_new_story: "criando uma nova estória"
44 | story: "Estória"
45 | story_plural: "Estórias"
46 | story_points: "Pontos da Estória"
47 | total_story_points: "Total de Pontos da Estória"
48 | story_team: "Time da Estória"
49 | create_story: "Criar Estória"
50 | update_story: "Atualizar Estória"
51 | work_on_story: "Trabalhar nessa estória"
52 | feature: "Feature"
53 | story_no_acceptance_criteria: "Esta história não tem critérios de aceitação."
54 | backlog_drag_stories: "Arraste as estórias para alterar a prioridade"
55 | iteration_drag_stories: "Arraste as estórias para definir seu status"
56 |
57 | status_pending: "Pendente"
58 | status_in_progress: "Em Andamento"
59 | status_testing: "Testando"
60 | status_complete: "Completo"
61 | update_status: "Status da Atualização"
62 |
63 | backlog: "Backlog"
64 | new_story_in_backlog: "Você não tem um backlog! Você pode querer escrever um"
65 | project_has_no_backlog: "Este projeto não tem backlog."
66 | full_backlog: "backlog cheio"
67 | empty_backlog: "Backlog Vazio"
68 |
69 | easy_agile_home: "Easy Agile Início"
70 | recent_work: "Trabalhos Recentes"
71 | recently_finished_iterations: "Iterações terminadas recentemente"
72 |
73 | in: "em"
74 | ends_at: "Termina em"
75 | dashboard: "Painel de Controle"
76 | next_steps: "Próximos Passos"
77 | estimate: "Estimar"
78 | editing: "Edição"
79 | include: "Incluir"
80 | remove_me: "Remova-me"
81 | complete: "Completo"
82 | uncomplete: "Incompleto"
83 | duration_days: "Duração (dias)"
84 |
85 | new_criterion: "Novo Critério"
86 | acceptance_criteria: "Critério de Aceitação"
87 |
88 | field_duration: "Duração"
89 | field_stories: "Estórias"
90 | field_criterion: "Critério"
91 |
--------------------------------------------------------------------------------
/config/locales/ru.yml:
--------------------------------------------------------------------------------
1 | # Russian strings go here for Rails i18n Translated by @Vorona (admin@vorona.no-ip.org) This is very beta version :)
2 | ru:
3 | iteration: "Итерация"
4 | iteration_plural: "Итерации"
5 | plan_iteration: "План итерации"
6 | create_iteration: "Создать итерацию"
7 | re_plan: "Re-plan"
8 | start_iteration: "Начать итерацию"
9 | active: "Активные"
10 | planned: "Запланированные"
11 | finished: "Законченные"
12 | active_iterations: "Активные итерации"
13 | planned_iterations: "Запланированные итерации"
14 | finished_iterations: "Завершенные итерации"
15 | page_only_active_iterations: "Здесь показаны только активные итерации."
16 | no_active_iterations: "Нет активных итераций."
17 | page_only_planned_iterations: "Здесь показаны только запланированные итерации."
18 | no_planned_iterations: "Нет запланированных итераций."
19 | page_only_finished_iterations: "Здесь показаны только завершенные итерации."
20 | no_finished_iterations: "Нет завершенных итераций."
21 | no_active_or_planned_iterations: "В этом проекте нет активных или запланированных итераций."
22 |
23 | add_to_iteration: "добавить в итерацию"
24 | iteration_no_stories: "В этой игерации нет историй."
25 | update_iteration: "Обновить итерацию"
26 | planning_iteration: "Планирование итерации"
27 | planning_iteration_for: "Планирование итерации для"
28 | burndown_for: "Burndown-диаграмма для"
29 | iteration_days_left: "Дней осталось до конца итерации"
30 | iteration_finished_on: "Эта итерация завершится "
31 | new_iteration_for: "Новая итерация для"
32 | no_stories_for: "Нет доступных историй для"
33 | no_stories_no_iteration: "Нет доступных историй для этого проекта, Вы не можете спланировать итерацию."
34 | you_might_want: "Возможно вы хотели "
35 | create_story_for_project: "создать историю для этого проекта"
36 | iteration_plan_guidance: "Итерация должна иметь уникальное имя, длительность от 1 до 60 дней. Истории могут быть до 100 points."
37 |
38 | new_story: "Новая история"
39 | new_story_accusative: "новую историю"
40 | the_rest_stories: "...and the rest"
41 | no_stories: "Нет Историй"
42 | you_can_start_by_new_story: "Начните с "
43 | creating_new_story: "создания новой истории"
44 | story: "История"
45 | story_plural: "Истории"
46 | story_points: "Точки истории"
47 | total_story_points: "Всего точек историй"
48 | story_team: "Цепочка истории"
49 | create_story: "Создать Историю"
50 | update_story: "Обновить Историю"
51 | work_on_story: "Работать с этой историей"
52 | feature: "Фича"
53 | story_no_acceptance_criteria: "Эта история не имеет критерий одобрения."
54 | backlog_drag_stories: "Переместите истории, чтобы изменить приоритет."
55 | iteration_drag_stories: "Переместите истории, чтобы установить их статусы"
56 |
57 | status_pending: "Ожидание"
58 | status_in_progress: "В процессе"
59 | status_testing: "Тестирование"
60 | status_complete: "Готово"
61 | update_status: "Обновить статус"
62 |
63 | backlog: "Backlog"
64 | new_story_in_backlog: "У вас нет backlog-а! Возможно вы хотели бы написать"
65 | project_has_no_backlog: "У этого проекта нет backlog-а."
66 | full_backlog: "Полный backlog"
67 | empty_backlog: "Пустой Backlog"
68 |
69 | easy_agile_home: "Agile домашняя"
70 | recent_work: "Недавняя работа"
71 | recently_finished_iterations: "Недавно оконченные итерации"
72 |
73 | in: "в"
74 | ends_at: "Завершается"
75 | dashboard: "Панель задач"
76 | next_steps: "Следующие Шаги"
77 | estimate: "Оценка"
78 | editing: "Редавтирование"
79 | include: "Включить"
80 | remove_me: "Переместить меня"
81 | complete: "Завершить"
82 | uncomplete: "Неоконченная"
83 | duration_days: "Длительность (дней)"
84 |
85 | new_criterion: "Новый критерий"
86 | acceptance_criteria: "Критерий приемки"
87 |
88 | field_duration: "Длительность"
89 | field_stories: "Истории"
90 | field_criterion: "Критерий"
--------------------------------------------------------------------------------
/config/routes.rb:
--------------------------------------------------------------------------------
1 | ActionController::Routing::Routes.draw do |map|
2 | map.with_options :name_prefix => 'project_', :path_prefix => 'projects/:project_id' do |project|
3 | project.resource :easy_agile, :controller => 'easy_agile', :member => { :my_page => :get }
4 |
5 | project.resources :iterations, :collection => { :finished => :get, :planned => :get } do |iteration|
6 | iteration.resource :burndown
7 | iteration.resource :active_iteration
8 | iteration.resources :stories
9 | end
10 |
11 | project.resources :stories, :member => { :estimate => :get },
12 | :collection => { :backlog => :get, :finished => :get } do |story|
13 | story.resources :acceptance_criteria
14 | end
15 |
16 | project.resources :story_team_members
17 | end
18 | end
19 |
--------------------------------------------------------------------------------
/db/migrate/20090303213012_create_iterations.rb:
--------------------------------------------------------------------------------
1 | class CreateIterations < ActiveRecord::Migration
2 | def self.up
3 | create_table :iterations do |t|
4 | t.integer :project_id
5 | t.string :name
6 | t.integer :duration
7 | t.integer :initial_estimate
8 | t.date :start_date
9 | t.date :end_date
10 |
11 | t.timestamps
12 | end
13 | end
14 |
15 | def self.down
16 | drop_table :iterations
17 | end
18 | end
19 |
--------------------------------------------------------------------------------
/db/migrate/20090304004418_create_stories.rb:
--------------------------------------------------------------------------------
1 | class CreateStories < ActiveRecord::Migration
2 | def self.up
3 | create_table :stories do |t|
4 | t.integer :project_id
5 | t.integer :iteration_id
6 | t.string :name
7 | t.text :content
8 | t.integer :estimate
9 | t.string :status, :default => 'pending'
10 | t.integer :priority, :default => 1
11 |
12 | t.timestamps
13 | end
14 | end
15 |
16 | def self.down
17 | drop_table :stories
18 | end
19 | end
20 |
--------------------------------------------------------------------------------
/db/migrate/20090304193819_create_acceptance_criteria.rb:
--------------------------------------------------------------------------------
1 | class CreateAcceptanceCriteria < ActiveRecord::Migration
2 | def self.up
3 | create_table :acceptance_criteria do |t|
4 | t.integer :story_id
5 | t.string :criterion
6 | t.datetime :fulfilled_at
7 |
8 | t.timestamps
9 | end
10 | end
11 |
12 | def self.down
13 | drop_table :acceptance_criteria
14 | end
15 | end
16 |
--------------------------------------------------------------------------------
/db/migrate/20090310175005_create_burndown_data_points.rb:
--------------------------------------------------------------------------------
1 | class CreateBurndownDataPoints < ActiveRecord::Migration
2 | def self.up
3 | create_table :burndown_data_points do |t|
4 | t.integer :iteration_id
5 | t.integer :story_points
6 | t.date :date
7 | end
8 | end
9 |
10 | def self.down
11 | drop_table :burndown_data_points
12 | end
13 | end
14 |
--------------------------------------------------------------------------------
/db/migrate/20090325133236_create_story_team_members.rb:
--------------------------------------------------------------------------------
1 | class CreateStoryTeamMembers < ActiveRecord::Migration
2 | def self.up
3 | create_table :story_team_members do |t|
4 | t.integer :user_id
5 | t.integer :story_id
6 |
7 | t.timestamps
8 | end
9 | end
10 |
11 | def self.down
12 | drop_table :story_team_members
13 | end
14 | end
15 |
--------------------------------------------------------------------------------
/db/migrate/20090327110522_create_story_actions.rb:
--------------------------------------------------------------------------------
1 | class CreateStoryActions < ActiveRecord::Migration
2 | def self.up
3 | create_table :story_actions do |t|
4 | t.integer :user_id
5 | t.integer :story_id
6 | t.integer :iteration_id
7 |
8 | t.timestamps
9 | end
10 | end
11 |
12 | def self.down
13 | drop_table :story_actions
14 | end
15 | end
16 |
--------------------------------------------------------------------------------
/init.rb:
--------------------------------------------------------------------------------
1 | require 'redmine'
2 | require 'dispatcher'
3 | require 'project_patch'
4 | require 'user_patch'
5 |
6 | Redmine::Plugin.register :easy_agile do
7 | name 'Redmine Easy Agile plugin'
8 | author 'Sphere Consulting Inc.'
9 | description 'Simple scrum board for agile teams'
10 | version '1.0.3'
11 | url 'http://github.com/SphereConsultingInc/easy_agile'
12 | author_url 'http://sphereinc.com'
13 |
14 | project_module :easy_agile do
15 | permission :easy_agile_manage_iterations, :iterations => [:index, :new, :create, :show, :edit, :update, :planned, :finished]
16 | permission :easy_agile_view_home, :easy_agile => [:show]
17 | permission :easy_agile_manage_stories, :stories => [:index, :new, :create, :show, :edit, :update, :backlog]
18 | permission :easy_agile_manage_acceptance_criteria, :acceptance_criteria => [:create, :edit, :update, :destroy]
19 | permission :easy_agile_manage_story_team_members, :story_team_members => [:create, :destroy]
20 | end
21 |
22 | Dispatcher.to_prepare do
23 | Project.send(:include, ProjectPatch) unless Project.included_modules.include? ProjectPatch
24 | User.send(:include, UserPatch) unless User.included_modules.include? UserPatch
25 | MyController.send(:include, MyControllerPatch) unless MyController.included_modules.include? MyControllerPatch
26 | end
27 |
28 | # observer
29 | ActiveRecord::Base.observers << :acceptance_criterion_observer << :story_action_observer
30 |
31 | menu :project_menu, :easy_agile, { :controller => 'easy_agile', :action => 'show' }, :caption => 'Easy Agile', :before => :calendar, :param => :project_id
32 |
33 | # feature
34 | Mime::Type.register "text/plain", :feature
35 |
36 | # cretiria inflections
37 | ActiveSupport::Inflector.inflections do |inflect|
38 | inflect.irregular 'criterion', 'criteria'
39 | end
40 |
41 | end
42 |
--------------------------------------------------------------------------------
/lib/my_controller_patch.rb:
--------------------------------------------------------------------------------
1 | require_dependency 'my_controller'
2 |
3 | module MyControllerPatch
4 | def self.included(base)
5 | base.extend(ClassMethods)
6 | base.send(:include, InstanceMethods)
7 |
8 | base.class_eval do
9 | helper :stories
10 | end
11 | end
12 |
13 | module ClassMethods
14 | end
15 |
16 | module InstanceMethods
17 | end
18 | end
19 |
20 | MyController.send(:include, MyControllerPatch)
21 |
22 |
--------------------------------------------------------------------------------
/lib/project_patch.rb:
--------------------------------------------------------------------------------
1 | require_dependency 'project'
2 |
3 | module ProjectPatch
4 | def self.included(base)
5 | base.send(:include, InstanceMethods)
6 |
7 | base.class_eval do
8 | has_many :iterations, :dependent => :destroy
9 | has_many :stories, :dependent => :destroy
10 | has_many(:available_stories,
11 | :class_name => 'Story',
12 | :conditions => 'iteration_id IS NULL')
13 | end
14 | end
15 |
16 | module InstanceMethods
17 |
18 | def priorities=(priorities)
19 | priorities.each_pair do |id, priority|
20 | stories.update(id, :priority => priority)
21 | end
22 | end
23 |
24 | end
25 | end
26 |
27 | Project.send(:include, ProjectPatch)
28 |
--------------------------------------------------------------------------------
/lib/user_patch.rb:
--------------------------------------------------------------------------------
1 | require_dependency 'user'
2 |
3 | module UserPatch
4 | def self.included(base)
5 | base.extend(ClassMethods)
6 | base.send(:include, InstanceMethods)
7 |
8 | base.class_eval do
9 | has_many :story_team_members
10 | has_many :stories, :through => :story_team_members
11 | has_many :story_actions
12 | has_many :stories_worked_on, :through => :story_actions, :source => 'story'
13 | has_many :iterations_worked_on, :through => :story_actions, :source => 'iteration'
14 | end
15 | end
16 |
17 | module ClassMethods
18 | end
19 |
20 | module InstanceMethods
21 | def active_iterations_worked_on
22 | iterations_worked_on.active.select do |iteration|
23 | self.projects.include?(iteration.project)
24 | end.uniq
25 | end
26 |
27 | def active_stories_worked_on
28 | active_iterations = active_iterations_worked_on
29 | stories_worked_on.delete_if do |story|
30 | ! active_iterations.include?(story.iteration)
31 | end
32 | end
33 |
34 | def recently_finished_iterations_worked_on
35 | iterations_worked_on.recently_finished.select do |iteration|
36 | self.projects.include?(iteration.project)
37 | end.uniq
38 | end
39 |
40 | def active_iterations
41 | Iteration.active.find_all_by_project_id(self.projects)
42 | end
43 | end
44 | end
45 |
46 | User.send(:include, UserPatch)
47 |
48 |
--------------------------------------------------------------------------------