effective_datatables 3.7.10 → 4.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (69) hide show
  1. checksums.yaml +5 -5
  2. data/MIT-LICENSE +1 -1
  3. data/README.md +32 -32
  4. data/app/assets/images/dataTables/sort-down.svg +1 -0
  5. data/app/assets/images/dataTables/sort-up.svg +1 -0
  6. data/app/assets/images/dataTables/sort.svg +1 -0
  7. data/app/assets/javascripts/dataTables/buttons/{buttons.bootstrap.js → buttons.bootstrap4.js} +7 -15
  8. data/app/assets/javascripts/dataTables/dataTables.bootstrap4.js +184 -0
  9. data/app/assets/javascripts/dataTables/responsive/dataTables.responsive.js +30 -11
  10. data/app/assets/javascripts/dataTables/responsive/{responsive.bootstrap.js → responsive.bootstrap4.js} +6 -6
  11. data/app/assets/javascripts/effective_datatables/bulk_actions.js.coffee +43 -43
  12. data/app/assets/javascripts/effective_datatables/events.js.coffee +7 -4
  13. data/app/assets/javascripts/effective_datatables/filters.js.coffee +0 -1
  14. data/app/assets/javascripts/effective_datatables/initialize.js.coffee +45 -49
  15. data/app/assets/javascripts/effective_datatables/overrides.js +12 -0
  16. data/app/assets/javascripts/effective_datatables/reset.js.coffee +1 -1
  17. data/app/assets/javascripts/effective_datatables.js +4 -4
  18. data/app/assets/stylesheets/dataTables/buttons/{buttons.bootstrap.scss → buttons.bootstrap4.css} +68 -1
  19. data/app/assets/stylesheets/dataTables/{dataTables.bootstrap.scss → dataTables.bootstrap4.css} +44 -29
  20. data/app/assets/stylesheets/dataTables/responsive/{responsive.bootstrap.scss → responsive.bootstrap4.css} +3 -3
  21. data/app/assets/stylesheets/effective_datatables/_overrides.scss +72 -152
  22. data/app/assets/stylesheets/effective_datatables.scss +3 -4
  23. data/app/controllers/effective/datatables_controller.rb +6 -39
  24. data/app/helpers/effective_datatables_helper.rb +55 -50
  25. data/app/helpers/effective_datatables_private_helper.rb +47 -179
  26. data/app/models/effective/datatable.rb +16 -44
  27. data/app/models/effective/datatable_column.rb +0 -1
  28. data/app/models/effective/datatable_column_tool.rb +2 -4
  29. data/app/models/effective/datatable_dsl_tool.rb +3 -11
  30. data/app/models/effective/datatable_value_tool.rb +23 -23
  31. data/app/models/effective/effective_datatable/attributes.rb +13 -5
  32. data/app/models/effective/effective_datatable/collection.rb +3 -18
  33. data/app/models/effective/effective_datatable/compute.rb +6 -17
  34. data/app/models/effective/effective_datatable/cookie.rb +20 -19
  35. data/app/models/effective/effective_datatable/dsl/bulk_actions.rb +25 -14
  36. data/app/models/effective/effective_datatable/dsl/datatable.rb +28 -70
  37. data/app/models/effective/effective_datatable/dsl/filters.rb +5 -5
  38. data/app/models/effective/effective_datatable/dsl.rb +3 -8
  39. data/app/models/effective/effective_datatable/format.rb +50 -95
  40. data/app/models/effective/effective_datatable/params.rb +3 -8
  41. data/app/models/effective/effective_datatable/resource.rb +76 -137
  42. data/app/models/effective/effective_datatable/state.rb +15 -30
  43. data/app/views/effective/datatables/_actions_column.html.haml +8 -1
  44. data/app/views/effective/datatables/_bulk_actions_column.html.haml +1 -1
  45. data/app/views/effective/datatables/_filters.html.haml +11 -12
  46. data/app/views/effective/datatables/_resource_column.html.haml +8 -11
  47. data/config/effective_datatables.rb +14 -12
  48. data/config/routes.rb +0 -1
  49. data/lib/effective_datatables/engine.rb +4 -14
  50. data/lib/effective_datatables/version.rb +1 -1
  51. data/lib/effective_datatables.rb +4 -57
  52. metadata +20 -31
  53. data/app/assets/config/effective_datatables_manifest.js +0 -3
  54. data/app/assets/images/dataTables/sort_asc.png +0 -0
  55. data/app/assets/images/dataTables/sort_both.png +0 -0
  56. data/app/assets/images/dataTables/sort_desc.png +0 -0
  57. data/app/assets/javascripts/dataTables/dataTables.bootstrap.js +0 -182
  58. data/app/assets/javascripts/dataTables/locales/en.lang +0 -33
  59. data/app/assets/javascripts/dataTables/locales/es.lang +0 -36
  60. data/app/assets/javascripts/dataTables/locales/nl.lang +0 -30
  61. data/app/assets/javascripts/effective_datatables/flash.js.coffee +0 -31
  62. data/app/assets/javascripts/effective_datatables/inline_crud.js.coffee +0 -217
  63. data/app/assets/javascripts/effective_datatables/overrides.js.coffee +0 -7
  64. data/app/assets/javascripts/effective_datatables/reorder.js.coffee +0 -43
  65. data/app/assets/stylesheets/effective_datatables/_filters.scss +0 -7
  66. data/app/views/effective/datatables/_reorder_column.html.haml +0 -5
  67. data/config/locales/en.yml +0 -12
  68. data/config/locales/es.yml +0 -12
  69. data/config/locales/nl.yml +0 -12
@@ -1,73 +1,91 @@
1
- // Use asset-data-url to prevent 3 additional GET requests for icons
2
- table.dataTable thead .sorting {
3
- background-image: asset-data-url('dataTables/sort_both.png');
4
- background-position: right 0px bottom 14px;
1
+ // Override dataTables.bootstrap4.css defaults
2
+ table.dataTable { border-collapse: collapse !important; }
3
+
4
+ // Override default padding
5
+ table.dataTable thead > tr > th.sorting_asc, table.dataTable thead > tr > th.sorting_desc, table.dataTable thead > tr > th.sorting,
6
+ table.dataTable thead > tr > td.sorting_asc,
7
+ table.dataTable thead > tr > td.sorting_desc,
8
+ table.dataTable thead > tr > td.sorting { padding: 0.5em 0.5em 0.5em 0.5em; }
9
+
10
+ // Override default sort icons
11
+ table.dataTable thead .sorting:before,
12
+ table.dataTable thead .sorting_asc:before,
13
+ table.dataTable thead .sorting_desc:before,
14
+ table.dataTable thead .sorting_asc_disabled:before,
15
+ table.dataTable thead .sorting_desc_disabled:before,
16
+ table.dataTable thead .sorting:after,
17
+ table.dataTable thead .sorting_asc:after,
18
+ table.dataTable thead .sorting_desc:after,
19
+ table.dataTable thead .sorting_asc_disabled:after,
20
+ table.dataTable thead .sorting_desc_disabled:after { content: ''; }
21
+
22
+ table.dataTable > thead th {
23
+ vertical-align: top;
24
+ background-repeat: no-repeat;
25
+
26
+ > span { padding-right: 1rem; }
5
27
  }
6
28
 
7
- table.dataTable thead .sorting_asc {
8
- background-image: asset-data-url('dataTables/sort_asc.png');
9
- background-position: right 0px bottom 14px;
29
+ table.dataTable > thead .sorting {
30
+ background-image: asset-data-url('dataTables/sort.svg');
31
+ background-position: right 0.25rem top 0.25rem;
10
32
  }
11
33
 
12
- table.dataTable thead .sorting_desc {
13
- background-image: asset-data-url('dataTables/sort_desc.png');
14
- background-position: right 0px bottom 14px;
34
+ table.dataTable > thead .sorting_asc {
35
+ background-image: asset-data-url('dataTables/sort-up.svg');
36
+ background-position: right 0.25rem top 0.25rem;
15
37
  }
16
38
 
17
- // Override bootstrap default glyphicons
18
- table.dataTable thead .sorting:after { content: ''; }
19
- table.dataTable thead .sorting_asc:after { content: ''; }
20
- table.dataTable thead .sorting_desc:after { content: ''; }
39
+ table.dataTable > thead .sorting_desc {
40
+ background-image: asset-data-url('dataTables/sort-down.svg');
41
+ background-position: right 0.25rem top 0.25rem;
42
+ }
21
43
 
22
- // Table header
23
- table.dataTable thead > tr > th.sorting_asc,
24
- table.dataTable thead > tr > th.sorting_desc,
25
- table.dataTable thead > tr > th.sorting {
26
- background-repeat: no-repeat;
27
- padding-right: 18px;
44
+ // Collapsed Responsive View
45
+ table.dataTable > tbody > tr.child {
46
+ td, th { border: none; }
47
+
48
+ ul.dtr-details > li {
49
+ border-bottom: none;
50
+ padding-left: 0.5em;
51
+
52
+ &:hover { background-color: rgba(0, 0, 0, 0.075); }
53
+
54
+ span.dtr-title { min-width: 175px; margin-bottom: 0.25em; }
55
+ span.dtr-data { white-space: nowrap; }
56
+ .col-resource_item { margin-bottom: 0.25em; }
57
+ }
58
+ }
59
+
60
+ // Buttons
61
+ .dataTables_buttons {
62
+ text-align: right;
63
+ .btn { font-size: 0.75rem; }
28
64
  }
29
65
 
30
66
  // Search bar
31
- table.dataTable thead {
67
+ table.dataTable > thead {
32
68
  tr th {
33
- text-align: left;
34
- vertical-align: top;
35
69
  border-bottom: none;
36
70
  white-space: nowrap;
37
- padding: 6px;
38
71
 
39
- span { display: block; }
40
- }
72
+ .form-group {
73
+ font-weight: normal;
74
+ margin-bottom: 0em;
41
75
 
42
- .form-control, .form-group {
43
- width: 100%;
44
- font-weight: normal;
45
- margin: 0px;
76
+ input { max-height: 38px; }
77
+ }
46
78
  }
47
-
48
- .datatable_search__bulk_actions { margin-left: 5px; }
49
79
  }
50
80
 
51
81
  // Simple styles
52
- table.dataTable.simple {
53
- thead {
54
- .sorting { background-image: none; cursor: default; }
55
- .sorting_asc { background-image: none; cursor: default; }
56
- .sorting_desc { background-image: none; cursor: default; }
57
-
58
- .form-group { display: none; }
59
- .col-bulk_actions { display: none; }
60
- }
61
- }
82
+ table.dataTable.simple > thead {
83
+ .sorting { background-image: none; cursor: default; }
84
+ .sorting_asc { background-image: none; cursor: default; }
85
+ .sorting_desc { background-image: none; cursor: default; }
62
86
 
63
- // Processing popup
64
- div.dataTables_wrapper div.dataTables_processing {
65
- top: -10px;
66
- border: none;
67
- box-shadow: none;
68
- margin-left: -35%;
69
- margin-bottom: 0;
70
- width: 70%;
87
+ .form-group { display: none; }
88
+ .col-bulk_actions { display: none; }
71
89
  }
72
90
 
73
91
  // Datatables entries
@@ -82,7 +100,7 @@ div.dataTables_wrapper div.dataTables_processing {
82
100
  // Showing 1 to 2 of 2 entries (filtered from 10 total entries)
83
101
  div.dataTables_info {
84
102
  display: inline-block;
85
- padding: 5px 0px 6px 6px;
103
+ padding: 0.25em 0em 0.25em 0.25em;
86
104
  }
87
105
 
88
106
  // with 25 per page
@@ -95,7 +113,7 @@ div.dataTables_wrapper div.dataTables_processing {
95
113
  max-width: 45px;
96
114
 
97
115
  .select2-selection { border: none; }
98
- .select2-selection__rendered { padding: 0px; color: #909090; }
116
+ .select2-selection__rendered { padding: 0em; color: #909090; }
99
117
  }
100
118
 
101
119
  span.select2-container.select2-container--open { max-width: 60px; }
@@ -104,80 +122,8 @@ div.dataTables_wrapper div.dataTables_processing {
104
122
  }
105
123
  }
106
124
 
107
- // Buttons
108
- div.dt-buttons {
109
- float: right;
110
- display: inherit;
111
- width: auto;
112
- }
113
-
114
- .dt-buttons {
115
- a, button {
116
- border: none;
117
- color: #337ab7;
118
- border-color: transparent;
119
- background: #fff;
120
- font-size: 12px;
121
- padding: 6px;
122
- margin-right: 6px;
123
- float: none;
124
-
125
- &:hover,
126
- &:focus {
127
- border: none;
128
- border-color: transparent;
129
- background: #eee !important;
130
- }
131
-
132
- &:last-child { margin-right: 0px; }
133
-
134
- &.active {
135
- color: #fff;
136
- background: #03428d !important;
137
- }
138
-
139
- .caret {
140
- margin-bottom: 4px;
141
- }
142
- }
143
- }
144
-
145
- // Show / hide columns button
146
- ul.dt-button-collection {
147
- width: 400px;
148
-
149
- li {
150
- width: 198px;
151
- overflow: hidden;
152
- }
153
-
154
- li:nth-child(odd) {
155
- float: left;
156
- }
157
-
158
- li:nth-child(even) {
159
- float: right;
160
- }
161
-
162
- .buttons-colvisGroup {
163
- clear: left;
164
- border-top: 1px solid grey;
165
- }
166
-
167
- .buttons-colvisRestore {
168
- border-top: 1px solid grey;
169
- }
170
- }
171
-
172
- // Collapsed Responsive View
173
- table.dataTable > tbody > tr.child {
174
- span.dtr-title { min-width: 175px; margin-bottom: 4px; }
175
- span.dtr-data { white-space: nowrap; }
176
- .col-resource_item { margin-bottom: 4px; }
177
- }
178
-
179
125
  // Column specific adjustments
180
- table.dataTable {
126
+ table.dataTable > tbody {
181
127
  td.col-price { text-align: right; }
182
128
  td.col-decimal { text-align: right; }
183
129
  td.col-right { text-align: right; }
@@ -193,32 +139,6 @@ table.dataTable {
193
139
  td.col-resource_item { word-break: keep-all; }
194
140
 
195
141
  td {
196
- p { margin-bottom: 0px; }
142
+ p { margin-bottom: 0em; }
197
143
  }
198
144
  }
199
-
200
- // Simple styles
201
- table.dataTable.hide-sort > thead {
202
- .sorting { background-image: none; cursor: default; }
203
- .sorting_asc { background-image: none; cursor: default; }
204
- .sorting_desc { background-image: none; cursor: default; }
205
- }
206
-
207
- table.dataTable.hide-search > thead {
208
- .form-group { display: none; }
209
- }
210
-
211
- table.dataTable.hide-buttons {
212
- .col-bulk_actions { display: none; }
213
- }
214
-
215
- // Datatables entries
216
- @media screen and (max-width: 767px) {
217
- div.dataTables_wrapper div.dataTables_entries { text-align: center; }
218
- }
219
-
220
- .dataTables_buttons {
221
- .buttons-bulk-actions {
222
- button { font-size: 12px; }
223
- }
224
- }
@@ -1,7 +1,6 @@
1
- @import 'dataTables/dataTables.bootstrap';
1
+ @import 'dataTables/dataTables.bootstrap4';
2
2
 
3
- @import 'dataTables/buttons/buttons.bootstrap';
4
- @import 'dataTables/responsive/responsive.bootstrap';
3
+ @import 'dataTables/buttons/buttons.bootstrap4';
4
+ @import 'dataTables/responsive/responsive.bootstrap4';
5
5
 
6
- @import 'effective_datatables/filters';
7
6
  @import 'effective_datatables/overrides';
@@ -5,7 +5,7 @@ module Effective
5
5
  # This will respond to both a GET and a POST
6
6
  def show
7
7
  begin
8
- @datatable = EffectiveDatatables.find(params[:id], params[:attributes])
8
+ @datatable = find_datatable(params[:id]).try(:new) || raise('unable to find datatable')
9
9
  @datatable.view = view_context
10
10
 
11
11
  EffectiveDatatables.authorize!(self, :index, @datatable.collection_class)
@@ -13,51 +13,18 @@ module Effective
13
13
  render json: @datatable.to_json
14
14
  rescue => e
15
15
  EffectiveDatatables.authorized?(self, :index, @datatable.try(:collection_class))
16
- render json: error_json(e)
17
16
 
18
- ExceptionNotifier.notify_exception(e) if defined?(ExceptionNotifier)
19
- raise e if Rails.env.development?
17
+ render json: error_json(e)
20
18
  end
21
19
  end
22
20
 
23
- def reorder
24
- begin
25
- @datatable = EffectiveDatatables.find(params[:id], params[:attributes])
26
- @datatable.view = view_context
27
-
28
- EffectiveDatatables.authorize!(self, :index, @datatable.collection_class)
29
-
30
- @resource = @datatable.collection.find(params[:reorder][:id])
31
-
32
- EffectiveDatatables.authorize!(self, :update, @resource)
33
-
34
- attribute = @datatable.columns[:_reorder][:reorder]
35
- old_index = params[:reorder][:old].to_i
36
- new_index = params[:reorder][:new].to_i
37
-
38
- @resource.class.transaction do
39
- if new_index > old_index
40
- @datatable.collection.where("#{attribute} > ? AND #{attribute} <= ?", old_index, new_index).update_all("#{attribute} = #{attribute} - 1")
41
- @resource.update_column(attribute, new_index)
42
- end
43
-
44
- if old_index > new_index
45
- @datatable.collection.where("#{attribute} >= ? AND #{attribute} < ?", new_index, old_index).update_all("#{attribute} = #{attribute} + 1")
46
- @resource.update_column(attribute, new_index)
47
- end
48
- end
49
-
50
- render status: :ok, body: :ok
51
- rescue Effective::AccessDenied => e
52
- render(status: :unauthorized, body: 'Access Denied')
53
- rescue => e
54
- render(status: :error, body: 'Unexpected Error')
55
- end
21
+ private
56
22
 
23
+ def find_datatable(id)
24
+ id = id.to_s.gsub(/-\d{12}\z/, '').gsub('-', '/')
25
+ id.classify.safe_constantize || id.classify.pluralize.safe_constantize
57
26
  end
58
27
 
59
- private
60
-
61
28
  def error_json(e)
62
29
  {
63
30
  data: [],
@@ -1,15 +1,8 @@
1
1
  # These are expected to be called by a developer. They are part of the datatables DSL.
2
2
  module EffectiveDatatablesHelper
3
- def render_datatable(datatable, input_js: {}, buttons: true, charts: true, entries: true, filters: true, inline: false, pagination: true, search: true, simple: false, sort: true)
4
- raise 'expected datatable to be present' unless datatable
5
- raise 'expected input_js to be a Hash' unless input_js.kind_of?(Hash)
6
-
7
- if simple
8
- buttons = charts = entries = filters = pagination = search = sort = false
9
- end
10
3
 
11
- datatable.attributes[:inline] = true if inline
12
- datatable.attributes[:sortable] = false unless sort
4
+ def render_datatable(datatable, input_js: {}, buttons: true, charts: true, filters: true, simple: false)
5
+ raise 'expected datatable to be present' unless datatable
13
6
 
14
7
  datatable.view ||= self
15
8
 
@@ -20,48 +13,29 @@ module EffectiveDatatablesHelper
20
13
  charts = charts && datatable._charts.present?
21
14
  filters = filters && (datatable._scopes.present? || datatable._filters.present?)
22
15
 
23
- html_class = ['effective-datatable', datatable.html_class, ('hide-sort' unless sort), ('hide-search' unless search), ('hide-buttons' unless buttons)].compact.join(' ')
24
-
25
- if datatable.reorder? && !buttons
26
- buttons = true; input_js[:buttons] = false
27
- end
28
-
29
- # Build the datatables DOM option
30
- input_js[:dom] ||= [
31
- ("<'row'<'col-sm-12 dataTables_buttons'B>>" if buttons),
32
- "<'row'<'col-sm-12'tr>>",
33
- ("<'row'" if entries || pagination),
34
- ("<'col-sm-6 dataTables_entries'il>" if entries),
35
- ("<'col-sm-6'p>" if pagination),
36
- (">" if entries || pagination)
37
- ].compact.join
16
+ datatable.attributes[:simple] = true if simple
17
+ input_js[:buttons] = false if simple || !buttons
38
18
 
39
19
  effective_datatable_params = {
40
20
  id: datatable.to_param,
41
- class: html_class,
21
+ class: ('effective-datatable ' + Array(datatable.table_html_class).join(' ')),
42
22
  data: {
43
- 'attributes' => EffectiveDatatables.encrypt(datatable.attributes),
44
- 'authenticity-token' => form_authenticity_token,
45
23
  'bulk-actions' => datatable_bulk_actions(datatable),
46
24
  'columns' => datatable_columns(datatable),
25
+ 'cookie' => datatable.cookie_key,
47
26
  'display-length' => datatable.display_length,
48
- 'display-order' => datatable_display_order(datatable),
27
+ 'display-order' => [datatable.order_index, datatable.order_direction].to_json().html_safe,
49
28
  'display-records' => datatable.to_json[:recordsFiltered],
50
29
  'display-start' => datatable.display_start,
51
- 'inline' => inline.to_s,
52
- 'language' => EffectiveDatatables.language(I18n.locale),
53
- 'options' => input_js.to_json,
54
- 'reset' => (datatable_reset(datatable) if search),
55
- 'reorder' => datatable_reorder(datatable),
56
- 'reorder-index' => (datatable.columns[:_reorder][:index] if datatable.reorder?).to_s,
57
- 'simple' => simple.to_s,
58
- 'spinner' => '', # effective_bootstrap
30
+ 'options' => (input_js || {}).to_json.html_safe,
31
+ 'reset' => datatable_reset(datatable),
32
+ 'simple' => datatable.simple?.to_s,
59
33
  'source' => effective_datatables.datatable_path(datatable, {format: 'json'}),
60
34
  'total-records' => datatable.to_json[:recordsTotal]
61
35
  }
62
36
  }
63
37
 
64
- if (charts || filters)
38
+ if (charts || filters) && !simple
65
39
  output = ''.html_safe
66
40
 
67
41
  if charts
@@ -84,28 +58,59 @@ module EffectiveDatatablesHelper
84
58
  end
85
59
  end
86
60
 
87
- def render_inline_datatable(datatable)
88
- render_datatable(datatable, inline: true)
61
+ def render_simple_datatable(datatable)
62
+ raise 'expected datatable to be present' unless datatable
63
+
64
+ datatable.view ||= self
65
+
66
+ unless EffectiveDatatables.authorized?(controller, :index, datatable.collection_class)
67
+ return content_tag(:p, "You are not authorized to view this datatable. (cannot :index, #{datatable.collection_class})")
68
+ end
69
+
70
+ effective_datatable_params = {
71
+ id: datatable.to_param,
72
+ class: ('effective-datatable simple ' + Array(datatable.table_html_class).join(' ')),
73
+ data: {}
74
+ }
75
+
76
+ render(partial: 'effective/datatables/datatable',
77
+ locals: { datatable: datatable, effective_datatable_params: effective_datatable_params }
78
+ )
89
79
  end
90
80
 
91
- def render_simple_datatable(datatable)
92
- render_datatable(datatable, simple: true)
81
+ def render_datatable_filters(datatable)
82
+ raise 'expected datatable to be present' unless datatable
83
+
84
+ datatable.view ||= self
85
+ return unless datatable._scopes.present? || datatable._filters.present?
86
+
87
+ if datatable._filters_form_required?
88
+ render partial: 'effective/datatables/filters', locals: { datatable: datatable }
89
+ else
90
+ render(partial: 'effective/datatables/filters', locals: { datatable: datatable }).gsub('<form', '<div').gsub('/form>', '/div>').html_safe
91
+ end
92
+
93
93
  end
94
94
 
95
- def inline_datatable?
96
- params[:_datatable_id].present? && params[:_datatable_attributes].present?
95
+ def render_datatable_charts(datatable)
96
+ raise 'expected datatable to be present' unless datatable
97
+
98
+ datatable.view ||= self
99
+ return unless datatable._charts.present?
100
+
101
+ datatable._charts.map { |name, _| render_datatable_chart(datatable, name) }.join.html_safe
97
102
  end
98
103
 
99
- def inline_datatable
100
- return nil unless inline_datatable?
101
- return @_inline_datatable if @_inline_datatable
104
+ def render_datatable_chart(datatable, name)
105
+ raise 'expected datatable to be present' unless datatable
102
106
 
103
- datatable = EffectiveDatatables.find(params[:_datatable_id], params[:_datatable_attributes])
104
- datatable.view = self
107
+ datatable.view ||= self
108
+ return unless datatable._charts[name].present?
105
109
 
106
- EffectiveDatatables.authorize!(self, :index, datatable.collection_class)
110
+ chart = datatable._charts[name]
111
+ chart_data = datatable.to_json[:charts][name][:data]
107
112
 
108
- @_inline_datatable ||= datatable
113
+ render partial: chart[:partial], locals: { datatable: datatable, chart: chart, chart_data: chart_data }
109
114
  end
110
115
 
111
116
  end