decidim-comparative_stats 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (91) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE-AGPLv3.txt +661 -0
  3. data/README.md +187 -0
  4. data/Rakefile +40 -0
  5. data/app/assets/config/admin/comparative_stats_manifest.css +4 -0
  6. data/app/assets/config/admin/comparative_stats_manifest.js +2 -0
  7. data/app/assets/config/comparative_stats_manifest.css +4 -0
  8. data/app/assets/config/comparative_stats_manifest.js +2 -0
  9. data/app/assets/images/bcn-logo.png +0 -0
  10. data/app/assets/images/decidim/comparative_stats/icon.svg +1 -0
  11. data/app/assets/images/platoniq-logo.png +0 -0
  12. data/app/assets/javascripts/decidim/comparative_stats/geocoded_events.js.es6 +94 -0
  13. data/app/assets/javascripts/decidim/comparative_stats/graphs.js.es6 +13 -0
  14. data/app/assets/stylesheets/decidim/comparative_stats/geocoded_events.scss +23 -0
  15. data/app/assets/stylesheets/decidim/comparative_stats/graphs.scss +6 -0
  16. data/app/assets/stylesheets/decidim/comparative_stats/widget.scss +8 -0
  17. data/app/cells/decidim/comparative_stats/metric_piecharts/show.erb +14 -0
  18. data/app/cells/decidim/comparative_stats/metric_piecharts_cell.rb +39 -0
  19. data/app/cells/decidim/comparative_stats/metric_timelines/show.erb +14 -0
  20. data/app/cells/decidim/comparative_stats/metric_timelines_cell.rb +23 -0
  21. data/app/cells/decidim/comparative_stats/participatory_processes_timeline/show.erb +55 -0
  22. data/app/cells/decidim/comparative_stats/participatory_processes_timeline_cell.rb +51 -0
  23. data/app/cells/decidim/comparative_stats/participatory_spaces_geocoded_events/show.erb +55 -0
  24. data/app/cells/decidim/comparative_stats/participatory_spaces_geocoded_events_cell.rb +108 -0
  25. data/app/commands/decidim/comparative_stats/admin/create_endpoint.rb +46 -0
  26. data/app/commands/decidim/comparative_stats/admin/destroy_endpoint.rb +43 -0
  27. data/app/commands/decidim/comparative_stats/admin/update_endpoint.rb +47 -0
  28. data/app/controllers/decidim/comparative_stats/admin/application_controller.rb +16 -0
  29. data/app/controllers/decidim/comparative_stats/admin/endpoints_controller.rb +83 -0
  30. data/app/controllers/decidim/comparative_stats/admin/graphs_controller.rb +16 -0
  31. data/app/controllers/decidim/comparative_stats/widgets_controller.rb +31 -0
  32. data/app/forms/decidim/comparative_stats/admin/endpoint_form.rb +26 -0
  33. data/app/helpers/decidim/comparative_stats/application_helper.rb +27 -0
  34. data/app/models/decidim/comparative_stats/application_record.rb +10 -0
  35. data/app/models/decidim/comparative_stats/endpoint.rb +22 -0
  36. data/app/permissions/decidim/comparative_stats/admin/permissions.rb +24 -0
  37. data/app/presenters/decidim/comparative_stats/admin_log/endpoint_presenter.rb +46 -0
  38. data/app/views/decidim/comparative_stats/admin/endpoints/_form.html.erb +7 -0
  39. data/app/views/decidim/comparative_stats/admin/endpoints/edit.html.erb +16 -0
  40. data/app/views/decidim/comparative_stats/admin/endpoints/index.html.erb +66 -0
  41. data/app/views/decidim/comparative_stats/admin/endpoints/new.html.erb +16 -0
  42. data/app/views/decidim/comparative_stats/admin/graphs/show.html.erb +15 -0
  43. data/app/views/decidim/comparative_stats/widgets/_all.html.erb +1 -0
  44. data/app/views/decidim/comparative_stats/widgets/_embed.html.erb +7 -0
  45. data/app/views/decidim/comparative_stats/widgets/_embed_modal.html.erb +27 -0
  46. data/app/views/decidim/comparative_stats/widgets/_global_stats.html.erb +4 -0
  47. data/app/views/decidim/comparative_stats/widgets/_global_stats_timeline.html.erb +4 -0
  48. data/app/views/decidim/comparative_stats/widgets/_processes_timeline.html.erb +4 -0
  49. data/app/views/decidim/comparative_stats/widgets/_spaces_geocoded_events.html.erb +5 -0
  50. data/app/views/decidim/comparative_stats/widgets/_tabs.html.erb +19 -0
  51. data/app/views/decidim/comparative_stats/widgets/show.html.erb +1 -0
  52. data/app/views/layouts/decidim/admin/comparative_stats.html.erb +28 -0
  53. data/app/views/layouts/decidim/comparative_stats/widget.html.erb +22 -0
  54. data/config/i18n-tasks.yml +10 -0
  55. data/config/locales/ca.yml +57 -0
  56. data/config/locales/cs.yml +57 -0
  57. data/config/locales/en.yml +64 -0
  58. data/config/locales/es.yml +57 -0
  59. data/db/migrate/20191219104548_create_decidim_comparative_stats_endpoints.rb +13 -0
  60. data/db/migrate/20200122072955_add_name_version_to_comparative_stats_endpoints.rb +8 -0
  61. data/db/migrate/20200130203914_rename_version_field_in_comparative_stats_endpoints.rb +7 -0
  62. data/db/seeds.rb +42 -0
  63. data/lib/decidim/comparative_stats.rb +22 -0
  64. data/lib/decidim/comparative_stats/admin.rb +10 -0
  65. data/lib/decidim/comparative_stats/admin_engine.rb +50 -0
  66. data/lib/decidim/comparative_stats/api_fetcher.rb +93 -0
  67. data/lib/decidim/comparative_stats/cached_http_adapter.rb +23 -0
  68. data/lib/decidim/comparative_stats/engine.rb +34 -0
  69. data/lib/decidim/comparative_stats/queries/global_events.graphql +84 -0
  70. data/lib/decidim/comparative_stats/queries/global_history_metrics.graphql +10 -0
  71. data/lib/decidim/comparative_stats/queries/global_metrics.graphql +6 -0
  72. data/lib/decidim/comparative_stats/queries/name_and_version.graphql +6 -0
  73. data/lib/decidim/comparative_stats/queries/participatory_processes.graphql +12 -0
  74. data/lib/decidim/comparative_stats/queries/v022/global_events.graphql +76 -0
  75. data/lib/decidim/comparative_stats/test/factories.rb +13 -0
  76. data/lib/decidim/comparative_stats/version.rb +10 -0
  77. data/vendor/assets/images/draw/layers-2x.png +0 -0
  78. data/vendor/assets/images/draw/layers.png +0 -0
  79. data/vendor/assets/images/draw/marker-icon-2x.png +0 -0
  80. data/vendor/assets/images/draw/marker-icon.png +0 -0
  81. data/vendor/assets/images/draw/marker-shadow.png +0 -0
  82. data/vendor/assets/images/draw/spritesheet-2x.png +0 -0
  83. data/vendor/assets/images/draw/spritesheet.png +0 -0
  84. data/vendor/assets/images/draw/spritesheet.svg +156 -0
  85. data/vendor/assets/images/images/layers-2x.png +0 -0
  86. data/vendor/assets/images/images/layers.png +0 -0
  87. data/vendor/assets/images/images/marker-icon-2x.png +0 -0
  88. data/vendor/assets/images/images/marker-icon.png +0 -0
  89. data/vendor/assets/images/images/marker-shadow.png +0 -0
  90. data/vendor/assets/javascripts/leaflet.js +5 -0
  91. metadata +234 -0
@@ -0,0 +1,187 @@
1
+ # Decidim::ComparativeStats
2
+
3
+ ![Test](https://github.com/Platoniq/decidim-module-comparative_stats/workflows/Test/badge.svg)
4
+ [![Maintainability](https://api.codeclimate.com/v1/badges/59d3415b89244ef0d40b/maintainability)](https://codeclimate.com/github/Platoniq/decidim-module-comparative_stats/maintainability)
5
+ [![Codecov](https://codecov.io/gh/Platoniq/decidim-module-comparative_stats/branch/master/graph/badge.svg?token=XhzWO0IiWt)](https://codecov.io/gh/Platoniq/decidim-module-comparative_stats)
6
+
7
+ Allows to compare different Decidim sites by accessing their GraphQL API and
8
+ generate graphs.
9
+
10
+ > NOTE: This module is in beta status, feel free to report issues or contribute in it!
11
+
12
+ ## Usage
13
+
14
+ This module works by connecting to several Decidim API's.
15
+ Just go to your `your-decidim-installation.org/admin/comparative_stats` and
16
+ add endpoints to compare.
17
+ For instance, Decidim Barcelona endpoint is `https://www.decidim.barcelona/api`
18
+
19
+ Then, go to graphs and see some nice graphs!
20
+
21
+ Graphs can be embedded anywhere independently, just use the button
22
+ `embed <>` and copy the code to any other place.
23
+
24
+ The generated code will look something like:
25
+
26
+ ```html
27
+ <iframe
28
+ src="http://your_url/comparative_stats/widgets/global_stats.html"
29
+ frameborder="0"
30
+ width="100%"
31
+ height="420"
32
+ scrolling="vertical"></iframe>
33
+ ```
34
+
35
+ You might want to customize the `height` parameter to match your particular case.
36
+
37
+ ![Barcelona/Helsinki comparison](example.png)
38
+ *A real example comparing the participatory processes carried out by the cities of Barcelona and Helsinki in 2019*
39
+
40
+ ## Installation
41
+
42
+ Add this line to your application's Gemfile:
43
+
44
+ ```ruby
45
+ gem "decidim-comparative_stats", "~> 1.0.1"
46
+ ```
47
+
48
+ And then execute:
49
+
50
+ ```bash
51
+ bundle
52
+ bundle exec rails decidim_comparative_stats:install:migrations
53
+ bundle exec rails db:migrate
54
+ ```
55
+
56
+ Depending on your Decidim version, choose the corresponding Awesome version to ensure
57
+ compatibility:
58
+
59
+ | Comparative stats version | Compatible Decidim versions |
60
+ |---|---|
61
+ | 1.0.x | 0.21.x - 0.23.x |
62
+
63
+ ## Configuration options
64
+
65
+ API queries are cached 1 hour by default.
66
+ This can be tuned by creating an initializer in your Decidim installation.
67
+ For instance, create the file `config/initializers/comparative_stats.rb`
68
+ with this content:
69
+
70
+ ```ruby
71
+ # frozen_string_literal: true
72
+
73
+ Decidim::ComparativeStats.configure do |config|
74
+ config.stats_cache_expiration_time = 2.hour
75
+ end
76
+ ```
77
+
78
+ ## Contributing
79
+
80
+ See [Decidim](https://github.com/decidim/decidim).
81
+
82
+ ### Developing
83
+
84
+ To start contributing to this project, first:
85
+
86
+ - Install the basic dependencies (such as Ruby and PostgreSQL)
87
+ - Clone this repository
88
+
89
+ Decidim's main repository also provides a Docker configuration file if you
90
+ prefer to use Docker instead of installing the dependencies locally on your
91
+ machine.
92
+
93
+ You can create the development app by running the following commands after
94
+ cloning this project:
95
+
96
+ ```bash
97
+ bundle
98
+ DATABASE_USERNAME=<username> DATABASE_PASSWORD=<password> bundle exec rake development_app
99
+ ```
100
+
101
+ Note that the database user has to have rights to create and drop a database in
102
+ order to create the dummy test app database.
103
+
104
+ Then to test how the module works in Decidim, start the development server:
105
+
106
+ ```bash
107
+ cd development_app
108
+ DATABASE_USERNAME=<username> DATABASE_PASSWORD=<password> bundle exec rails s
109
+ ```
110
+
111
+ In case you are using [rbenv](https://github.com/rbenv/rbenv) and have the
112
+ [rbenv-vars](https://github.com/rbenv/rbenv-vars) plugin installed for it, you
113
+ can add the environment variables to the root directory of the project in a file
114
+ named `.rbenv-vars`. If these are defined for the environment, you can omit
115
+ defining these in the commands shown above.
116
+
117
+ #### Code Styling
118
+
119
+ Please follow the code styling defined by the different linters that ensure we
120
+ are all talking with the same language collaborating on the same project. This
121
+ project is set to follow the same rules that Decidim itself follows.
122
+
123
+ [Rubocop](https://rubocop.readthedocs.io/) linter is used for the Ruby language.
124
+
125
+ You can run the code styling checks by running the following commands from the
126
+ console:
127
+
128
+ ```
129
+ bundle exec rubocop
130
+ ```
131
+
132
+ To ease up following the style guide, you should install the plugin to your
133
+ favorite editor, such as:
134
+
135
+ - Atom - [linter-rubocop](https://atom.io/packages/linter-rubocop)
136
+ - Sublime Text - [Sublime RuboCop](https://github.com/pderichs/sublime_rubocop)
137
+ - Visual Studio Code - [Rubocop for Visual Studio Code](https://github.com/misogi/vscode-ruby-rubocop)
138
+
139
+ ### Testing
140
+
141
+ To run the tests run the following in the gem development path:
142
+
143
+ ```bash
144
+ bundle
145
+ DATABASE_USERNAME=<username> DATABASE_PASSWORD=<password> bundle exec rake test_app
146
+ DATABASE_USERNAME=<username> DATABASE_PASSWORD=<password> bundle exec rspec
147
+ ```
148
+
149
+ Note that the database user has to have rights to create and drop a database in
150
+ order to create the dummy test app database.
151
+
152
+ In case you are using [rbenv](https://github.com/rbenv/rbenv) and have the
153
+ [rbenv-vars](https://github.com/rbenv/rbenv-vars) plugin installed for it, you
154
+ can add these environment variables to the root directory of the project in a
155
+ file named `.rbenv-vars`. In this case, you can omit defining these in the
156
+ commands shown above.
157
+
158
+ ### Test code coverage
159
+
160
+ If you want to generate the code coverage report for the tests, you can use
161
+ the `SIMPLECOV=1` environment variable in the rspec command as follows:
162
+
163
+ ```bash
164
+ SIMPLECOV=1 bundle exec rspec
165
+ ```
166
+
167
+ This will generate a folder named `coverage` in the project root which contains
168
+ the code coverage report.
169
+
170
+ ### Localization
171
+
172
+ If you would like to see this module in your own language, you can help with its
173
+ translation at Crowdin:
174
+
175
+ <https://crowdin.com/translate/decidim-comparative-stats>
176
+
177
+ ## License
178
+
179
+ This engine is distributed under the GNU AFFERO GENERAL PUBLIC LICENSE.
180
+
181
+ ## Credits
182
+
183
+ This plugin has been developed by ![Platoniq](app/assets/images/platoniq-logo.png)
184
+
185
+ > Amb el suport de l'Ajuntament de Barcelona - Direcció de Serveis d'Innovació Democràtica
186
+ >
187
+ > ![Logo Barcelona](app/assets/images/bcn-logo.png)
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "decidim/dev/common_rake"
4
+
5
+ def install_module(path)
6
+ Dir.chdir(path) do
7
+ system("bundle exec rake decidim_comparative_stats:install:migrations")
8
+ system("bundle exec rake db:migrate")
9
+ end
10
+ end
11
+
12
+ def seed_db(path)
13
+ Dir.chdir(path) do
14
+ system("bundle exec rake db:seed")
15
+ end
16
+ end
17
+
18
+ desc "Generates a dummy app for testing"
19
+ task test_app: "decidim:generate_external_test_app" do
20
+ ENV["RAILS_ENV"] = "test"
21
+ install_module("spec/decidim_dummy_app")
22
+ end
23
+
24
+ desc "Generates a development app"
25
+ task :development_app do
26
+ Bundler.with_original_env do
27
+ generate_decidim_app(
28
+ "development_app",
29
+ "--app_name",
30
+ "#{base_app_name}_development_app",
31
+ "--path",
32
+ "..",
33
+ "--recreate_db",
34
+ "--demo"
35
+ )
36
+ end
37
+
38
+ install_module("development_app")
39
+ seed_db("development_app")
40
+ end
@@ -0,0 +1,4 @@
1
+ /*
2
+ *= link decidim/comparative_stats/graphs.css
3
+ *= link decidim/comparative_stats/geocoded_events.css
4
+ */
@@ -0,0 +1,2 @@
1
+ //= link decidim/comparative_stats/graphs.js
2
+ //= link decidim/comparative_stats/geocoded_events.js
@@ -0,0 +1,4 @@
1
+ /*
2
+ *= link decidim/comparative_stats/widget.css
3
+ *= link decidim/comparative_stats/geocoded_events.css
4
+ */
@@ -0,0 +1,2 @@
1
+ //= link decidim/comparative_stats/graphs.js
2
+ //= link decidim/comparative_stats/geocoded_events.js
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 35 35"><path d="M17.5 35A17.5 17.5 0 1 1 35 17.5 17.52 17.52 0 0 1 17.5 35zm0-33.06A15.56 15.56 0 1 0 33.06 17.5 15.57 15.57 0 0 0 17.5 1.94zm9.5 13.7H8a1 1 0 0 1 0-1.94h19a1 1 0 0 1 0 1.94zm0 3.68H8a1 1 0 0 1 0-1.94h19a1 1 0 0 1 0 1.94zM22.26 23H8a1 1 0 0 1 0-1.94h14.26a1 1 0 0 1 0 1.94z"/></svg>
@@ -0,0 +1,94 @@
1
+ // = require leaflet
2
+ // = require leaflet-svg-icon
3
+ // = require leaflet.markercluster
4
+ // = require jquery-tmpl
5
+ // = require_self
6
+
7
+ $(() => {
8
+
9
+ var map_object = document.getElementById('geocoded_events');
10
+ var map = L.map(map_object, {
11
+ center: [41,2],
12
+ zoom: 4
13
+ });
14
+
15
+ L.DivIcon.SVGIcon.DecidimIcon = L.DivIcon.SVGIcon.extend({
16
+ options: {
17
+ fillColor: "#ef604d",
18
+ opacity: 0
19
+ },
20
+ _createPathDescription: function() {
21
+ return "M14 1.17a11.685 11.685 0 0 0-11.685 11.685c0 11.25 10.23 20.61 10.665 21a1.5 1.5 0 0 0 2.025 0c0.435-.435 10.665-9.81 10.665-21A11.685 11.685 0 0 0 14 1.17Zm0 17.415A5.085 5.085 0 1 1 19.085 13.5 5.085 5.085 0 0 1 14 18.585Z";
22
+ },
23
+ _createCircle: function() {
24
+ return ""
25
+ }
26
+ });
27
+
28
+ L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
29
+ attribution: '&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
30
+ }).addTo(map);
31
+
32
+ var endpoints = $('#geocoded_events').data('geocoded-events');
33
+ const popupProposalsTemplateId = "marker-popup-proposal";
34
+ $.template(popupProposalsTemplateId, $(`#${popupProposalsTemplateId}`).html());
35
+ const popupMeetingsTemplateId = "marker-popup-meeting";
36
+ $.template(popupMeetingsTemplateId, $(`#${popupMeetingsTemplateId}`).html());
37
+
38
+ const randomColor = () => '#'+Math.floor(Math.random()*16777215).toString(16);
39
+
40
+ const getMarker = (id, point, color) => {
41
+ let coordinates = [point.latitude, point.longitude];
42
+ let marker = L.marker(coordinates, {
43
+ icon: new L.DivIcon.SVGIcon.DecidimIcon({fillColor: color})
44
+ });
45
+
46
+ let node = document.createElement("div");
47
+
48
+ $.tmpl(id, point).appendTo(node);
49
+ marker.bindPopup(node, {
50
+ maxWidth: 640,
51
+ minWidth: 500,
52
+ keepInView: true,
53
+ className: "map-info"
54
+ }).openPopup();
55
+
56
+ return marker;
57
+ };
58
+
59
+ let layers = {};
60
+
61
+ for (let endpoint in endpoints) {
62
+
63
+ // In the future the color should come from the assigned to the endpoint
64
+ let color = randomColor();
65
+ let markerClusters = L.markerClusterGroup({
66
+ iconCreateFunction: function (cluster) {
67
+ var childCount = cluster.getChildCount();
68
+
69
+ return new L.DivIcon({ html: '<div style="background-color:' + color +'"><span>' + childCount + '</span></div>', className: 'marker-cluster', iconSize: new L.Point(40, 40) });
70
+
71
+ }
72
+ });
73
+
74
+ let meetings = endpoints[endpoint].meetings;
75
+ let proposals = endpoints[endpoint].proposals;
76
+
77
+ for(let key in meetings) {
78
+ markerClusters.addLayer(getMarker(popupMeetingsTemplateId, meetings[key], color));
79
+ }
80
+
81
+ for(let key in proposals) {
82
+ markerClusters.addLayer(getMarker(popupProposalsTemplateId, proposals[key], color));
83
+ }
84
+ markerClusters.addTo(map);
85
+ let key = '<span class="endpoint-legend"><span class="square" style="background-color:' + color +'"></span>' + endpoints[endpoint].name + '</span>';
86
+ layers[key] = markerClusters;
87
+ }
88
+
89
+ L.control.layers(null, layers).addTo(map);
90
+
91
+ $("[data-tabs]").on('change.zf.tabs', function() {
92
+ map.invalidateSize(true);
93
+ });
94
+ });
@@ -0,0 +1,13 @@
1
+ // = require chartkick
2
+ // = require Chart.bundle
3
+ // = require_self
4
+
5
+ $(() => {
6
+ //create trigger to resizeEnd event
7
+ $(window).resize(() => {
8
+ if(window.resizeTO) clearTimeout(window.resizeTO);
9
+ window.resizeTO = setTimeout(() => {
10
+ $(window).trigger('resizeEnd');
11
+ }, 100);
12
+ });
13
+ });
@@ -0,0 +1,23 @@
1
+ @import "graphs";
2
+ @import "decidim/modules/cards";
3
+ @import "decidim/modules/address";
4
+ @import "decidim/modules/buttons";
5
+ @import "decidim/modules/map";
6
+ @import "decidim/extras/leaflet";
7
+
8
+ #geocoded_events{
9
+ min-height: 360px;
10
+ height: 100%;
11
+
12
+ .endpoint-legend{
13
+ font-size: .8rem;
14
+ line-height: .8;
15
+
16
+ .square{
17
+ display: inline-block;
18
+ width: .9em;
19
+ height: .9em;
20
+ margin-right: .3em;
21
+ }
22
+ }
23
+ }
@@ -0,0 +1,6 @@
1
+ @import "decidim/variables";
2
+ @import "decidim/utils/settings";
3
+ @import "decidim/utils/mixins";
4
+ @import "decidim/modules/typography";
5
+ @import "decidim/modules/margins";
6
+ @import "decidim/modules/buttons";
@@ -0,0 +1,8 @@
1
+ html,
2
+ body{
3
+ height: 100%;
4
+ }
5
+
6
+ .full-height{
7
+ height: calc(100% - 1.5rem);
8
+ }
@@ -0,0 +1,14 @@
1
+ <div class="row small-up-1 smallmedium-up-2 mediumlarge-up-3 large-up-4 card-grid">
2
+ <% metrics.each do |name, metric| %>
3
+ <div class="column" style="padding: 1em">
4
+ <div class="card">
5
+ <div class="card-divider">
6
+ <%= title name %>
7
+ </div>
8
+ <div class="card-section">
9
+ <%= pie_chart metric, id: "pie_chart_#{name}" %>
10
+ </div>
11
+ </div>
12
+ </div>
13
+ <% end %>
14
+ </div>
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "chartkick"
4
+ require "chartkick/helper"
5
+
6
+ module Decidim
7
+ module ComparativeStats
8
+ class MetricPiechartsCell < Decidim::ViewModel
9
+ include Chartkick::Helper
10
+
11
+ def show
12
+ return unless model
13
+
14
+ render :show
15
+ end
16
+
17
+ def endpoints
18
+ model
19
+ end
20
+
21
+ def title(name)
22
+ return t "decidim.comparative_stats.metrics.users.title" if name == "users"
23
+
24
+ t "decidim.metrics.#{name}.title"
25
+ end
26
+
27
+ def metrics
28
+ metrics = {}
29
+ endpoints.each do |endpoint|
30
+ endpoint.api.fetch_global_metrics.data.metrics.each do |item|
31
+ metrics[item.name] ||= {}
32
+ metrics[item.name][endpoint.name] = item.count
33
+ end
34
+ end
35
+ metrics
36
+ end
37
+ end
38
+ end
39
+ end