diff --git a/app/controllers/admin/clients_controller.rb b/app/controllers/admin/clients_controller.rb index 3d9ccfa..5d20566 100644 --- a/app/controllers/admin/clients_controller.rb +++ b/app/controllers/admin/clients_controller.rb @@ -1,51 +1,53 @@ class Admin::ClientsController < Admin::BaseController before_action :fetch_client, only: [:show, :jobs, :logs, :stats] before_action :fetch_logs, only: [:logs] # Shows all available clients # # GET /admin/clients def index @clients = Client.includes(:jobs).all @client_ids = @clients.map(&:id) fetch_jobs_info end # Shows a specific client # # GET /admin/clients/1 def show get_charts end # GET /admin/clients/1/jobs - def jobs; end + def jobs + @jobs = @client.recent_jobs.page(params[:page]) + end # GET /admin/clients/1/logs def logs end # GET /admin/clients/1/stats # POST /admin/clients/1/stats def stats get_charts end private # Fetches the client based on the given id def fetch_client @client = Client.find(params[:id]) @client_ids = [@client.id] end def fetch_jobs_info @stats = JobStats.new end def get_charts days_ago = params.fetch(:days_back, 7).to_i rescue 7 @job_status = ChartGenerator.job_statuses(@client_ids, days_ago) @job_stats = ChartGenerator.job_stats(@client_ids, days_ago - 1) end end diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index dda37b9..39ebcf6 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -1,25 +1,26 @@ class ApplicationController < ActionController::Base # Prevent CSRF attacks by raising an exception. # For APIs, you may want to use :null_session instead. protect_from_forgery with: :exception helper_method :current_user protected def current_user @current_user ||= User.last end def fetch_logs days_ago = params.fetch(:days_back, 7).to_i rescue 7 if @client @logs = Log.includes(:job).joins(job: :client).where(Client: { ClientId: @client.id }) else @logs = Log.includes(:job).joins(job: { client: { host: :users } }). where(users: { id: current_user.id }) end - @logs = @logs.where('Time > ?', days_ago.days.ago).order(Time: :desc)#.limit(10) + @logs = @logs.where('Time > ?', days_ago.days.ago). + order(Time: :desc, LogId: :desc).page(params[:page]) end end diff --git a/app/controllers/clients_controller.rb b/app/controllers/clients_controller.rb index e18d752..273c25d 100644 --- a/app/controllers/clients_controller.rb +++ b/app/controllers/clients_controller.rb @@ -1,47 +1,49 @@ class ClientsController < ApplicationController before_action :set_client, only: [:show, :jobs, :logs, :stats] before_action :fetch_logs, only: [:logs] # GET /clients # POST /clients def index @client_ids = Client.for_user(current_user.id).pluck(:ClientId) @clients = Client.where(ClientId: @client_ids).includes(:jobs) @hosts = current_user.hosts.not_baculized fetch_jobs_info get_charts end # GET /clients/1 def show end # GET /clients/1/jobs - def jobs; end + def jobs + @jobs = @client.recent_jobs.page(params[:page]) + end # GET /clients/1/logs def logs; end # GET /clients/1/stats # POST /clients/1/stats def stats get_charts end private def set_client @client = Client.for_user(current_user.id).find(params[:id]) @client_ids = [@client.id] end def fetch_jobs_info @stats = JobStats.new(@client_ids) end def get_charts days_ago = params.fetch(:days_back, 7).to_i rescue 7 @job_status = ChartGenerator.job_statuses(@client_ids, days_ago) @job_stats = ChartGenerator.job_stats(@client_ids, days_ago - 1) end end diff --git a/app/models/client.rb b/app/models/client.rb index eb68a58..bb6de09 100644 --- a/app/models/client.rb +++ b/app/models/client.rb @@ -1,91 +1,90 @@ class Client < ActiveRecord::Base self.table_name = :Client self.primary_key = :ClientId alias_attribute :name, :Name alias_attribute :uname, :Uname alias_attribute :auto_prune, :AutoPrune alias_attribute :file_retention, :FileRetention alias_attribute :job_retention, :JobRetention has_many :jobs, foreign_key: :ClientId has_one :host, foreign_key: :name, primary_key: :Name scope :for_user, ->(user_id) { joins(host: :users).where(users: { id: user_id }) } DAY_SECS = 60 * 60 * 24 - RECENT_JOBS_COUNT = 5 # Fetches the client's job_templates that are already persisted to # Bacula's configuration # # @return [ActiveRecord::Relation] of `JobTemplate` def persisted_jobs host.job_templates.where(baculized: true).includes(:fileset, :schedule) end # Fetches the client's performed jobs in reverse chronological order # # @return [ActiveRecord::Relation] of `Job` def recent_jobs - jobs.order(EndTime: :desc).limit(RECENT_JOBS_COUNT).includes(:file_set) + jobs.order(EndTime: :desc).includes(:file_set) end # Helper method. It shows the client's job retention, # (which is expressed in seconds) in days. # # @return [Integer] def job_retention_days job_retention / DAY_SECS end # Helper method. It shows the client's file retention, # (which is expressed in seconds) in days. # # @return [Integer] def file_retention_days file_retention / DAY_SECS end # Helper method for auto_prune # # @return [String] 'yes' or 'no' def auto_prune_human auto_prune == 1 ? 'yes' : 'no' end # Helper method for displayin the last job's datetime in a nice format. def last_job_date_formatted if job_time = jobs.backup_type.last.try(:end_time) I18n.l(job_time, format: :long) end end # Shows if a client has any backup jobs to Bacule config # # @return [Boolean] def is_backed_up? jobs.backup_type.any? end # Shows the total file size of the jobs that run for a specific client # # @return [Integer] Size in Bytes def backup_jobs_size jobs.backup_type.map(&:job_bytes).sum end # Shows the total files' count for the jobs that run for a specific client # # @return [Integer] File count def files_count jobs.map(&:job_files).sum end # Fetches the client's jobs that are running at the moment # # @return [Integer] def running_jobs jobs.running.count end end diff --git a/app/models/job.rb b/app/models/job.rb index 7f5fc83..21f404a 100644 --- a/app/models/job.rb +++ b/app/models/job.rb @@ -1,97 +1,99 @@ class Job < ActiveRecord::Base self.table_name = :Job self.primary_key = :JobId alias_attribute :job_id, :JobId alias_attribute :job, :Job alias_attribute :name, :Name alias_attribute :type, :Type alias_attribute :level, :Level alias_attribute :client_id, :ClientId alias_attribute :job_status, :JobStatus alias_attribute :sched_time, :SchedTime alias_attribute :start_time, :StartTime alias_attribute :end_time, :EndTime alias_attribute :real_end_time, :RealEndTime alias_attribute :job_t_date, :JobTDate alias_attribute :vol_session_id, :VolSessionId alias_attribute :vol_session_time, :VolSessionTime alias_attribute :job_files, :JobFiles alias_attribute :job_bytes, :JobBytes alias_attribute :read_bytes, :ReadBytes alias_attribute :job_errors, :JobErrors alias_attribute :job_missing_files, :JobMissingFiles alias_attribute :pool_id, :PoolId alias_attribute :file_set_id, :FileSetId alias_attribute :prior_job_id, :PriorJobId alias_attribute :purged_files, :PurgedFiles alias_attribute :has_base, :HasBase alias_attribute :has_cache, :HasCache alias_attribute :reviewed, :Reviewed alias_attribute :comment, :Comment belongs_to :pool, foreign_key: :PoolId belongs_to :file_set, foreign_key: :FileSetId belongs_to :client, foreign_key: :ClientId has_many :bacula_files, foreign_key: :JobId has_many :base_files, foreign_key: :BaseJobId has_many :job_media, foreign_key: :JobId has_many :logs, foreign_key: :JobId scope :running, -> { where(job_status: 'R') } scope :backup_type, -> { where(type: 'B') } scope :restore_type, -> { where(type: 'R') } HUMAN_STATUS = { 'A' => 'Canceled by user', 'B' => 'Blocked', 'C' => 'Created, not yet running', 'D' => 'Verify found differences', 'E' => 'Terminated with errors', 'F' => 'Waiting for Client', 'M' => 'Waiting for media mount', 'R' => 'Running', 'S' => 'Waiting for Storage daemon', 'T' => 'Completed successfully', 'a' => 'SD despooling attributes', 'c' => 'Waiting for client resource', 'd' => 'Waiting on maximum jobs', 'e' => 'Non-fatal error', 'f' => 'Fatal error', 'i' => 'Doing batch insert file records', 'j' => 'Waiting for job resource', 'm' => 'Waiting for new media', 'p' => 'Waiting on higher priority jobs', 's' => 'Waiting for storage resource', 't' => 'Waiting on start time' } + paginates_per 20 + def level_human { 'F' => 'Full', 'D' => 'Differential', 'I' => 'Incremental' }[level] end def status_human HUMAN_STATUS[job_status] end def fileset file_set.try(:file_set) || '-' end def start_time_formatted if start_time I18n.l(start_time, format: :long) end end def end_time_formatted if end_time I18n.l(end_time, format: :long) end end end diff --git a/app/models/log.rb b/app/models/log.rb index 3955614..2a67b3e 100644 --- a/app/models/log.rb +++ b/app/models/log.rb @@ -1,17 +1,19 @@ class Log < ActiveRecord::Base self.table_name = :Log self.primary_key = :LogId alias_attribute :log_id, :LogId alias_attribute :job_id, :JobId alias_attribute :time, :Time alias_attribute :log_text, :LogText belongs_to :job, foreign_key: :JobId + paginates_per 20 + def time_formatted if time I18n.l(time, format: :long) end end end diff --git a/app/views/admin/clients/_recent_jobs.html.erb b/app/views/admin/clients/_recent_jobs.html.erb index a444a8e..96514c6 100644 --- a/app/views/admin/clients/_recent_jobs.html.erb +++ b/app/views/admin/clients/_recent_jobs.html.erb @@ -1,22 +1,22 @@
- <%= render partial: 'recent_job', collection: @client.recent_jobs %> + <%= render partial: 'recent_job', collection: @jobs %>
Name JobId Level Fileset Started At Finished At Bytes Files Status
diff --git a/app/views/admin/clients/jobs.html.erb b/app/views/admin/clients/jobs.html.erb index f26a259..f8e83bc 100644 --- a/app/views/admin/clients/jobs.html.erb +++ b/app/views/admin/clients/jobs.html.erb @@ -1,10 +1,20 @@ <%= render partial: 'header' %>
-

Recent Jobs

+

Recent Jobs (<%= @jobs.total_count %>)

+ +
+
+ <%= page_entries_info @jobs, entry_name: 'job' %> +
+
+ <%= paginate @jobs %> +
+
+
<%= render partial: 'recent_jobs' %>
diff --git a/app/views/admin/clients/logs.html.erb b/app/views/admin/clients/logs.html.erb index a87cdac..df7816c 100644 --- a/app/views/admin/clients/logs.html.erb +++ b/app/views/admin/clients/logs.html.erb @@ -1,25 +1,36 @@ <%= render partial: 'header' %>
-

Logs

+

Logs (<%= @logs.total_count %>)

+
+ +
+
+ <%= page_entries_info @logs, entry_name: 'log' %> +
+
+ <%= paginate @logs %> +
+
+
<%= render partial: 'log', collection: @logs %>
LogId Job Time Text
diff --git a/app/views/clients/_recent_jobs.html.erb b/app/views/clients/_recent_jobs.html.erb index d29f972..6a39c49 100644 --- a/app/views/clients/_recent_jobs.html.erb +++ b/app/views/clients/_recent_jobs.html.erb @@ -1,22 +1,22 @@
- <%= render partial: 'clients/recent_job', collection: @client.recent_jobs %> + <%= render partial: 'clients/recent_job', collection: @jobs %>
Name JobId Level Fileset Started At Finished At Bytes Files Status
diff --git a/app/views/clients/jobs.html.erb b/app/views/clients/jobs.html.erb index a22efeb..28b8c01 100644 --- a/app/views/clients/jobs.html.erb +++ b/app/views/clients/jobs.html.erb @@ -1,12 +1,20 @@ <%= render partial: 'header' %>
-

Recent Jobs

+

Recent Jobs (<%= @jobs.total_count %>)

+
+
+
+
+ <%= page_entries_info @jobs, entry_name: 'job' %> +
+
+ <%= paginate @jobs %>
<%= render partial: 'recent_jobs' %>
<%= link_to 'Back to clients', clients_path %> diff --git a/app/views/clients/logs.html.erb b/app/views/clients/logs.html.erb index a87cdac..df7816c 100644 --- a/app/views/clients/logs.html.erb +++ b/app/views/clients/logs.html.erb @@ -1,25 +1,36 @@ <%= render partial: 'header' %>
-

Logs

+

Logs (<%= @logs.total_count %>)

+
+ +
+
+ <%= page_entries_info @logs, entry_name: 'log' %> +
+
+ <%= paginate @logs %> +
+
+
<%= render partial: 'log', collection: @logs %>
LogId Job Time Text