reporta-modules 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (81) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.md +203 -0
  4. data/Rakefile +20 -0
  5. data/lib/generators/reporta/views_generator.rb +24 -0
  6. data/lib/generators/templates/reports/_box.html.erb +48 -0
  7. data/lib/generators/templates/reports/_chartjs_bar.html.erb +31 -0
  8. data/lib/generators/templates/reports/_chartjs_line.html.erb +33 -0
  9. data/lib/generators/templates/reports/_chartjs_pie.html.erb +19 -0
  10. data/lib/generators/templates/reports/_filters.html.erb +100 -0
  11. data/lib/generators/templates/reports/_table.html.erb +49 -0
  12. data/lib/reporta-modules.rb +15 -0
  13. data/lib/reporta/box_helper.rb +17 -0
  14. data/lib/reporta/chartjs_helper.rb +74 -0
  15. data/lib/reporta/models/column.rb +68 -0
  16. data/lib/reporta/models/filter.rb +42 -0
  17. data/lib/reporta/models/form.rb +77 -0
  18. data/lib/reporta/models/reportable.rb +50 -0
  19. data/lib/reporta/railtie.rb +8 -0
  20. data/lib/reporta/version.rb +3 -0
  21. data/lib/reporta/view_helper.rb +38 -0
  22. data/lib/tasks/reporta_tasks.rake +4 -0
  23. data/spec/dummy/README.rdoc +28 -0
  24. data/spec/dummy/Rakefile +6 -0
  25. data/spec/dummy/app/assets/javascripts/application.js +18 -0
  26. data/spec/dummy/app/assets/javascripts/jquery.dataTables.js +12099 -0
  27. data/spec/dummy/app/assets/javascripts/jquery.flot.js +3061 -0
  28. data/spec/dummy/app/assets/javascripts/jquery.flot.time.js +431 -0
  29. data/spec/dummy/app/assets/javascripts/jquery.js +2 -0
  30. data/spec/dummy/app/assets/stylesheets/application.css +14 -0
  31. data/spec/dummy/app/assets/stylesheets/bootstrap.min.css +9 -0
  32. data/spec/dummy/app/assets/stylesheets/style.css +57 -0
  33. data/spec/dummy/app/controllers/application_controller.rb +3 -0
  34. data/spec/dummy/app/controllers/reports_controller.rb +18 -0
  35. data/spec/dummy/app/helpers/application_helper.rb +5 -0
  36. data/spec/dummy/app/models/account.rb +3 -0
  37. data/spec/dummy/app/models/account_chart.rb +41 -0
  38. data/spec/dummy/app/models/account_report.rb +39 -0
  39. data/spec/dummy/app/models/user.rb +8 -0
  40. data/spec/dummy/app/views/layouts/application.html.erb +28 -0
  41. data/spec/dummy/app/views/reports/chart.html.erb +6 -0
  42. data/spec/dummy/app/views/reports/dynamic_table.html.erb +33 -0
  43. data/spec/dummy/app/views/reports/dynamic_table_with_bootstrap.html.erb +37 -0
  44. data/spec/dummy/app/views/reports/overview.html.erb +4 -0
  45. data/spec/dummy/app/views/reports/table.html.erb +12 -0
  46. data/spec/dummy/bin/bundle +3 -0
  47. data/spec/dummy/bin/rails +4 -0
  48. data/spec/dummy/bin/rake +4 -0
  49. data/spec/dummy/config.ru +4 -0
  50. data/spec/dummy/config/application.rb +23 -0
  51. data/spec/dummy/config/boot.rb +5 -0
  52. data/spec/dummy/config/database.yml +25 -0
  53. data/spec/dummy/config/environment.rb +5 -0
  54. data/spec/dummy/config/environments/development.rb +29 -0
  55. data/spec/dummy/config/environments/production.rb +80 -0
  56. data/spec/dummy/config/environments/test.rb +36 -0
  57. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  58. data/spec/dummy/config/initializers/filter_parameter_logging.rb +4 -0
  59. data/spec/dummy/config/initializers/inflections.rb +16 -0
  60. data/spec/dummy/config/initializers/mime_types.rb +5 -0
  61. data/spec/dummy/config/initializers/secret_token.rb +12 -0
  62. data/spec/dummy/config/initializers/session_store.rb +3 -0
  63. data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
  64. data/spec/dummy/config/locales/en.yml +23 -0
  65. data/spec/dummy/config/routes.rb +7 -0
  66. data/spec/dummy/db/migrate/20130622041213_create_users.rb +14 -0
  67. data/spec/dummy/db/migrate/20130623054801_create_accounts.rb +9 -0
  68. data/spec/dummy/db/schema.rb +33 -0
  69. data/spec/dummy/db/seeds.rb +20 -0
  70. data/spec/dummy/db/test.sqlite3 +0 -0
  71. data/spec/dummy/log/test.log +1190 -0
  72. data/spec/dummy/public/404.html +58 -0
  73. data/spec/dummy/public/422.html +58 -0
  74. data/spec/dummy/public/500.html +57 -0
  75. data/spec/dummy/public/favicon.ico +0 -0
  76. data/spec/models/column_spec.rb +76 -0
  77. data/spec/models/filter_spec.rb +63 -0
  78. data/spec/models/form_spec.rb +81 -0
  79. data/spec/models/report_spec.rb +51 -0
  80. data/spec/spec_helper.rb +43 -0
  81. metadata +247 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 24231287130d42d72c0e84992b2bea414f81289b
4
+ data.tar.gz: 6d19674561f3ae544758cb1f11ddbb096429f471
5
+ SHA512:
6
+ metadata.gz: 25052bfc227fda62f69bb12aba5b783b9a74681153c4c2922b8c013c866a67f11a598d356f39e2411887356797a700465cbd1cbd821538ea6f7fe159c1ca0bec
7
+ data.tar.gz: 74616e062c0781180563f51f2fa82c4bd75a6df85e15afb5e16e3c9108bb8f1e48224444173191e397700acc53c68f4d0823309c6187b2ea8abf3b3dc7e6a1ff
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright 2014 Alvin S.J. Ng
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,203 @@
1
+ # Reporta Modules
2
+
3
+ __reporta-modules__ is a Rails gem packed with modules and helpers to help you build your reports.
4
+
5
+ It is also a fork from the original [__reporta__](github.com/uts/reporta) Rails engine gem.
6
+
7
+ ## Installation
8
+
9
+ Add Reporta to your Gemfile
10
+
11
+ ```ruby
12
+ gem 'reporta-modules'
13
+ ```
14
+
15
+ Generate default view templates in your project
16
+ `$ rails generate reporta:views`
17
+
18
+ Turn any plain Ruby class into a Reporta class by including `Reporta::Reportable`
19
+
20
+ ```ruby
21
+ class YourReport
22
+ include Reporta::Reportable
23
+ end
24
+ ```
25
+
26
+ ## Basic Example
27
+
28
+ ### View Model
29
+
30
+ ```ruby
31
+ class ProjectReport
32
+ include Reporta::Reportable
33
+
34
+ filter :start_date, default: '2013-01-01', required: true
35
+ filter :finish_date, default: '2013-12-13', required: true
36
+
37
+ column :name
38
+ column :created_at
39
+
40
+ def rows
41
+ Project.where(created_at: start_date..finish_date)
42
+ end
43
+ end
44
+ ```
45
+
46
+ ### Controller
47
+
48
+ ```ruby
49
+ class ProjectReportsController < ApplicationController
50
+ def show
51
+ @report = ProjectsReport.new(params[:reporta_form])
52
+ end
53
+ end
54
+ ```
55
+
56
+ ### View
57
+
58
+ ```erb
59
+ <%= filters_for @report %>
60
+ <%= table_for @report %>
61
+ ```
62
+
63
+
64
+
65
+ ## Reporta Modules
66
+
67
+ ### Reporta::Reportable
68
+
69
+ `Reporta::Reportable` module added some DSL for your covenience to create your report's [__view model/object__](http://blog.codeclimate.com/blog/2012/10/17/7-ways-to-decompose-fat-activerecord-models/).
70
+
71
+ #### Filters
72
+
73
+ Report are normally generated based on some filter or a certain criteria.
74
+ For example:
75
+
76
+ ```ruby
77
+ class ProjectReport
78
+ include Reporta::Reportable
79
+
80
+ filter :start_date, as: :date, default: '2013-01-01', required: true
81
+ filter :finish_date, as: :date, default: '2013-12-31', required: true
82
+ filter :status, collection: Status.all, include_blank: false
83
+ filter :exclude_deleted, as: :boolean, default: false
84
+
85
+ # required method
86
+ def rows
87
+ # use filters above to manipulate the results
88
+ projects = Project.where(created_at: start_date..finish_date)
89
+ .where(status: status)
90
+ projects = projects.where(deleted_at: nil) if exclude_deleted
91
+ projects
92
+ end
93
+ end
94
+ ```
95
+
96
+ **Filter Options**
97
+
98
+ * `required` - set to `true` to force a field to be set. Defaults to `false`.
99
+ * `collection` - setting a collection will force the filter to render as a select input.
100
+ * `include_blank` - only has an affect if a collection is set. defaults to `true`.
101
+ * `as` - set the type of field to render. Available values are `:boolean`, `:string`, `:check_boxes`, `:radio`, `:date`. Defaults to `:string`.
102
+ * `default` - set the default value for the filter.
103
+ * `label` - set the label of display
104
+
105
+ #### Columns
106
+
107
+ When is comes to displaying the report you will generally want to display a subset of data from the rows, custom calculations or maybe some associated data. Here's a quick example of defining a variety of columns.
108
+
109
+ ```ruby
110
+ class ProjectReport
111
+ include Reporta::Reportable
112
+
113
+ column :name
114
+ column :formatted_date, title: 'Created at'
115
+ column :manager, data_chain: 'manager.full_name'
116
+ column :cost, class_names: 'sum currency'
117
+
118
+ def rows
119
+ Projects.all
120
+ end
121
+
122
+ def formatted_date(project)
123
+ project.created_at.strftime("%b %d, %Y")
124
+ end
125
+ end
126
+ ```
127
+
128
+ **Column Options**
129
+
130
+ * `title` - set a custom title for the colum. Defaults to the column name
131
+ * `data_chain` - provide a chain of methods to call in order to fetch the data.
132
+ * `class_names` - these classes will be applied to the column to allow for custom styling or Javascript hooks.
133
+ * `helper` - format your column
134
+
135
+ ### Required Methods
136
+
137
+ As a very minimum you need to define the `rows` method which will return the rows that are displayed in the report.
138
+
139
+ ```ruby
140
+ class ProjectReport
141
+ include Reporta::Reportable
142
+
143
+ def rows
144
+ Project.all
145
+ end
146
+ end
147
+ ```
148
+
149
+
150
+ #### Default View Templates
151
+
152
+ In order to render the results of your report there are a variety of different ways to access and display the data. If you have any filters defined you will probably want to display a form for the user to enter parameters into.
153
+
154
+ The `filters_for` helper generates a basic form based on the filters you have defined.
155
+
156
+ ```erb
157
+ <%= filters_for @report %>
158
+ ```
159
+ If we look at how `filters_for` is created you can see the underlying data structures used to render the form.
160
+
161
+ ```erb
162
+ <%= form_for @report.form do |f| %>
163
+ <% @report.filters.each do |filter| %>
164
+ <%= f.label filter.name %>
165
+ <%= f.text_field filter.name %>
166
+ <% end %>
167
+ <%= f.submit %>
168
+ <% end %>
169
+ ```
170
+ To display the results of the report you can simply use the `table_for` helper method.
171
+
172
+ ```erb
173
+ <%= table_for @report %>
174
+ ```
175
+ Or for more detailed control you can build the table yourself.
176
+
177
+ ```erb
178
+ <table>
179
+ <thead>
180
+ <tr>
181
+ <% @report.columns.each do |column| %>
182
+ <th class="#{column.class_names}">
183
+ <%= column.title %>
184
+ </th>
185
+ <% end %>
186
+ </tr>
187
+ </thead>
188
+ <tbody>
189
+ <% @report.rows.each do |record| %>
190
+ <tr>
191
+ <% @report.columns.each do |column| %>
192
+ <th class="#{column.class_names}">
193
+ <%= @report.value_for(record, column) %>
194
+ </th>
195
+ <% end %>
196
+ </tr>
197
+ <% end %>
198
+ </tbody>
199
+ </table>
200
+ ```
201
+
202
+ ## License
203
+ see MIT-LICENSE
data/Rakefile ADDED
@@ -0,0 +1,20 @@
1
+ begin
2
+ require 'bundler/setup'
3
+ rescue LoadError
4
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
5
+ end
6
+
7
+ APP_RAKEFILE = File.expand_path("../spec/dummy/Rakefile", __FILE__)
8
+ load 'rails/tasks/engine.rake'
9
+
10
+ Bundler::GemHelper.install_tasks
11
+
12
+ require 'rake/testtask'
13
+
14
+ Rake::TestTask.new(:test) do |t|
15
+ t.libs = ["lib", "spec"]
16
+ t.test_files = FileList['spec/**/*_spec.rb']
17
+ end
18
+
19
+
20
+ task default: :test
@@ -0,0 +1,24 @@
1
+ require 'rails/generators/base'
2
+
3
+ module Reporta
4
+ module Generators
5
+ class ViewsGenerator < Rails::Generators::Base
6
+ source_root File.expand_path("../../templates", __FILE__)
7
+ public_task :copy_views
8
+
9
+ def copy_views
10
+ view_directory :reports
11
+ end
12
+
13
+ def view_directory(name, _target_path = nil)
14
+ directory name.to_s, _target_path || "#{target_path}/#{name}" do |content|
15
+ content
16
+ end
17
+ end
18
+
19
+ def target_path
20
+ @target_path ||= "app/views/reporta"
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,48 @@
1
+ <div class="well">
2
+ <div class="reporta-box">
3
+ <span class="box-icon <%=report.icon_bg %>" >
4
+ <!-- uses FontAwesome -->
5
+ <i class="fa <%=report.fa_icon %>"></i>
6
+ </span>
7
+ <span class="box-info">
8
+ <p class="value"><%= raw report.value %></p>
9
+ <p class="title"><%= raw report.description %></p>
10
+ </span>
11
+ </div>
12
+ </div>
13
+ <!--
14
+ <style>
15
+ .reporta-box .box-icon{
16
+ display: block;
17
+ float: left;
18
+ margin: 0 10px 10px 0;
19
+ width: 65px;
20
+ height: 65px;
21
+ border-radius: 50%;
22
+ vertical-align: middle;
23
+ text-align: center;
24
+ font-size: 35px;
25
+ line-height: 65px;
26
+ }
27
+ .reporta-box i.fa{
28
+ line-height: 35px;
29
+ text-align:center;
30
+ color: white;
31
+ }
32
+
33
+ .reporta-box .box-info p{
34
+ margin:0;
35
+ }
36
+
37
+ .reporta-box .box-info .value{
38
+ color: #767676;
39
+ font-size: 30px;
40
+ }
41
+
42
+ .reporta-box .box-info .title{
43
+ color: #999999;
44
+ font-size: 14px;
45
+ }
46
+ </style>
47
+ -->
48
+
@@ -0,0 +1,31 @@
1
+ <canvas id="<%=prefix.to_s.camelize %>BarChart"></canvas>
2
+ <% content_for :script do %>
3
+ // uses JQuery
4
+ $(function(){
5
+ "use strict";
6
+ var data = {
7
+ labels : <%=raw labels_from_rows(rows, x).to_json %>,
8
+ datasets : [
9
+ <% y = [y] if !y.is_a?(Array) %>
10
+ <% lines = y.map do |k|
11
+ "{
12
+ fillColor : '#{color}',
13
+ strokeColor : '#{color}',
14
+ pointColor : '#{color}',
15
+ pointStrokeColor : '#fff',
16
+ data : #{raw decimals_from_rows(rows, x, k).to_json}
17
+ }"
18
+ end.join(',') %>
19
+ <%=raw lines %>
20
+ ]
21
+ };
22
+
23
+ var ctx = document.getElementById("<%=prefix.to_s.camelize %>BarChart").getContext("2d");
24
+
25
+ // uses Chartjs
26
+ var chart = new Chart(ctx).Bar(data, {responsive: true});
27
+ <%= yield :chartjs_script %>
28
+ });
29
+
30
+ <% end %>
31
+
@@ -0,0 +1,33 @@
1
+ <canvas id="<%=prefix.to_s.camelize %>LineChart"></canvas>
2
+ <% content_for :script do %>
3
+
4
+ // uses JQuery
5
+ $(function(){
6
+ "use strict";
7
+
8
+ var data = {
9
+ labels : <%=raw labels_from_rows(rows, x).to_json %>,
10
+ datasets : [
11
+ <% y = [y] if !y.is_a?(Array) %>
12
+ <% lines = y.map do |k|
13
+ "{
14
+ fillColor : '#{color}',
15
+ strokeColor : '#{color}',
16
+ pointColor : '#{color}',
17
+ pointStrokeColor : '#fff',
18
+ data : #{raw decimals_from_rows(rows, x, k).to_json}
19
+ }"
20
+ end.join(',') %>
21
+ <%=raw lines %>
22
+ ]
23
+ };
24
+
25
+ var ctx = document.getElementById("<%=prefix.to_s.camelize %>LineChart").getContext("2d");
26
+
27
+ // uses Chartjs
28
+ var chart = new Chart(ctx).Line(data, {responsive: true});
29
+ <%= yield :chartjs_script %>
30
+ });
31
+
32
+ <% end %>
33
+
@@ -0,0 +1,19 @@
1
+ <div class="col-md-6">
2
+ <canvas id="<%=prefix.to_s.camelize %>PieChart" ></canvas>
3
+ </div>
4
+ <div class="col-md-6">
5
+ <div id="<%=prefix.to_s.camelize%>PieChartLegend"></div>
6
+ </div>
7
+ <% chart = chart_pie_from_rows(rows, x, y) %>
8
+ <% content_for :script do %>
9
+ $(function(){
10
+ "use strict";
11
+
12
+ var data = <%=raw chart[:datasets] %>;
13
+ var ctx = document.getElementById("<%=prefix.to_s.camelize %>PieChart").getContext("2d");
14
+ var chart = new Chart(ctx).Pie(data, {responsive: true});
15
+ $('#<%=prefix.to_s.camelize %>PieChartLegend').html(chart.generateLegend());
16
+ <%= yield :chartjs_script %>
17
+ });
18
+ <% end %>
19
+
@@ -0,0 +1,100 @@
1
+ <!--
2
+ Copyright 2013-2014 University of Technology, Sydney (github.com/uts)
3
+
4
+ Permission is hereby granted, free of charge, to any person obtaining
5
+ a copy of this software and associated documentation files (the
6
+ "Software"), to deal in the Software without restriction, including
7
+ without limitation the rights to use, copy, modify, merge, publish,
8
+ distribute, sublicense, and/or sell copies of the Software, and to
9
+ permit persons to whom the Software is furnished to do so, subject to
10
+ the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be
13
+ included in all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
+ -->
23
+
24
+ <%= form_for report.form, url: request.path, html:{class: 'form-horizontal well'} do |f| %>
25
+ <%
26
+ non_advanced = report.filters.select{|k,o| !o.advanced}
27
+ advanced = report.filters.select{|k,o| o.advanced }
28
+ %>
29
+ <% [non_advanced, advanced].each do |filters| %>
30
+ <div id="<%=raw('form-advanced" style="display:none') if filters == advanced%>">
31
+ <% filters.each do |name, options| %>
32
+
33
+ <% label_name = options.label || ("#{name.to_s.humanize} #{'*' if options.required}") %>
34
+ <div class='form-group'>
35
+ <%#Collection field%>
36
+ <% if options.collection %>
37
+ <%= f.label name, label_name, class: 'col-sm-2 control-label' %>
38
+ <div class='col-sm-10'>
39
+ <% html_opts = options.include_blank ? {include_blank: options.include_blank} : {} %>
40
+ <%= f.select name, options_for_select(options.collection, f.object.send(name)), html_opts, required: options.required, multiple: options.multiple%>
41
+ </div>
42
+
43
+ <%#Boolean field%>
44
+ <% elsif options.boolean? %>
45
+ <div class="col-sm-offset-2 col-sm-10">
46
+ <label>
47
+ <%= f.check_box name %> <%=label_name %>
48
+ </label>
49
+ </div>
50
+
51
+ <%#Date field%>
52
+ <% elsif options.as == :date %>
53
+ <%= f.label name, label_name, class: 'col-sm-2 control-label text-left' %>
54
+ <div class="col-sm-10">
55
+ <%= f.text_field name, required: options.required, class: "#{name}-datepicker" %>
56
+ </div>
57
+ <!--
58
+ // uses JQuery
59
+ $(function(){
60
+ // uses JQueryUI
61
+ $('input.<%=name.to_s%>-datepicker').datepicker({
62
+ changeMonth: true, changeYear: true, dateFormat: 'yy-mm-dd'
63
+ });
64
+ });
65
+ -->
66
+
67
+ <%#Text field%>
68
+ <% else %>
69
+ <%= f.label name, label_name, class: 'col-sm-2 control-label text-left' %>
70
+ <div class="col-sm-10">
71
+ <%= f.text_field name, required: options.required %>
72
+ </div>
73
+ <% end %>
74
+ </div>
75
+
76
+ <% if report.form.errors[name].any? %>
77
+ <%= report.form.errors[name].to_sentence %>
78
+ <% end %>
79
+ <% end %>
80
+ </div>
81
+
82
+ <% if advanced.present? && non_advanced == filters %>
83
+ <div class="form-group">
84
+ <div class="col-sm-offset-2 col-sm-10">
85
+ <a href="#" id='toggle-advanced'>Show Advanced Options</a>
86
+ </div>
87
+ </div>
88
+ <% end %>
89
+
90
+ <% end %>
91
+
92
+ <div class="form-group">
93
+ <div class="col-sm-offset-2 col-sm-10">
94
+ <%= f.button 'Apply', class: 'btn btn-primary' %>
95
+ <%= link_to 'Reset all', request.original_url, class: 'btn btn-default' %>
96
+ </div>
97
+ </div>
98
+
99
+ <% end %>
100
+