kanaui 0.5.1 → 2.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +15 -9
- data/Rakefile +4 -5
- data/app/assets/javascripts/application.js +1 -1
- data/app/assets/javascripts/kanaui/kiddo/kiddo_initialize.js +1 -1
- data/app/assets/javascripts/kanaui/reports.dataTables.js +74 -2
- data/app/assets/stylesheets/application.css +2 -0
- data/app/assets/stylesheets/bootstrap_and_overrides.css +0 -4
- data/app/assets/stylesheets/kanaui/reports.css +66 -2
- data/app/controllers/kanaui/dashboard_controller.rb +24 -12
- data/app/controllers/kanaui/engine_controller.rb +41 -6
- data/app/controllers/kanaui/reports_controller.rb +15 -12
- data/app/controllers/kanaui/settings_controller.rb +13 -0
- data/app/helpers/kanaui/application_helper.rb +2 -2
- data/app/helpers/kanaui/dashboard_helper.rb +7 -5
- data/app/views/kanaui/dashboard/index.html.erb +153 -125
- data/app/views/kanaui/reports/_form.html.erb +30 -16
- data/app/views/kanaui/reports/_reports_table.html.erb +22 -0
- data/app/views/kanaui/settings/index.html.erb +19 -0
- data/config/routes.rb +11 -8
- data/lib/kanaui.rb +11 -10
- data/lib/kanaui/engine.rb +5 -1
- data/lib/kanaui/version.rb +3 -1
- data/lib/tasks/kanaui_tasks.rake +1 -0
- data/test/dummy/app/assets/config/manifest.js +1 -0
- data/test/dummy/bin/bundle +3 -0
- data/test/dummy/bin/rails +4 -0
- data/test/dummy/bin/rake +4 -0
- data/test/dummy/bin/setup +38 -0
- data/test/dummy/bin/update +29 -0
- data/test/dummy/bin/yarn +11 -0
- data/test/dummy/config/application.rb +15 -47
- data/test/dummy/config/boot.rb +2 -9
- data/test/dummy/config/environment.rb +4 -4
- data/test/dummy/config/environments/development.rb +38 -18
- data/test/dummy/config/environments/production.rb +61 -39
- data/test/dummy/config/environments/test.rb +20 -14
- data/test/dummy/config/initializers/application_controller_renderer.rb +6 -0
- data/test/dummy/config/initializers/assets.rb +14 -0
- data/test/dummy/config/initializers/cookies_serializer.rb +5 -0
- data/test/dummy/config/initializers/filter_parameter_logging.rb +4 -0
- data/test/dummy/config/initializers/inflections.rb +6 -5
- data/test/dummy/config/initializers/killbill_client.rb +3 -3
- data/test/dummy/config/initializers/mime_types.rb +0 -1
- data/test/dummy/config/initializers/new_framework_defaults_5_1.rb +14 -0
- data/test/dummy/config/initializers/wrap_parameters.rb +5 -5
- data/test/dummy/config/locales/en.yml +30 -2
- data/test/dummy/config/secrets.yml +32 -0
- data/test/functional/kanaui/tests_controller_test.rb +2 -0
- data/test/integration/navigation_test.rb +7 -5
- data/test/kanaui_test.rb +3 -1
- data/test/test_helper.rb +7 -7
- data/test/unit/helpers/kanaui/tests_helper_test.rb +2 -0
- metadata +117 -176
- data/app/models/kanaui/dashboard.rb +0 -5
- data/test/dummy/config/database.yml +0 -25
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c634cb242e7d9aef0a4bb937451a57c3f10f0c90
|
4
|
+
data.tar.gz: '08e4e1e1419a230305488420fa8f2f8b69de57a4'
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4e4bd12458f02a2beeddd6b111e89460245bcc24c8d65be1debd3b261eb88dc55ce6a139e7e550e5110c59cc8d63b287805ec47d74ad803849560b97e55a2eb2
|
7
|
+
data.tar.gz: a3d7284429507ddc4b465613407b30ccd3ed118f31b834a7db4846ff1a7b9b416e89f9526e5c2f38a4ee4ed28651f3b3d9d6fe4aa8121a9d2534b18cfe1ae68e
|
data/README.md
CHANGED
@@ -12,7 +12,10 @@ Kill Bill compatibility
|
|
12
12
|
| Kanaui version | Kill Bill version |
|
13
13
|
| -------------: | ----------------: |
|
14
14
|
| 0.4.y | 0.16.z |
|
15
|
-
| 0.5.y | 0.18.z
|
15
|
+
| 0.5.y | 0.18.z (Rails 4) |
|
16
|
+
| 0.6.y | 0.18.z (Rails 5) |
|
17
|
+
| 1.x.y | 0.20.z |
|
18
|
+
| 2.x.y | 0.22.z |
|
16
19
|
|
17
20
|
Getting Started
|
18
21
|
===============
|
@@ -34,15 +37,18 @@ KillBillClient.api_key = 'bob'
|
|
34
37
|
KillBillClient.api_secret = 'lazar'
|
35
38
|
```
|
36
39
|
|
37
|
-
|
38
|
-
|
40
|
+
Testing
|
41
|
+
-------
|
39
42
|
|
40
|
-
|
43
|
+
To run the dummy app:
|
41
44
|
|
42
45
|
```
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
46
|
+
rails s
|
47
|
+
```
|
48
|
+
|
49
|
+
|
50
|
+
To run tests:
|
51
|
+
|
52
|
+
```
|
53
|
+
rails t
|
48
54
|
```
|
data/Rakefile
CHANGED
@@ -1,4 +1,6 @@
|
|
1
1
|
#!/usr/bin/env rake
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
2
4
|
begin
|
3
5
|
require 'bundler/setup'
|
4
6
|
rescue LoadError
|
@@ -20,11 +22,9 @@ RDoc::Task.new(:rdoc) do |rdoc|
|
|
20
22
|
rdoc.rdoc_files.include('lib/**/*.rb')
|
21
23
|
end
|
22
24
|
|
23
|
-
APP_RAKEFILE = File.expand_path(
|
25
|
+
APP_RAKEFILE = File.expand_path('test/dummy/Rakefile', __dir__)
|
24
26
|
load 'rails/tasks/engine.rake'
|
25
27
|
|
26
|
-
|
27
|
-
|
28
28
|
Bundler::GemHelper.install_tasks
|
29
29
|
|
30
30
|
require 'rake/testtask'
|
@@ -36,5 +36,4 @@ Rake::TestTask.new(:test) do |t|
|
|
36
36
|
t.verbose = false
|
37
37
|
end
|
38
38
|
|
39
|
-
|
40
|
-
task :default => :test
|
39
|
+
task default: :test
|
@@ -6,13 +6,13 @@
|
|
6
6
|
//
|
7
7
|
//= require js-routes
|
8
8
|
//= require log4javascript
|
9
|
-
//= require moment
|
10
9
|
//= require spin
|
11
10
|
//= require jquery
|
12
11
|
//= require jquery_ujs
|
13
12
|
//= require twitter/bootstrap
|
14
13
|
//= require dataTables/jquery.dataTables
|
15
14
|
//= require dataTables/bootstrap/3/jquery.dataTables.bootstrap
|
15
|
+
//= require dataTables/extras/dataTables.colVis
|
16
16
|
//= require d3
|
17
17
|
//= require bootstrap-datepicker
|
18
18
|
//= require jquery.spin
|
@@ -40,16 +40,88 @@ ReportsDataTables.prototype.buildTable = function(data, wrapper) {
|
|
40
40
|
}
|
41
41
|
|
42
42
|
var aoColumns = [];
|
43
|
+
var columnsVisible = [];
|
43
44
|
for (var i in data['header']) {
|
44
|
-
|
45
|
+
var isVisible = isColumnVisible(data['header'][i]);
|
46
|
+
aoColumns.push({ "sTitle": data['header'][i], "name": data['header'][i], "visible": isVisible })
|
47
|
+
if (isVisible) {
|
48
|
+
columnsVisible.push(data['header'][i]);
|
49
|
+
}
|
45
50
|
}
|
46
51
|
|
47
52
|
dataTable.dataTable({
|
48
53
|
"aaData": aaData,
|
49
|
-
"aoColumns": aoColumns
|
54
|
+
"aoColumns": aoColumns,
|
55
|
+
"scrollX": true,
|
56
|
+
"sDom": 'C<"clear">lfrtip'
|
50
57
|
});
|
58
|
+
|
59
|
+
dataTable.on( 'column-visibility.dt', function ( e, settings, column, state ) {
|
60
|
+
setColumnVisible(settings.aoColumns[column].name, state);
|
61
|
+
});
|
62
|
+
|
63
|
+
$("#copy-url").click(function(e){
|
64
|
+
var pathPlusParams = $(this).data("reports-path");
|
65
|
+
var sPageURL = decodeURIComponent(pathPlusParams.substring(1)).split('?');
|
66
|
+
var params = sPageURL[1].split('&');
|
67
|
+
|
68
|
+
var columnsVisible = $("#visible-table-columns").val();
|
69
|
+
var placeholder = $("#url-placeholder");
|
70
|
+
|
71
|
+
var urlToShare = window.location.origin + "/" + sPageURL[0] + "?";
|
72
|
+
for (var i in params) {
|
73
|
+
var keyValue = params[i].split('=');
|
74
|
+
if (keyValue[0] == 'columns') {
|
75
|
+
continue;
|
76
|
+
}
|
77
|
+
urlToShare += "&" + params[i];
|
78
|
+
}
|
79
|
+
|
80
|
+
placeholder.val(urlToShare + "&columns=" + columnsVisible);
|
81
|
+
placeholder.removeClass("hidden");
|
82
|
+
placeholder.select();
|
83
|
+
|
84
|
+
document.execCommand("Copy");
|
85
|
+
placeholder.addClass("hidden");
|
86
|
+
alert("URL copied into the clipboard!")
|
87
|
+
});
|
88
|
+
|
89
|
+
$("#visible-table-columns").val(columnsVisible.join());
|
51
90
|
}
|
52
91
|
|
53
92
|
ReportsDataTables.prototype.buildCSVURL = function(position) {
|
54
93
|
return this.reports.buildDataURL(position, 'csv');
|
55
94
|
}
|
95
|
+
function setColumnVisible(column, isVisible) {
|
96
|
+
var columnsVisible = $("#visible-table-columns").val();
|
97
|
+
if (columnsVisible == undefined || columnsVisible == null || columnsVisible.length == 0) {
|
98
|
+
columnsVisible = [];
|
99
|
+
} else {
|
100
|
+
columnsVisible = (columnsVisible).split(",");
|
101
|
+
}
|
102
|
+
|
103
|
+
var columnIndex = columnsVisible.indexOf(column);
|
104
|
+
if (isVisible && columnIndex == -1) {
|
105
|
+
columnsVisible.push(column);
|
106
|
+
} else if (!isVisible && columnIndex != -1) {
|
107
|
+
columnsVisible.splice(columnIndex, 1);
|
108
|
+
}
|
109
|
+
|
110
|
+
$("#visible-table-columns").val(columnsVisible.join());
|
111
|
+
}
|
112
|
+
|
113
|
+
function isColumnVisible(column) {
|
114
|
+
var columnsVisible = $("#visible-table-columns").val();
|
115
|
+
if ((columnsVisible == undefined || columnsVisible == null || columnsVisible.length == 0) && column != 'tenant_record_id') {
|
116
|
+
return true;
|
117
|
+
}
|
118
|
+
columnsVisible = (columnsVisible).split(",");
|
119
|
+
|
120
|
+
for (var i in columnsVisible) {
|
121
|
+
if (columnsVisible[i] == column) {
|
122
|
+
return true;
|
123
|
+
}
|
124
|
+
}
|
125
|
+
|
126
|
+
return false;
|
127
|
+
}
|
@@ -6,6 +6,8 @@
|
|
6
6
|
*= require bootstrap-datepicker3
|
7
7
|
*= require dataTables/jquery.dataTables
|
8
8
|
*= require dataTables/bootstrap/3/jquery.dataTables.bootstrap
|
9
|
+
*= require dataTables/extras/dataTables.colVis
|
10
|
+
*= require font-awesome
|
9
11
|
*= require bootstrap_and_overrides
|
10
12
|
*= require kanaui/kanaui
|
11
13
|
*/
|
@@ -1,9 +1,5 @@
|
|
1
1
|
/*
|
2
2
|
*= require twitter-bootstrap-static/bootstrap
|
3
|
-
*
|
4
|
-
* Use Font Awesome icons (default)
|
5
|
-
* To use Glyphicons sprites instead of Font Awesome, replace with "require twitter-bootstrap-static/sprites"
|
6
|
-
*= require twitter-bootstrap-static/fontawesome
|
7
3
|
*/
|
8
4
|
|
9
5
|
/* Override Bootstrap 3 font locations */
|
@@ -1,5 +1,10 @@
|
|
1
|
-
#
|
2
|
-
|
1
|
+
#reports-table th, #reports-table td,
|
2
|
+
#dataTable-api_wrapper th, #dataTable-api_wrapper td {
|
3
|
+
white-space: nowrap;
|
4
|
+
}
|
5
|
+
|
6
|
+
.sql-query {
|
7
|
+
word-break: break-word;
|
3
8
|
}
|
4
9
|
|
5
10
|
.axis path,
|
@@ -92,3 +97,62 @@
|
|
92
97
|
.grid path{
|
93
98
|
stroke-width: 0;
|
94
99
|
}
|
100
|
+
|
101
|
+
button.ColVis_Button, button.ColVis_Button:hover {
|
102
|
+
background: inherit;
|
103
|
+
box-shadow: unset;
|
104
|
+
text-transform: none;
|
105
|
+
color: #333 !important;
|
106
|
+
border-color: #adadad;
|
107
|
+
}
|
108
|
+
|
109
|
+
ul.ColVis_collection {
|
110
|
+
background-color: #f3f3f3;
|
111
|
+
}
|
112
|
+
|
113
|
+
ul.ColVis_collection li, ul.ColVis_collection li:hover{
|
114
|
+
border: none;
|
115
|
+
box-shadow: unset;
|
116
|
+
background: transparent;
|
117
|
+
}
|
118
|
+
|
119
|
+
button.ColVis_Button:hover, ul.ColVis_collection li:hover {
|
120
|
+
background-color: #e6e6e6;
|
121
|
+
border-color: #adadad;
|
122
|
+
}
|
123
|
+
|
124
|
+
.dataTables_wrapper .dataTables_paginate .paginate_button {
|
125
|
+
padding: 0.25em 0.5em;
|
126
|
+
}
|
127
|
+
|
128
|
+
.flex-panel {
|
129
|
+
display: -webkit-flex;
|
130
|
+
display: flex;
|
131
|
+
-webkit-flex-direction: row;
|
132
|
+
flex-direction: row;
|
133
|
+
}
|
134
|
+
|
135
|
+
.flex-inner-left-panel {
|
136
|
+
-ms-flex: 1 .5 0%;
|
137
|
+
-webkit-flex: 1 .5 0%;
|
138
|
+
flex: 1 .5 0%;
|
139
|
+
}
|
140
|
+
|
141
|
+
.flex-inner-left-panel ul li {
|
142
|
+
white-space: nowrap;
|
143
|
+
}
|
144
|
+
|
145
|
+
.flex-inner-right-panel {
|
146
|
+
-ms-flex: .5 1 70%;
|
147
|
+
-webkit-flex: .5 1 70%;
|
148
|
+
flex: .5 1 70%;
|
149
|
+
overflow: scroll;
|
150
|
+
}
|
151
|
+
|
152
|
+
#date-picker .form-group {
|
153
|
+
height: 34px;
|
154
|
+
}
|
155
|
+
|
156
|
+
#table-tools {
|
157
|
+
padding-bottom: 10px;
|
158
|
+
}
|
@@ -1,6 +1,7 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Kanaui
|
2
4
|
class DashboardController < Kanaui::EngineController
|
3
|
-
|
4
5
|
#
|
5
6
|
# Load the dashboard by rendering the view and executing the javascript that will call
|
6
7
|
# the reports and available_reports endpoints below.
|
@@ -20,25 +21,34 @@ module Kanaui
|
|
20
21
|
|
21
22
|
query = build_slice_and_dice_query
|
22
23
|
|
24
|
+
# get columns visibility from query parameters to be used by tables
|
25
|
+
@visible_columns = params[:columns]
|
26
|
+
|
23
27
|
# Redirect also in case the dates have been updated to avoid any confusion in the view
|
24
28
|
if query.present? || params[:start_date].blank? || params[:end_date].blank?
|
25
|
-
# TODO Make metrics configurable
|
29
|
+
# TODO: Make metrics configurable
|
26
30
|
name = query.present? ? "#{params[:name]}#{query}^metric:count" : params[:name]
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
31
|
+
query_params = { start_date: @start_date,
|
32
|
+
end_date: @end_date,
|
33
|
+
name: name,
|
34
|
+
smooth: params[:smooth],
|
35
|
+
sql_only: params[:sql_only],
|
36
|
+
format: params[:format] }
|
37
|
+
|
38
|
+
# Test only
|
39
|
+
query_params[:fake] = params[:fake] unless params[:fake].blank?
|
40
|
+
query_params[:type] = params[:type] unless params[:type].blank?
|
41
|
+
|
42
|
+
redirect_to dashboard_index_path(query_params) and return
|
33
43
|
end
|
34
44
|
|
35
|
-
|
45
|
+
params.permit!
|
36
46
|
end
|
37
47
|
|
38
48
|
# Not used anymore as reports are pulled from index
|
39
49
|
def available_reports
|
40
50
|
available_reports = Kanaui::DashboardHelper::DashboardApi.available_reports(options_for_klient)
|
41
|
-
render :
|
51
|
+
render json: available_reports
|
42
52
|
end
|
43
53
|
|
44
54
|
def reports
|
@@ -57,7 +67,7 @@ module Kanaui
|
|
57
67
|
else
|
58
68
|
reports = raw_reports
|
59
69
|
end
|
60
|
-
render :
|
70
|
+
render json: reports
|
61
71
|
end
|
62
72
|
|
63
73
|
private
|
@@ -108,6 +118,7 @@ module Kanaui
|
|
108
118
|
filter_query = ''
|
109
119
|
filters.each do |k, v|
|
110
120
|
next if v.blank?
|
121
|
+
|
111
122
|
filter_query << '%26' unless filter_query.blank?
|
112
123
|
filter_query << "(#{k}=#{v.join("|#{k}=")})"
|
113
124
|
end
|
@@ -115,7 +126,8 @@ module Kanaui
|
|
115
126
|
|
116
127
|
groups.each do |k, v|
|
117
128
|
next if v.blank?
|
118
|
-
|
129
|
+
|
130
|
+
# TODO: Make "no other" configurable
|
119
131
|
query << "^dimension:#{k}(#{v.join('|')}|-)"
|
120
132
|
end
|
121
133
|
|
@@ -1,6 +1,7 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Kanaui
|
2
4
|
class EngineController < ApplicationController
|
3
|
-
|
4
5
|
layout :get_layout
|
5
6
|
|
6
7
|
def get_layout
|
@@ -17,12 +18,46 @@ module Kanaui
|
|
17
18
|
def options_for_klient
|
18
19
|
user = current_tenant_user
|
19
20
|
{
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
21
|
+
username: user[:username],
|
22
|
+
password: user[:password],
|
23
|
+
session_id: user[:session_id],
|
24
|
+
api_key: user[:api_key],
|
25
|
+
api_secret: user[:api_secret]
|
25
26
|
}
|
26
27
|
end
|
28
|
+
|
29
|
+
rescue_from(KillBillClient::API::ResponseError) do |killbill_exception|
|
30
|
+
flash[:error] = "Error while communicating with the Kill Bill server: #{as_string(killbill_exception)}"
|
31
|
+
redirect_to dashboard_index_path
|
32
|
+
end
|
33
|
+
|
34
|
+
def as_string(e)
|
35
|
+
if e.is_a?(KillBillClient::API::ResponseError)
|
36
|
+
"Error #{e.response.code}: #{as_string_from_response(e.response.body)}"
|
37
|
+
else
|
38
|
+
log_rescue_error(e)
|
39
|
+
e.message
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def log_rescue_error(error)
|
44
|
+
Rails.logger.warn "#{error.class} #{error}. #{error.backtrace.join("\n")}"
|
45
|
+
end
|
46
|
+
|
47
|
+
def as_string_from_response(response)
|
48
|
+
error_message = response
|
49
|
+
begin
|
50
|
+
# BillingExceptionJson?
|
51
|
+
error_message = JSON.parse response
|
52
|
+
rescue StandardError => _e
|
53
|
+
end
|
54
|
+
|
55
|
+
if error_message.respond_to?(:[]) && error_message['message'].present?
|
56
|
+
# Likely BillingExceptionJson
|
57
|
+
error_message = error_message['message']
|
58
|
+
end
|
59
|
+
# Limit the error size to avoid ActionDispatch::Cookies::CookieOverflow
|
60
|
+
error_message[0..1000]
|
61
|
+
end
|
27
62
|
end
|
28
63
|
end
|
@@ -1,6 +1,7 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Kanaui
|
2
4
|
class ReportsController < Kanaui::EngineController
|
3
|
-
|
4
5
|
def index
|
5
6
|
@reports = JSON.parse(Kanaui::DashboardHelper::DashboardApi.available_reports(options_for_klient)).map(&:deep_symbolize_keys)
|
6
7
|
end
|
@@ -13,7 +14,7 @@ module Kanaui
|
|
13
14
|
Kanaui::DashboardHelper::DashboardApi.create_report(report_from_params.to_json, options_for_klient)
|
14
15
|
|
15
16
|
flash[:notice] = 'Report successfully created'
|
16
|
-
redirect_to :
|
17
|
+
redirect_to action: :index
|
17
18
|
end
|
18
19
|
|
19
20
|
def edit
|
@@ -26,34 +27,36 @@ module Kanaui
|
|
26
27
|
Kanaui::DashboardHelper::DashboardApi.update_report(params.require(:id), report_from_params.to_json, options_for_klient)
|
27
28
|
|
28
29
|
flash[:notice] = 'Report successfully updated'
|
29
|
-
redirect_to :
|
30
|
+
redirect_to action: :index
|
30
31
|
end
|
31
32
|
|
32
33
|
def refresh
|
33
34
|
Kanaui::DashboardHelper::DashboardApi.refresh_report(params.require(:id), options_for_klient)
|
34
35
|
|
35
36
|
flash[:notice] = 'Report refresh successfully scheduled'
|
36
|
-
redirect_to :
|
37
|
+
redirect_to action: :index
|
37
38
|
end
|
38
39
|
|
39
40
|
def destroy
|
40
41
|
Kanaui::DashboardHelper::DashboardApi.delete_report(params.require(:id), options_for_klient)
|
41
42
|
|
42
43
|
flash[:notice] = 'Report successfully deleted'
|
43
|
-
redirect_to :
|
44
|
+
redirect_to action: :index
|
44
45
|
end
|
45
46
|
|
46
47
|
private
|
47
48
|
|
48
49
|
def report_from_params
|
49
50
|
{
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
51
|
+
reportName: params[:report_name],
|
52
|
+
reportPrettyName: params[:report_pretty_name],
|
53
|
+
reportType: params[:report_type],
|
54
|
+
sourceTableName: params[:source_table_name],
|
55
|
+
sourceName: params[:source_name],
|
56
|
+
sourceQuery: params[:source_query],
|
57
|
+
refreshProcedureName: params[:refresh_procedure_name],
|
58
|
+
refreshFrequency: params[:refresh_frequency].presence,
|
59
|
+
refreshHourOfDayGmt: params[:refresh_hour_of_day_gmt]
|
57
60
|
}
|
58
61
|
end
|
59
62
|
end
|