From dbeaf3973d258ce819465772a02210d4b8b3328f Mon Sep 17 00:00:00 2001 From: Trevor Vallender Date: Thu, 16 Nov 2023 20:23:09 +0000 Subject: [PATCH] Initial commit --- README.rdoc | 6 +++ app/controllers/jobs_controller.rb | 64 ++++++++++++++++++++++++ app/helpers/jobs_helper.rb | 2 + app/models/job.rb | 10 ++++ app/views/jobs/_form.html.erb | 40 +++++++++++++++ app/views/jobs/_job.html.erb | 9 ++++ app/views/jobs/edit.html.erb | 6 +++ app/views/jobs/index.html.erb | 26 ++++++++++ app/views/jobs/new.html.erb | 3 ++ app/views/jobs/show.html.erb | 11 ++++ config/locales/en.yml | 3 ++ config/routes.rb | 1 + db/migrate/20231116202759_create_jobs.rb | 14 ++++++ init.rb | 11 ++++ test/functional/jobs_controller_test.rb | 8 +++ test/test_helper.rb | 2 + test/unit/job_test.rb | 9 ++++ todo.md | 33 ++++++++++++ 18 files changed, 258 insertions(+) create mode 100644 README.rdoc create mode 100644 app/controllers/jobs_controller.rb create mode 100644 app/helpers/jobs_helper.rb create mode 100644 app/models/job.rb create mode 100644 app/views/jobs/_form.html.erb create mode 100644 app/views/jobs/_job.html.erb create mode 100644 app/views/jobs/edit.html.erb create mode 100644 app/views/jobs/index.html.erb create mode 100644 app/views/jobs/new.html.erb create mode 100644 app/views/jobs/show.html.erb create mode 100644 config/locales/en.yml create mode 100644 config/routes.rb create mode 100644 db/migrate/20231116202759_create_jobs.rb create mode 100644 init.rb create mode 100644 test/functional/jobs_controller_test.rb create mode 100644 test/test_helper.rb create mode 100644 test/unit/job_test.rb create mode 100644 todo.md diff --git a/README.rdoc b/README.rdoc new file mode 100644 index 0000000..b7a6f59 --- /dev/null +++ b/README.rdoc @@ -0,0 +1,6 @@ += Jobs + +_Jobs_ is a Redmine plugin allowing the management of jobs—chunks of time sold to clients for budget management. + +- Add jobs with time budgets +- Associated time log entries with a given job diff --git a/app/controllers/jobs_controller.rb b/app/controllers/jobs_controller.rb new file mode 100644 index 0000000..bf56092 --- /dev/null +++ b/app/controllers/jobs_controller.rb @@ -0,0 +1,64 @@ +class JobsController < ApplicationController + before_action :set_project, only: [:index, :new, :show, :edit] + before_action :set_job, only: [:show, :edit, :update, :destroy] + + def index + @jobs = Job.all + end + + def show + end + + def new + @job = Job.new + end + + def edit + end + + def update + if @job.update(job_params) + redirect_to @job + else + render :edit + end + end + + def create + if @job = Job.create(job_params) + redirect_to @job + else + render :edit + end + end + + def destroy + if @job.destroy + redirect_to jobs_path(project_id: @project.id) + else + render :show + end + end + + private + + def job_params + params.require(:job).permit( + :starts_on, + :ends_on, + :project_id, + :budget, + :external_project_id, + :name, + :description + ) + end + + def set_project + @project = Project.find(params[:project_id]) + end + + def set_job + @job = Job.find(params[:id]) + end +end diff --git a/app/helpers/jobs_helper.rb b/app/helpers/jobs_helper.rb new file mode 100644 index 0000000..44c7bf6 --- /dev/null +++ b/app/helpers/jobs_helper.rb @@ -0,0 +1,2 @@ +module JobsHelper +end diff --git a/app/models/job.rb b/app/models/job.rb new file mode 100644 index 0000000..746c1d3 --- /dev/null +++ b/app/models/job.rb @@ -0,0 +1,10 @@ +class Job < ActiveRecord::Base + validates :starts_on, + :ends_on, + :name, + presence: true + + def time_logged + 42 + end +end diff --git a/app/views/jobs/_form.html.erb b/app/views/jobs/_form.html.erb new file mode 100644 index 0000000..d570ef8 --- /dev/null +++ b/app/views/jobs/_form.html.erb @@ -0,0 +1,40 @@ +
+ <%= form_with model: @job, id: "job_form" do |f| %> +

+ <%= f.label :name %> + <%= f.text_field :name %> +

+ +

+ <%= f.label :description %> + <%= f.text_area :description %> +

+ +

+ <%= f.label :starts_on %> + <%= f.date_field :starts_on %> +

+ +

+ <%= f.label :ends_on %> + <%= f.date_field :ends_on %> +

+ +

+ <%= f.label :project_id %> + <%= f.number_field :project_id %> +

+ +

+ <%= f.label :external_project_id %> + <%= f.number_field :external_project_id %> +

+ +

+ <%= f.label :budget %> + <%= f.number_field :budget %> +

+ + <%= f.submit %> + <% end %> +
diff --git a/app/views/jobs/_job.html.erb b/app/views/jobs/_job.html.erb new file mode 100644 index 0000000..d29dee7 --- /dev/null +++ b/app/views/jobs/_job.html.erb @@ -0,0 +1,9 @@ + + <%= link_to job.name, job_path(job, project_id: job.project_id) %> + <%= job.starts_on %> + <%= job.ends_on %> + <%= job.project_id %> + <%= job.external_project_id %> + <%= job.budget %> + + diff --git a/app/views/jobs/edit.html.erb b/app/views/jobs/edit.html.erb new file mode 100644 index 0000000..4216fd3 --- /dev/null +++ b/app/views/jobs/edit.html.erb @@ -0,0 +1,6 @@ +<% html_title "Edit #{@job.name}" %> +

Edit <%= @job.name %>

+ +<%= render "form" %> + +<%= link_to "Delete job", job_path(@job), data: { confirm: "Are you sure?" }, method: :delete %> diff --git a/app/views/jobs/index.html.erb b/app/views/jobs/index.html.erb new file mode 100644 index 0000000..56879f4 --- /dev/null +++ b/app/views/jobs/index.html.erb @@ -0,0 +1,26 @@ +<% html_title "Jobs" %> +
+ <%= link_to 'Create new job', new_job_path(project_id: @project.id), class: "icon icon-add new-job" %> +
+ +

Jobs

+ +<% if @jobs.empty? %> +

You haven’t created any jobs yet.

+<% else %> + + + + + + + + + + + + + <%= render @jobs %> + +
NameStarts onEnds onProjectExternal projectBudget
+<% end %> diff --git a/app/views/jobs/new.html.erb b/app/views/jobs/new.html.erb new file mode 100644 index 0000000..bc1edae --- /dev/null +++ b/app/views/jobs/new.html.erb @@ -0,0 +1,3 @@ +

<%= link_to "Jobs", jobs_path(project_id: @project.id) %> » New

+ +<%= render "form" %> diff --git a/app/views/jobs/show.html.erb b/app/views/jobs/show.html.erb new file mode 100644 index 0000000..407e651 --- /dev/null +++ b/app/views/jobs/show.html.erb @@ -0,0 +1,11 @@ +<% html_title @job.name %> +

<%= link_to @job.name, @job %>

+

<%= @job.description %>

+
+
Starts on:
+
<%= @job.starts_on %>
+
Ends on:
+
<%= @job.ends_on %>
+
+ +<%= link_to 'Edit job', edit_job_path(@job, project_id: @project.id) %> diff --git a/config/locales/en.yml b/config/locales/en.yml new file mode 100644 index 0000000..642b07f --- /dev/null +++ b/config/locales/en.yml @@ -0,0 +1,3 @@ +# English strings go here for Rails i18n +en: + # my_label: "My label" diff --git a/config/routes.rb b/config/routes.rb new file mode 100644 index 0000000..2da398c --- /dev/null +++ b/config/routes.rb @@ -0,0 +1 @@ +resources :jobs diff --git a/db/migrate/20231116202759_create_jobs.rb b/db/migrate/20231116202759_create_jobs.rb new file mode 100644 index 0000000..f076ec5 --- /dev/null +++ b/db/migrate/20231116202759_create_jobs.rb @@ -0,0 +1,14 @@ +class CreateJobs < ActiveRecord::Migration[6.1] + def change + create_table :jobs do |t| + t.date :starts_on, null: false + t.date :ends_on, null: false + t.integer :external_project_id + t.string :name, null: false + t.references :project, foreign_key: true + t.string :description + t.integer :budget + end + add_index :jobs, :name, unique: true + end +end diff --git a/init.rb b/init.rb new file mode 100644 index 0000000..b96a81a --- /dev/null +++ b/init.rb @@ -0,0 +1,11 @@ +Redmine::Plugin.register :jobs do + name 'Redmine Jobs plugin' + author 'T S Vallender' + description 'Manage jobs in Redmine' + version '0.0.1' + url 'http://tsvallender.co.uk' + author_url 'http://tsvallender.co.uk' + + permission :jobs, { jobs: [:index, :show, :new, :create, :edit, :update, :destroy] }, public: true + menu :project_menu, :jobs, { controller: 'jobs', action: 'index' }, caption: 'Jobs', after: :issues, param: :project_id +end diff --git a/test/functional/jobs_controller_test.rb b/test/functional/jobs_controller_test.rb new file mode 100644 index 0000000..1cf8101 --- /dev/null +++ b/test/functional/jobs_controller_test.rb @@ -0,0 +1,8 @@ +require_relative '../test_helper' + +class JobsControllerTest < ActionController::TestCase + # Replace this with your real tests. + def test_truth + assert true + end +end diff --git a/test/test_helper.rb b/test/test_helper.rb new file mode 100644 index 0000000..55b016f --- /dev/null +++ b/test/test_helper.rb @@ -0,0 +1,2 @@ +# Load the Redmine helper +require_relative '../../../test/test_helper' diff --git a/test/unit/job_test.rb b/test/unit/job_test.rb new file mode 100644 index 0000000..28c2e91 --- /dev/null +++ b/test/unit/job_test.rb @@ -0,0 +1,9 @@ +require_relative '../test_helper' + +class JobTest < ActiveSupport::TestCase + + # Replace this with your real tests. + def test_truth + assert true + end +end diff --git a/todo.md b/todo.md new file mode 100644 index 0000000..c1671a8 --- /dev/null +++ b/todo.md @@ -0,0 +1,33 @@ +- Add a job model + - Start/end date + - External project ID (one-to-one relationship) + - Name + - Client (project ID) + - Description + - Job ID? (this is in Amigo) + - Status (pending acceptance etc.) + - Total time (budget per activity type?) + - List of associated trackers +- Add association between time log entries and jobs +- Add UI for jobs + - CRUD stuff + - Set up default associations + +- Separate plugin: + - Whenever time log is updated, fire this at Everhour + - Back the other way? + +- What about meetings etc? + +- Examples: + - Developer logs time for ticket #123 + - Doesn't explicitly choose a job + - Logged as development time + - If ticket is in retainer tracker the time is logged against the retainer job + - If ticket is in support tracker the time is logged against the support job + - If ticket is anywhere else, it is logged against the active project + + - Product manager logs time for ticket #123 + - Doesn't explicitly choose a job + - Logged as refinement time + -