From 198867facb2ae5e691d3366ae0483e81fcfae1eb Mon Sep 17 00:00:00 2001 From: Oliver Peate Date: Mon, 28 Sep 2020 16:52:23 +0100 Subject: [PATCH] Dynamically render Dashboard stats from CSV data --- config.rb | 12 +++++++- lib/api_catalogue.rb | 8 ++---- lib/dashboard_stats.rb | 44 ++++++++++++++++++++++++++++++ source/dashboard.html.erb | 47 ++++++++++++++++++++++++++++++++ source/dashboard/index.html.md | 35 ------------------------ spec/lib/dashboard_stats_spec.rb | 43 +++++++++++++++++++++++++++++ 6 files changed, 148 insertions(+), 41 deletions(-) create mode 100644 lib/dashboard_stats.rb create mode 100644 source/dashboard.html.erb delete mode 100644 source/dashboard/index.html.md create mode 100644 spec/lib/dashboard_stats_spec.rb diff --git a/config.rb b/config.rb index 50606b856..8489d3091 100644 --- a/config.rb +++ b/config.rb @@ -1,5 +1,6 @@ require 'govuk_tech_docs' require 'lib/api_catalogue' +require 'lib/dashboard_stats' require 'lib/url_helpers' GovukTechDocs.configure(self) @@ -11,7 +12,9 @@ helpers UrlHelpers csv_path = File.expand_path("data/inputs/apic.csv", __dir__) -ApiCatalogue.from_csv(csv_path).organisations_apis.each do |organisation, apis| +api_catalogue = ApiCatalogue.from_csv(csv_path) + +api_catalogue.organisations_apis.each do |organisation, apis| proxy( UrlHelpers.organisation_path(organisation), "organisation_index.html", @@ -30,3 +33,10 @@ ) end end + +proxy( + "/dashboard/index.html", + "dashboard.html", + locals: { dashboard_stats: DashboardStats.new(api_catalogue) }, + ignore: true, +) diff --git a/lib/api_catalogue.rb b/lib/api_catalogue.rb index 88be3367f..216603638 100644 --- a/lib/api_catalogue.rb +++ b/lib/api_catalogue.rb @@ -18,12 +18,10 @@ def self.from_csv(csv_path) new(data) end - def initialize(data) - @data = data - end + attr_reader :organisations_apis - def organisations_apis - data.each + def initialize(organisations_apis) + @organisations_apis = organisations_apis end private diff --git a/lib/dashboard_stats.rb b/lib/dashboard_stats.rb new file mode 100644 index 000000000..83d93cb4a --- /dev/null +++ b/lib/dashboard_stats.rb @@ -0,0 +1,44 @@ +class DashboardStats + OrganisationStats = Struct.new( + :organisation, :api_count, :first_added, :last_updated, keyword_init: true + ) + + def initialize(api_catalogue) + @api_catalogue = api_catalogue + end + + def total_apis + api_catalogue.organisations_apis.sum do |_, apis| + apis.count + end + end + + def total_organisations + api_catalogue.organisations_apis.count + end + + def by_organisation + @_by_organsation ||= calculate_stats_by_organisation + end + + private + + attr_reader :api_catalogue + + def calculate_stats_by_organisation + api_catalogue + .organisations_apis + .map(&method(:build_organisation_stats)) + .sort_by(&:api_count) + .reverse + end + + def build_organisation_stats(organisation, apis) + OrganisationStats.new( + organisation: organisation, + api_count: apis.count, + first_added: apis.min_by(&:date_added)&.date_added, + last_updated: apis.max_by(&:date_updated)&.date_updated, + ) + end +end diff --git a/source/dashboard.html.erb b/source/dashboard.html.erb new file mode 100644 index 000000000..ab4b7f753 --- /dev/null +++ b/source/dashboard.html.erb @@ -0,0 +1,47 @@ +--- +title: API Catalogue Contents +weight: 1000 +hide_in_navigation: true +--- + +

API Catalogue Contents

+ + + + + + + + + + + + + + + +
Total APIs:Departments Represented:
<%= dashboard_stats.total_apis %><%= dashboard_stats.total_organisations %>
+ + + + + + + + + + + + + + <% dashboard_stats.by_organisation.each do |stats| %> + + + + + + + + <% end %> + +
Department:Number of APIs:First Added:Last Update:Link:
<%= stats.organisation.name %><%= stats.api_count %><%= stats.first_added&.to_formatted_s(:iso8601) %><%= stats.last_updated&.to_formatted_s(:iso8601) %><%= link_to(stats.organisation.alternate_name, organisation_path(stats.organisation)) %>
diff --git a/source/dashboard/index.html.md b/source/dashboard/index.html.md deleted file mode 100644 index 80be32752..000000000 --- a/source/dashboard/index.html.md +++ /dev/null @@ -1,35 +0,0 @@ ---- -title: API Catalogue Contents -weight: 1000 -hide_in_navigation: true ---- - -## API Catalogue Contents - -
 
- -|Total APIs:|Departments Represented:| -|:---|:---| -|161|17| - -
 
- -|Department:|Number of APIs:|First Added:|Last Update:|Link:| -|:---|:---|:---|:---|:---| -|National Health Service|39|2020-08-25|2020-08-25|[NHS](/NHS/)| -|Department of Work and Pensions|38|2020-08-28|2020-09-01|[DWP](/DWP/)| -|HM Revenue & Customs|30|2020-09-02|2020-09-14|[HMRC](/HMRC/)| -|Government Digital Service|11|2020-01-08|2020-08-24|[GDS](/GDS/)| -|UK Hydrographic Office|10|2020-09-18|2020-09-18|[UKHO](/UKHO/)| -|Environment Agency|9|2020-01-08|2020-08-26|[EA](/EA/)| -|Ordnance Survey|8|2020-08-24|2020-08-24|[OS](/OS/)| -|Department for Education|3|2020-08-24|2020-08-24|[DfE](/DfE/)| -|Companies House|2|2020-01-08|2020-08-24|[CH](/CH/)| -|Driver and Vehicle Licensing Agency|2|2020-01-08|2020-08-24|[DVLA](/DVLA/)| -|Food Standards Agency|2|2020-01-08|2020-08-26|[FSA](/FSA/)| -|Office of National Statistics|2|2020-01-08|2020-08-24|[ONS](/ONS/)| -|Department for International Trade|1|2020-09-05|2020-09-05|[DfIT](/DfIT/)| -|London Borough of Hackney|1|2020-01-08|2020-08-24|[Hackney](/Hackney/)| -|Local Government Association|1|2020-01-08|2020-08-24|[LG](/LG/)| -|Scottish Government|1|2020-01-08|2020-08-26|[Scot](/Scot/)| -|West Berkshire Council|1|2020-01-08|2020-08-24|[WBerks](/WBerks/)| diff --git a/spec/lib/dashboard_stats_spec.rb b/spec/lib/dashboard_stats_spec.rb new file mode 100644 index 000000000..0fd550f9f --- /dev/null +++ b/spec/lib/dashboard_stats_spec.rb @@ -0,0 +1,43 @@ +require "api_catalogue" +require "dashboard_stats" + +RSpec.describe DashboardStats do + let(:csv_path) { File.expand_path("../../data/inputs/apic.csv", __dir__) } + let(:api_catalogue) { ApiCatalogue.from_csv(csv_path) } + + subject { described_class.new(api_catalogue) } + + describe "#total_apis" do + it "sums the APIs across each organisation" do + expect(subject.total_apis).to be > 100 + end + end + + describe "#total_organisations" do + it "sums the number of organisations" do + expect(subject.total_organisations).to be > 10 + expect(subject.total_organisations).to be < subject.total_apis + end + end + + describe "#by_organisation" do + it "provides stats per organisation" do + nhs_stats = subject.by_organisation.detect do |stats| + stats.organisation.name.casecmp?("National Health Service") + end + + expect(nhs_stats).to have_attributes( + organisation: have_attributes(name: "National Health Service"), + api_count: (a_value > 30), + first_added: be_a(Date), + last_updated: be_a(Date), + ) + end + + it "orders the organisations by number of APIs" do + subject.by_organisation.each_cons(2) do |org1, org2| + expect(org1.api_count).to be >= org2.api_count + end + end + end +end