Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

270 Dashboard Filters. #381

Merged
merged 12 commits into from
Feb 6, 2024
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .bundler-audit.yml
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
---
ignore:
- CVE-2023-26141
- CVE-2024-21636
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -44,3 +44,6 @@ bin/fetch_config.rb

/app/assets/builds/*
!/app/assets/builds/.keep

./nginx/key.pem
./nginx/cert.pem
2 changes: 1 addition & 1 deletion Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ gem "foreman"
gem "jbuilder"
gem "okcomputer"
gem "pg", "~> 1.5"
gem "puma", "~> 6.4"
gem "puma", ">= 6.4.2", "< 7"
gem "rails", "~> 7.1"
gem "tzinfo-data", platforms: %i[mingw mswin x64_mingw jruby]

Expand Down
4 changes: 2 additions & 2 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -319,7 +319,7 @@ GEM
psych (5.1.1.1)
stringio
public_suffix (5.0.1)
puma (6.4.0)
puma (6.4.2)
nio4r (~> 2.0)
raabro (1.4.0)
racc (1.7.3)
Expand Down Expand Up @@ -536,7 +536,7 @@ DEPENDENCIES
phonelib
propshaft (~> 0.8.0)
pry-byebug
puma (~> 6.4)
puma (>= 6.4.2, < 7)
rails (~> 7.1)
rolify
rspec-rails
Expand Down
6 changes: 5 additions & 1 deletion app/controllers/system_admin/dashboard_controller.rb
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
module SystemAdmin
class DashboardController < AdminController
def show
@kpis = Kpis.new(**kpi_params)
@kpis = Kpis.new(**kpi_params.merge(window_params))
rescue ArgumentError => e
flash[:alert] = e.message
redirect_to(dashboard_path)
Expand All @@ -16,5 +16,9 @@ def kpi_params
.to_hash
.symbolize_keys
end

def window_params
{ window: params[:window] }
end
end
end
9 changes: 9 additions & 0 deletions app/helpers/application_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,13 @@ def application_statuses_options(selected: nil, all_statuses: false)

options_for_select(statuses, selected:)
end

def dashboard_link(window_param, label)
current_window = params[:window] || "all"
if current_window == window_param
content_tag(:strong, label)
else
link_to(label, dashboard_path(window: window_param))
end
end
end
15 changes: 15 additions & 0 deletions app/helpers/inflection_helper.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Initially created to help display the correct form of day or days in the dashboard.
module InflectionHelper
def pluralize_word(count, word)
"#{count} #{word.pluralize(count)}"
end

def calculate_day_stats(durations)
min_days = pluralize_word(durations.min.abs, "day") if durations.min
max_days = pluralize_word(durations.max.abs, "day") if durations.max
average_duration = durations.size.positive? ? (durations.sum / durations.size.to_f).round.abs : 0
average_days = pluralize_word(average_duration, "day")

{ min: min_days, max: max_days, average: average_days }
end
end
58 changes: 41 additions & 17 deletions app/models/kpis.rb
Original file line number Diff line number Diff line change
@@ -1,73 +1,74 @@
class Kpis
def initialize(unit: "hours", range_start: "24", range_end: "0")
def initialize(unit: "hours", range_start: "24", range_end: "0", window: "all")
@date_range_params = parse_date_range(unit:, range_start:, range_end:)
@date_range = to_date_range(**@date_range_params)
@window = window
end

attr_reader :date_range, :date_range_params
eddieleeper marked this conversation as resolved.
Show resolved Hide resolved

def total_applications
Application.count
filtered_applications_by_date.count
end

def total_rejections
ApplicationProgress.where.not(rejection_completed_at: nil).count
filter_by_date_range(ApplicationProgress.where.not(rejection_completed_at: nil)).count
end

def average_age
AverageAgeQuery.new.call
AverageAgeQuery.new(filtered_applications_by_date).call
end

def total_paid
ApplicationProgress.where.not(banking_approval_completed_at: nil).count
filter_by_date_range(ApplicationProgress.where.not(banking_approval_completed_at: nil)).count
end

def route_breakdown
RouteBreakdownQuery.new.call
RouteBreakdownQuery.new(filtered_applications_by_date).call
end

def subject_breakdown
SubjectBreakdownQuery.new.call
SubjectBreakdownQuery.new(filtered_applications_by_date).call
end

def visa_breakdown
VisaBreakdownQuery.new.call.first(3)
VisaBreakdownQuery.new(filtered_applications_by_date).call.first(3)
end

def nationality_breakdown
NationalityBreakdownQuery.new.call.first(5)
NationalityBreakdownQuery.new(filtered_applications_by_date).call.first(5)
end

def gender_breakdown
GenderBreakdownQuery.new.call
GenderBreakdownQuery.new(filtered_applications_by_date).call
end

def rejection_reason_breakdown
RejectionReasonBreakdownQuery.new.call
RejectionReasonBreakdownQuery.new(filtered_applications_by_date).call
end

def time_to_initial_checks
TimeToInitialChecksQuery.new.call
TimeToInitialChecksQuery.new(filtered_progress_by_date).call
end

def time_to_home_office_checks
TimeToHomeOfficeChecksQuery.new.call
TimeToHomeOfficeChecksQuery.new(filtered_progress_by_date).call
end

def time_to_school_checks
TimeToSchoolChecksQuery.new.call
TimeToSchoolChecksQuery.new(filtered_progress_by_date).call
end

def time_to_banking_approval
TimeToBankingApprovalQuery.new.call
TimeToBankingApprovalQuery.new(filtered_progress_by_date).call
end

def time_to_payment_confirmation
TimeToPaymentConfirmationQuery.new.call
TimeToPaymentConfirmationQuery.new(filtered_progress_by_date).call
end

def status_breakdown
StatusBreakdownQuery.call
StatusBreakdownQuery.call(filtered_progress_by_date)
end

def forms_funnel
Expand Down Expand Up @@ -119,4 +120,27 @@ def to_date_range(unit:, range_start:, range_end:)
def forms_funnel_query
@forms_funnel_query ||= FormsFunnelQuery.call(date_range:)
end

def date_ranges
{
"sept_oct" => Date.new(2023, 9, 1).beginning_of_day..Date.new(2023, 10, 31).end_of_day,
"jan_feb" => Date.new(2024, 1, 1).beginning_of_day..Date.new(2024, 3, 1).end_of_day,
}
end

def filter_by_date_range(scope)
if date_ranges.key?(@window)
scope.where(created_at: date_ranges[@window])
else
scope
end
end

def filtered_applications_by_date
filter_by_date_range(Application.all)
end

def filtered_progress_by_date
filter_by_date_range(ApplicationProgress.all)
end
end
4 changes: 2 additions & 2 deletions app/queries/average_age_query.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
class AverageAgeQuery
def initialize(relation = Applicant.all)
@relation = relation.joins(:application).merge(Application.all)
def initialize(applications = Application.all)
@relation = Applicant.all.joins(:application).merge(applications)
eddieleeper marked this conversation as resolved.
Show resolved Hide resolved
end

def call
Expand Down
4 changes: 2 additions & 2 deletions app/queries/gender_breakdown_query.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
class GenderBreakdownQuery
def initialize(relation = Applicant.all)
@relation = relation.joins(:application).merge(Application.all)
def initialize(applications = Application.all)
@relation = Applicant.all.joins(:application).merge(applications)
eddieleeper marked this conversation as resolved.
Show resolved Hide resolved
end

def call
Expand Down
4 changes: 2 additions & 2 deletions app/queries/nationality_breakdown_query.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
class NationalityBreakdownQuery
def initialize(relation = Applicant.all)
@relation = relation.joins(:application).merge(Application.all)
def initialize(applications = Application.all)
@relation = Applicant.all.joins(:application).merge(applications)
eddieleeper marked this conversation as resolved.
Show resolved Hide resolved
end

def call
Expand Down
4 changes: 2 additions & 2 deletions app/queries/rejection_reason_breakdown_query.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
class RejectionReasonBreakdownQuery
def initialize(relation = ApplicationProgress.all)
@relation = relation.joins(:application).merge(Application.all).where.not(rejection_reason: nil)
def initialize(applications = Application.all)
@relation = ApplicationProgress.all.joins(:application).merge(applications).where.not(rejection_reason: nil)
eddieleeper marked this conversation as resolved.
Show resolved Hide resolved
end

def call
Expand Down
10 changes: 7 additions & 3 deletions app/queries/status_breakdown_query.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
class StatusBreakdownQuery
def self.call
new.execute
def self.call(scope = ApplicationProgress.all)
new(scope).execute
end

def initialize(scope)
@scope = scope
end

def execute
Expand All @@ -10,7 +14,7 @@ def execute
private

def status_breakdown
ApplicationProgress.group(:status).count
@scope.group(:status).count
end

def ordered_with_defaults(breakdown)
Expand Down
9 changes: 2 additions & 7 deletions app/queries/time_to_banking_approval_query.rb
Original file line number Diff line number Diff line change
@@ -1,17 +1,12 @@
class TimeToBankingApprovalQuery
include InflectionHelper
def initialize(relation = ApplicationProgress.all)
@relation = relation
end

def call
applications_list = @relation.where.not(school_checks_completed_at: nil).where.not(banking_approval_completed_at: nil)

durations = applications_list.map { |app| (app.banking_approval_completed_at.to_date - app.school_checks_completed_at.to_date).to_i }

min_days = "#{durations.min.abs} days" if durations.min
max_days = "#{durations.max.abs} days" if durations.max
average_days = durations.size.positive? ? "#{(durations.sum / durations.size.to_f).round.abs} days" : "0 days"

{ min: min_days, max: max_days, average: average_days }
calculate_day_stats(durations)
end
end
10 changes: 3 additions & 7 deletions app/queries/time_to_home_office_checks_query.rb
Original file line number Diff line number Diff line change
@@ -1,17 +1,13 @@
class TimeToHomeOfficeChecksQuery
include InflectionHelper

def initialize(relation = ApplicationProgress.all)
@relation = relation
end

def call
applications_list = @relation.where.not(initial_checks_completed_at: nil).where.not(home_office_checks_completed_at: nil)

durations = applications_list.map { |app| (app.home_office_checks_completed_at.to_date - app.initial_checks_completed_at.to_date).to_i }

min_days = "#{durations.min.abs} days" if durations.min
max_days = "#{durations.max.abs} days" if durations.max
average_days = durations.size.positive? ? "#{(durations.sum / durations.size.to_f).round.abs} days" : "0 days"

{ min: min_days, max: max_days, average: average_days }
calculate_day_stats(durations)
end
end
10 changes: 3 additions & 7 deletions app/queries/time_to_initial_checks_query.rb
Original file line number Diff line number Diff line change
@@ -1,17 +1,13 @@
class TimeToInitialChecksQuery
include InflectionHelper

def initialize(relation = ApplicationProgress.all)
@relation = relation
end

def call
applications_list = @relation.where.not(created_at: nil).where.not(initial_checks_completed_at: nil)

durations = applications_list.map { |app| (app.initial_checks_completed_at.to_date - app.created_at.to_date).to_i }

min_days = "#{durations.min.abs} days" if durations.min
max_days = "#{durations.max.abs} days" if durations.max
average_days = durations.size.positive? ? "#{(durations.sum / durations.size.to_f).round.abs} days" : "0 days"

{ min: min_days, max: max_days, average: average_days }
calculate_day_stats(durations)
end
end
9 changes: 2 additions & 7 deletions app/queries/time_to_payment_confirmation_query.rb
Original file line number Diff line number Diff line change
@@ -1,17 +1,12 @@
class TimeToPaymentConfirmationQuery
include InflectionHelper
def initialize(relation = ApplicationProgress.all)
@relation = relation
end

def call
applications_list = @relation.where.not(payment_confirmation_completed_at: nil).where.not(banking_approval_completed_at: nil)

durations = applications_list.map { |app| (app.payment_confirmation_completed_at.to_date - app.banking_approval_completed_at.to_date).to_i }

min_days = "#{durations.min.abs} days" if durations.min
max_days = "#{durations.max.abs} days" if durations.max
average_days = durations.size.positive? ? "#{(durations.sum / durations.size.to_f).round.abs} days" : "0 days"

{ min: min_days, max: max_days, average: average_days }
calculate_day_stats(durations)
end
end
9 changes: 2 additions & 7 deletions app/queries/time_to_school_checks_query.rb
Original file line number Diff line number Diff line change
@@ -1,17 +1,12 @@
class TimeToSchoolChecksQuery
include InflectionHelper
def initialize(relation = ApplicationProgress.all)
@relation = relation
end

def call
applications_list = @relation.where.not(home_office_checks_completed_at: nil).where.not(school_checks_completed_at: nil)

durations = applications_list.map { |app| (app.school_checks_completed_at.to_date - app.home_office_checks_completed_at.to_date).to_i }

min_days = "#{durations.min.abs} days" if durations.min
max_days = "#{durations.max.abs} days" if durations.max
average_days = durations.size.positive? ? "#{(durations.sum / durations.size.to_f).round.abs} days" : "0 days"

{ min: min_days, max: max_days, average: average_days }
calculate_day_stats(durations)
end
end
8 changes: 8 additions & 0 deletions app/views/system_admin/dashboard/show.html.erb
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
<div class="govuk-body date-range">
<%= dashboard_link('all', 'All') %>
|
<%= dashboard_link('sept_oct', 'Sept/Oct 2023') %>
|
<%= dashboard_link('jan_feb', 'Jan/Feb 2024') %>
</div>

<div class="dashboard govuk-body">
<div class="kpi-widget applications">
<h3 class="title">Applications</h3>
Expand Down
2 changes: 2 additions & 0 deletions config/environments/development.rb
Original file line number Diff line number Diff line change
Expand Up @@ -61,4 +61,6 @@

# Uncomment if you wish to allow Action Cable access from any origin.
# config.action_cable.disable_request_forgery_protection = true

config.hosts << "itrp.local"
end
2 changes: 2 additions & 0 deletions config/environments/test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -54,4 +54,6 @@

# config/initializers/dartsass.rb
config.dartsass.build_options << " --quiet-deps"

config.hosts << "www.example.com"
end
Loading
Loading