diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js index 69f8036..e040f17 100644 --- a/app/assets/javascripts/application.js +++ b/app/assets/javascripts/application.js @@ -1,67 +1,68 @@ // This is a manifest file that'll be compiled into application.js, which will include all the files // listed below. // // Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts, // or vendor/assets/javascripts of plugins, if any, can be referenced here using a relative path. // // It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the // compiled file. // // Read Sprockets README (https://github.com/sstephenson/sprockets#sprockets-directives) for details // about supported directives. // //= require jquery.min //= require jquery_ujs //= require bootstrap.min //= require_tree . //= require highcharts +//= require jobs $(document).ready(function() { $(".include_files-plus-sign").click(function() { addIncludedFileTextArea(); }); $(".exclude_directions-plus-sign").click(function() { addExcludeDirectionsTextArea(); }); $(".schedule_run_form_plus").click(function() { addScheduleRun(); }); $(".schedule_run_form_remove").click(function() { removeScheduleRun(); }); }); function addIncludedFileTextArea() { var textArrea = $('.include_files:last').clone(true).val(""); $('.include_files-plus-sign:first').parent().remove(); textArrea.insertAfter('.include_files:last'); $('.include_files:last input').val(""); } function addExcludeDirectionsTextArea() { var textArrea = $('.exclude_directions:last').clone(true).val(""); $('.exclude_directions-plus-sign:first').parent().remove(); textArrea.insertAfter('.exclude_directions:last'); $('.exclude_directions:last input').val(""); } function addScheduleRun() { var scheduleRun = $('.schedule_run_form:last').clone(); scheduleRun.insertAfter('.schedule_run_form:last'); $('.schedule_run_form:last input').val(''); if ($('.schedule_run_form').size() > 1) { $(".schedule_run_form_remove").show(); }; } function removeScheduleRun() { if ($('.schedule_run_form').size() > 1) { $('.schedule_run_form:last').remove(); if ($('.schedule_run_form').size() == 1) { $(".schedule_run_form_remove").hide(); }; } else { alert('nothing to remove'); }; } diff --git a/app/assets/javascripts/jobs.js b/app/assets/javascripts/jobs.js new file mode 100644 index 0000000..40a62e0 --- /dev/null +++ b/app/assets/javascripts/jobs.js @@ -0,0 +1,22 @@ +$(document).ready(function() { + $("#job_template_schedule_id").change(function() { + showSchedule(); + }); + $("#job_template_fileset_id").change(function() { + showFileset(); + }); +}); + +function showSchedule() { + var scheduleId = $("#job_template_schedule_id").val(); + $.ajax({ + url: "/hosts/" + hostId + "/schedules/" + scheduleId + }); +} + +function showFileset() { + var filesetId = $("#job_template_fileset_id").val(); + $.ajax({ + url: "/hosts/" + hostId + "/filesets/" + filesetId + }); +} diff --git a/app/controllers/filesets_controller.rb b/app/controllers/filesets_controller.rb index bcb88c9..8fbac37 100644 --- a/app/controllers/filesets_controller.rb +++ b/app/controllers/filesets_controller.rb @@ -1,46 +1,51 @@ class FilesetsController < ApplicationController before_action :require_logged_in - before_action :fetch_host, only: [:new, :create] + before_action :fetch_host, only: [:new, :create, :show] before_action :fetch_job_id, only: [:new, :create] def new @fileset = @host.filesets.new end def show + @fileset = @host.filesets.find(params[:id]) + + respond_to do |format| + format.js {} + end end def create @fileset = @host.filesets.new(fetch_params) if @fileset.save flash[:success] = 'Fileset created' if @job_id.present? redirect_to edit_host_job_path(@host, @job_id, fileset_id: @fileset.id) else redirect_to new_host_job_path(@host, fileset_id: @fileset.id) end else @fileset.include_files = nil @fileset.exclude_directions = nil render :new end end def destroy end private def fetch_host @host = current_user.hosts.find(params[:host_id]) end def fetch_job_id @job_id = @host.job_templates.find(params[:job_id]).id if params[:job_id].present? end def fetch_params params.require(:fileset).permit(:name, exclude_directions: [], include_files: []) end end diff --git a/app/controllers/jobs_controller.rb b/app/controllers/jobs_controller.rb index 6074d2e..5816f06 100644 --- a/app/controllers/jobs_controller.rb +++ b/app/controllers/jobs_controller.rb @@ -1,77 +1,80 @@ class JobsController < ApplicationController before_action :require_logged_in before_action :fetch_host, only: [:new, :edit, :show, :create, :update, :toggle_enable, :backup_now] before_action :fetch_job, only: [:show, :edit, :update, :destroy, :toggle_enable, :backup_now] # GET /jobs def new @job = @host.job_templates.new end # POST /jobs def create @job = @host.job_templates.new(fetch_params) if @job.save flash[:success] = 'Job created successfully' redirect_to host_path(@host) else render :new end end # GET /jobs/1 def show; end # GET /jobs/1/edit - def edit;end + def edit + @fileset = @host.filesets.find(params[:fileset_id]) if params[:fileset_id] + @schedule = @host.schedules.find(params[:schedule_id]) if params[:schedule_id] + end # PUT /jobs/1 def update if @job.update_attributes(fetch_params) flash[:success] = 'Job updated' redirect_to host_job_path(@host, @job) else render :edit end end # DELETE /jobs/1 def destroy end # PATCH /hosts/1/jobs/1/enable def toggle_enable @job.enabled = !@job.enabled @job.save flash[:success] = @job.enabled? ? 'Job enabled' : 'Job disabled' redirect_to host_path(@host) end # POST /hosts/1/jobs/1/backup_now def backup_now if @job.backup_now flash[:success] = 'Backup directive was sent to bacula. Backup will be taken in a while' else flash[:error] = 'Backup was not sent, try again later' end redirect_to client_path(@host.client) end private def fetch_job @job = @host.job_templates.find(params[:id]) end def fetch_host @host = current_user.hosts.find(params[:host_id]) end def fetch_params params.require(:job_template). permit(:name, :fileset_id, :schedule_id, :client_before_run_file, :client_after_run_file) end end diff --git a/app/controllers/schedules_controller.rb b/app/controllers/schedules_controller.rb index 04403d6..fcfb33f 100644 --- a/app/controllers/schedules_controller.rb +++ b/app/controllers/schedules_controller.rb @@ -1,53 +1,58 @@ class SchedulesController < ApplicationController before_action :require_logged_in - before_action :fetch_host, only: [:new, :create] + before_action :fetch_host, only: [:new, :create, :show] before_action :fetch_job_id, only: [:new, :create] def new @schedule = @host.schedules.new end def show + @schedule = @host.schedules.find(params[:id]) + + respond_to do |format| + format.js {} + end end def edit end def update end def create @schedule = @host.schedules.new(fetch_params) @schedule.runtime = params[:schedule][:runtime] if params[:schedule][:runtime] if @schedule.save flash[:success] = 'Schedule created successfully' if @job_id.present? redirect_to edit_host_job_path(@host, @job_id, schedule_id: @schedule.id) else redirect_to new_host_job_path(@host, schedule_id: @schedule.id) end else render :new end end def destroy end private def fetch_host @host = current_user.hosts.find(params[:host_id]) end def fetch_job_id @job_id = @host.job_templates.find(params[:job_id]).id if params[:job_id].present? end def fetch_params params.require(:schedule). permit(:name, { schedule_runs_attributes: [[:level, :month, :day, :time]] }) end end diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index 1bb6ee0..2049b36 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -1,106 +1,108 @@ module ApplicationHelper # Custom helper for better display of big numbers # @example number_by_magnitude(4242) # "4.2K" # # @param number[Numeric] # @return [String] human friendly respresentation def number_by_magnitude(number) number_to_human(number, units: { thousand: :K, million: :M, billion: :G }) end # Creates a bootstrap form-group div with an additional 'Add' button next to the select field # # @param object[ActiveRecord::Object] the form's subject # @param resource[Symbol] the objects class # @param attr[Symbol] the select box's attribute # @param attr_name[String] the attribute's display name # @param options[Array] the select box options # @param path[String] the add button's path def select_with_errors_and_button(object, resource, attr, attr_name, options, path) has_errors = object.errors[attr].present? content_tag(:div, class: "form-group #{' has-error' if has_errors }") do attr_label = label(resource, attr, attr_name, class: 'control-label col-xs-5 required') select_div = content_tag(:div, class: 'col-xs-5') do select_part = select_tag([resource, attr].join('_').to_sym, options, name: "#{resource}[#{attr}]", class: 'form-control' ) if has_errors select_part.concat(content_tag(:span, class: 'help-block') { object.errors[attr].first }) end select_part end button_part = content_tag(:div, class: 'col-xs-1') do - link_to 'Add', path, class: 'btn btn-primary', role: 'button' + link_to path do + content_tag(:span, class: 'glyphicon glyphicon-plus text-success') {} + end end attr_label.concat(select_div).concat(button_part) end end # Returns a style class depending on the given parameter # # @param status[Char] def success_class(status) case status when 'T' then 'success' when 'E' then 'danger' when 'f' then 'fatal' end end # Fetches the html class for a given path # # @param path[String] the path to check for # @param partial[Boolean] forces a left partial match # # @return [Hash] { class: 'active' } if the given path is the current page def active_class(path, partial = false) if current_page?(path) || (partial && request.path.starts_with?(path)) { class: 'active' } else {} end end # Constructs a breadcrumb out the given options # # @param options[Hash] a hash containing the breadcrumb links in name: path sets # @return an html ol breadcrumb def breadcrumb_with(options) content_tag(:ol, class: 'breadcrumb') do options.map { |name, path| content_tag(:li, active_class(path)) do link_to_if !current_page?(path), name, path end }.inject { |result, element| result.concat(element) } end end # Constructs a list with the given array elements # # @example: # inline_list([:foo, :bar]) # # # # @param arr[Array] # @return an html ul list def inline_list(arr) content_tag(:ul, class: 'list-inline') do arr.map { |element| content_tag(:li) do content_tag(:span, class: 'label label-default') do element end end }.inject { |result, element| result.concat(element) } end end end diff --git a/app/views/filesets/show.js.erb b/app/views/filesets/show.js.erb new file mode 100644 index 0000000..a569f63 --- /dev/null +++ b/app/views/filesets/show.js.erb @@ -0,0 +1 @@ +$('#fileset').html("<%= escape_javascript(render partial: 'jobs/fileset', locals: { fileset: @fileset }) %>"); diff --git a/app/views/jobs/_fileset.html.erb b/app/views/jobs/_fileset.html.erb new file mode 100644 index 0000000..ec4150d --- /dev/null +++ b/app/views/jobs/_fileset.html.erb @@ -0,0 +1,6 @@ +
+

Fileset "<%= fileset.name %>"

+
+
+<%= fileset.to_bacula_config_array.join("\n") %>
+
diff --git a/app/views/jobs/_form.html.erb b/app/views/jobs/_form.html.erb index e6d1e8c..652ea6f 100644 --- a/app/views/jobs/_form.html.erb +++ b/app/views/jobs/_form.html.erb @@ -1,29 +1,33 @@ <%= bootstrap_form_for(@job, url: @job.new_record? ? host_jobs_path : host_job_path(@host, @job), layout: :horizontal, label_col: 'col-xs-5', control_col: 'col-xs-5') do |f| %> <%= f.text_field :name %> <%= select_with_errors_and_button( @job, :job_template, :fileset_id, 'Fileset', - options_from_collection_for_select(@host.filesets, :id, :name, - params[:fileset_id] || @job.fileset_id), + options_from_collection_for_select( + @host.filesets, :id, :name, params[:fileset_id] || @job.fileset_id), new_host_fileset_path(@host, job_id: @job.id)) %> <% if !@job.restore? %> <%= select_with_errors_and_button( - @job, :job_template, :schedule_id, - 'Schedule', options_from_collection_for_select(@host.schedules, :id, :name, - params[:schedule_id] || @job.schedule_id), + @job, :job_template, :schedule_id, 'Schedule', + options_from_collection_for_select( + @host.schedules, :id, :name, params[:schedule_id] || @job.schedule_id), new_host_schedule_path(@host, job_id: @job.id)) %> <% end %> <%= f.text_field :client_before_run_file, label: 'Client Run Before Job' %> <%= f.text_field :client_after_run_file, label: 'Client Run After Job' %>
<%= f.submit class: "btn btn-success" %>
<% end %> + + diff --git a/app/views/jobs/_schedule.html.erb b/app/views/jobs/_schedule.html.erb new file mode 100644 index 0000000..33fd25e --- /dev/null +++ b/app/views/jobs/_schedule.html.erb @@ -0,0 +1,6 @@ +
+

Schedule "<%= schedule.name %>"

+
+
+<%= schedule.to_bacula_config_array.join("\n") %>
+
diff --git a/app/views/jobs/edit.html.erb b/app/views/jobs/edit.html.erb index f40874d..b6113c7 100644 --- a/app/views/jobs/edit.html.erb +++ b/app/views/jobs/edit.html.erb @@ -1,18 +1,36 @@

Edit Job Template <%= @job.name %>

-
-
-

Job Attributes

+
+
+
+

Job Attributes

+
+
<%= render 'form' %>
+ +
+
+
+ <% fileset = @fileset || @job.fileset %> + <%= render partial: 'fileset', locals: { fileset: fileset } if fileset %> +
+
+
+
+ <% schedule = @schedule || @job.schedule %> + <%= render partial: 'schedule', locals: { schedule: schedule } if schedule %> +
+
+

<%= link_to 'Cancel', host_job_path(@host, @job), class: 'btn btn-danger', role: 'button' %>
diff --git a/app/views/schedules/show.js.erb b/app/views/schedules/show.js.erb new file mode 100644 index 0000000..45706d6 --- /dev/null +++ b/app/views/schedules/show.js.erb @@ -0,0 +1 @@ +$('#schedule').html("<%= escape_javascript(render partial: 'jobs/schedule', locals: { schedule: @schedule }) %>");