easy_data_tables 0.1.1 → 0.2.0
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.
- checksums.yaml +4 -4
- data/Gemfile.lock +1 -1
- data/README.md +24 -8
- data/Rakefile +15 -3
- data/app/assets/stylesheets/easy_data_tables/application.css +5 -0
- data/app/helpers/easy_data_tables/table_helper.rb +15 -0
- data/app/models/easy_data_tables/column.rb +48 -0
- data/app/models/easy_data_tables/combined_column.rb +37 -0
- data/app/models/easy_data_tables/data_table.rb +39 -0
- data/app/views/easy_data_tables/_data_table.html.erb +61 -3
- data/app/views/easy_data_tables/_download_links.html.erb +5 -0
- data/easy_data_tables.gemspec +1 -1
- data/lib/easy_data_tables.rb +0 -3
- data/lib/easy_data_tables/version.rb +1 -1
- metadata +7 -5
- data/app/helpers/table_helper.rb +0 -13
- data/app/models/column.rb +0 -46
- data/app/models/combined_column.rb +0 -35
- data/app/models/data_table.rb +0 -37
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f9f6075dc6b932de890fbe28050a1b6d3b417d5576e601ccb97b695cedffcc84
|
4
|
+
data.tar.gz: '09d60e1ba17eac10c7760bf908912d37b56cdda590543a9075938d55f8e1cc10'
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 67d03e29ff2f7725c8da4492f75ad4a6d3be78de093fe1e54fc1fc71775614e5075b2c731ffda8b835cfc515f6b0590a8e252952612fbd4cf97148bd3dce3d06
|
7
|
+
data.tar.gz: 3f59f1c2fd4302981e88af92ac01318b6634a046a93fc7703477ecafa58b82e3530fa8ac86328dcca937d3c20080786b58c58c5f53db470a0e1ebb18dd15dde1
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -2,6 +2,8 @@
|
|
2
2
|
|
3
3
|
This gem provides a way to create fast tables based on the models of your db. It will expose a helper method `easy_data_table(columns, rows, grouping)`that will output a datatable with the rows and the columns you indicated.
|
4
4
|
|
5
|
+
Two links above and below the table will allow you to export it on csv format
|
6
|
+
|
5
7
|
## Installation
|
6
8
|
|
7
9
|
Add this line to your application's Gemfile:
|
@@ -24,6 +26,11 @@ Or install it yourself as:
|
|
24
26
|
|
25
27
|
You will have a method available once you install this gem: `easy_data_table(columns, rows, grouping)` in order to expose it, you need to add `helper EasyDataTables::Engine.helpers` to your app's ApplicationController. You can call this helper method in any view and it will output a table with the data you provide.
|
26
28
|
|
29
|
+
In order to access the style of the application add:
|
30
|
+
`@import "easy_data_tables/application";`
|
31
|
+
|
32
|
+
to your `application.scss`
|
33
|
+
|
27
34
|
### Parameters
|
28
35
|
|
29
36
|
#### Columns
|
@@ -108,14 +115,18 @@ in order to have correct looking column labels you must have a I18n file that wi
|
|
108
115
|
en:
|
109
116
|
easy_data_tables:
|
110
117
|
data_table:
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
118
|
+
user_count: User count
|
119
|
+
user_count_title: "Count of all the users that have the row's status"
|
120
|
+
active_user_count: Active User Count
|
121
|
+
active_user_count_title: Active users for each status
|
122
|
+
active_user_expense: Active User Expense
|
123
|
+
active_user_expense_title: Sum of the expenses for the active users of each status
|
124
|
+
active_user_rate: Active User Rate
|
125
|
+
active_user_rate_title: % of active users over total users per status
|
126
|
+
download_links:
|
127
|
+
download_formated_csv: Download Formated CSV
|
128
|
+
download_unformated_csv: Download Unformated CSV
|
129
|
+
|
119
130
|
```
|
120
131
|
|
121
132
|
On hover on a column label, you will have the title that appears as a tooltip.
|
@@ -141,3 +152,8 @@ Bug reports and pull requests are welcome on GitHub at https://github.com/pabloc
|
|
141
152
|
## License
|
142
153
|
|
143
154
|
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
155
|
+
|
156
|
+
## Changelog
|
157
|
+
|
158
|
+
### v 0.2.0
|
159
|
+
- added possibility of downloading the table as a csv (both formated and unformated)
|
data/Rakefile
CHANGED
@@ -1,8 +1,20 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'bundler/setup'
|
4
|
+
|
5
|
+
APP_RAKEFILE = File.expand_path('test/dummy/Rakefile', __dir__)
|
6
|
+
load 'rails/tasks/engine.rake'
|
7
|
+
|
8
|
+
load 'rails/tasks/statistics.rake'
|
9
|
+
|
3
10
|
require 'bundler/gem_tasks'
|
4
|
-
require 'rspec/core/rake_task'
|
5
11
|
|
6
|
-
|
12
|
+
require 'rake/testtask'
|
13
|
+
|
14
|
+
Rake::TestTask.new(:test) do |t|
|
15
|
+
t.libs << 'test'
|
16
|
+
t.pattern = 'test/**/*_test.rb'
|
17
|
+
t.verbose = false
|
18
|
+
end
|
7
19
|
|
8
|
-
task default: :
|
20
|
+
task default: :test
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module EasyDataTables
|
4
|
+
# Creates and exposes the helper method
|
5
|
+
module TableHelper
|
6
|
+
def easy_data_table(columns, label, grouping)
|
7
|
+
data_table = DataTable.new(
|
8
|
+
columns,
|
9
|
+
label,
|
10
|
+
grouping
|
11
|
+
)
|
12
|
+
render 'easy_data_tables/data_table', data_table: data_table
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module EasyDataTables
|
4
|
+
# Column class, we can access the formated data and the data of a particular cell
|
5
|
+
class Column
|
6
|
+
attr_reader :label
|
7
|
+
|
8
|
+
# values = {}, label = '', type = 'Integer')
|
9
|
+
def initialize(args = {})
|
10
|
+
@label = args[:label] || ''
|
11
|
+
@type = args[:type] || 'Integer'
|
12
|
+
@default = args[:default] || 0
|
13
|
+
@collection = args[:collection]
|
14
|
+
@grouping = args[:grouping]
|
15
|
+
@agregate_function = args[:agregate_function]
|
16
|
+
@values = construct_values
|
17
|
+
end
|
18
|
+
|
19
|
+
def formated_data_at(row)
|
20
|
+
case @type
|
21
|
+
when 'Integer'
|
22
|
+
helpers.number_with_delimiter(data_at(row))
|
23
|
+
when 'Percentage'
|
24
|
+
helpers.number_to_percentage(data_at(row), precision: 2)
|
25
|
+
when 'Currency'
|
26
|
+
helpers.number_to_currency(data_at(row))
|
27
|
+
else
|
28
|
+
data_at(row)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def data_at(row)
|
33
|
+
@values[row]
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
def construct_values
|
39
|
+
Hash.new(@default)
|
40
|
+
.merge(@collection.send(*@grouping).send(*@agregate_function))
|
41
|
+
.merge({ 'TOTAL' => @collection.send(*@agregate_function) })
|
42
|
+
end
|
43
|
+
|
44
|
+
def helpers
|
45
|
+
ActionController::Base.helpers
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module EasyDataTables
|
4
|
+
# combined columns. can substract and create rates
|
5
|
+
class CombinedColumn < EasyDataTables::Column
|
6
|
+
attr_accessor :columns
|
7
|
+
|
8
|
+
def initialize(args = {})
|
9
|
+
super(args)
|
10
|
+
@columns = args[:columns]
|
11
|
+
@method = args[:method]
|
12
|
+
@type = args[:type]
|
13
|
+
@label = args[:label]
|
14
|
+
end
|
15
|
+
|
16
|
+
def data_at(row)
|
17
|
+
combine(row)
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def combine(row)
|
23
|
+
case @method
|
24
|
+
when 'rate'
|
25
|
+
columns[0].data_at(row).fdiv(columns[1].data_at(row)) * 100
|
26
|
+
when 'substract'
|
27
|
+
columns[0].data_at(row) - columns[1].data_at(row)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def construct_values; end
|
32
|
+
|
33
|
+
def helpers
|
34
|
+
ActionController::Base.helpers
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module EasyDataTables
|
4
|
+
# creates the datatable and it's columns
|
5
|
+
class DataTable
|
6
|
+
attr_reader :columns, :rows, :labels
|
7
|
+
|
8
|
+
def initialize(columns, rows, grouping)
|
9
|
+
@grouping = grouping
|
10
|
+
@rows = rows + ['TOTAL']
|
11
|
+
@columns = treat_columns(columns)
|
12
|
+
@labels = @columns.map(&:label)
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
def treat_columns(columns)
|
18
|
+
convert_columns(columns)
|
19
|
+
columns.map! do |col|
|
20
|
+
if col.is_a?(CombinedColumn)
|
21
|
+
col.columns = columns.find_all { |col2| col.columns.include?(col2.label) }.sort do |column|
|
22
|
+
col.columns.index(column.label)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
col
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def convert_columns(columns)
|
30
|
+
columns.map! do |col|
|
31
|
+
if col[:column_type] == 'combined'
|
32
|
+
CombinedColumn.new(col)
|
33
|
+
else
|
34
|
+
Column.new(col.merge(grouping: @grouping))
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -1,4 +1,5 @@
|
|
1
|
-
|
1
|
+
<%= render 'easy_data_tables/download_links' %>
|
2
|
+
<table class="table datatable" id="easy_data_table" data-controller="datatable">
|
2
3
|
<thead>
|
3
4
|
<tr>
|
4
5
|
<th></th>
|
@@ -16,11 +17,68 @@
|
|
16
17
|
<%= row %>
|
17
18
|
</td>
|
18
19
|
<% data_table.columns.each do |column| %>
|
19
|
-
<td>
|
20
|
+
<td data-unformated-value="<%= column.data_at(row) %>">
|
20
21
|
<%= column.formated_data_at(row) %>
|
21
22
|
</td>
|
22
23
|
<% end %>
|
23
24
|
</tr>
|
24
25
|
<% end %>
|
25
26
|
</tbody>
|
26
|
-
</table>
|
27
|
+
</table>
|
28
|
+
|
29
|
+
<%= render 'easy_data_tables/download_links' %>
|
30
|
+
|
31
|
+
<script>
|
32
|
+
// Quick and simple export target #table_id into a csv
|
33
|
+
function download_unformated_table_as_csv(table_id, separator = ',') {
|
34
|
+
const rows = document.querySelectorAll('table#' + table_id + ' tr');
|
35
|
+
const csv = [];
|
36
|
+
for (let i = 0; i < rows.length; i++) {
|
37
|
+
let row = []
|
38
|
+
let cols = rows[i].querySelectorAll('td, th');
|
39
|
+
for (let j = 0; j < cols.length; j++) {
|
40
|
+
let data;
|
41
|
+
if (cols[j].dataset.unformatedValue) {
|
42
|
+
data = cols[j].dataset.unformatedValue
|
43
|
+
}
|
44
|
+
else {
|
45
|
+
data = cols[j].innerText.replace(/(\r\n|\n|\r)/gm, '').replace(/(\s\s)/gm, ' ')
|
46
|
+
}
|
47
|
+
data = data.replace(/"/g, '""');
|
48
|
+
row.push('"' + data + '"');
|
49
|
+
}
|
50
|
+
csv.push(row.join(separator));
|
51
|
+
}
|
52
|
+
createLink(csv, table_id)
|
53
|
+
}
|
54
|
+
|
55
|
+
function download_formated_table_as_csv(table_id, separator = ',') {
|
56
|
+
const rows = document.querySelectorAll('table#' + table_id + ' tr');
|
57
|
+
const csv = [];
|
58
|
+
for (let i = 0; i < rows.length; i++) {
|
59
|
+
let row = []
|
60
|
+
let cols = rows[i].querySelectorAll('td, th');
|
61
|
+
for (let j = 0; j < cols.length; j++) {
|
62
|
+
let data = cols[j].innerText.replace(/(\r\n|\n|\r)/gm, '').replace(/(\s\s)/gm, ' ')
|
63
|
+
data = data.replace(/"/g, '""');
|
64
|
+
row.push('"' + data + '"');
|
65
|
+
}
|
66
|
+
csv.push(row.join(separator));
|
67
|
+
}
|
68
|
+
createLink(csv, table_id)
|
69
|
+
}
|
70
|
+
|
71
|
+
function createLink(csv, table_id) {
|
72
|
+
const csv_string = csv.join('\n');
|
73
|
+
// Download it
|
74
|
+
const filename = 'export_' + table_id + '_' + new Date().toLocaleDateString() + '.csv';
|
75
|
+
const link = document.createElement('a');
|
76
|
+
link.style.display = 'none';
|
77
|
+
link.setAttribute('target', '_blank');
|
78
|
+
link.setAttribute('href', 'data:text/csv;charset=utf-8,' + encodeURIComponent(csv_string));
|
79
|
+
link.setAttribute('download', filename);
|
80
|
+
document.body.appendChild(link);
|
81
|
+
link.click();
|
82
|
+
document.body.removeChild(link);
|
83
|
+
}
|
84
|
+
</script>
|
@@ -0,0 +1,5 @@
|
|
1
|
+
<div class="easy-data-tables__links">
|
2
|
+
<a href="#" onclick="download_unformated_table_as_csv('easy_data_table');"><%= t('.download_unformated_csv') %></a>
|
3
|
+
<span> | </span>
|
4
|
+
<a href="#" onclick="download_formated_table_as_csv('easy_data_table');"><%= t('.download_formated_csv') %></a>
|
5
|
+
</div>
|
data/easy_data_tables.gemspec
CHANGED
@@ -14,7 +14,7 @@ Gem::Specification.new do |spec|
|
|
14
14
|
spec.license = 'MIT'
|
15
15
|
spec.required_ruby_version = Gem::Requirement.new('>= 2.4.0')
|
16
16
|
|
17
|
-
spec.metadata['allowed_push_host'] =
|
17
|
+
spec.metadata['allowed_push_host'] = 'https://rubygems.org/'
|
18
18
|
|
19
19
|
spec.metadata['homepage_uri'] = spec.homepage
|
20
20
|
spec.metadata['source_code_uri'] = 'https://github.com/pablocm90/easy_data_tables'
|
data/lib/easy_data_tables.rb
CHANGED
@@ -1,10 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'easy_data_tables/version'
|
4
|
-
# require "app/helpers/helper"
|
5
4
|
require 'easy_data_tables/engine'
|
6
|
-
# require "easy_data_tables/models/column"
|
7
|
-
# require "easy_data_tables/models/combined_column"
|
8
5
|
|
9
6
|
module EasyDataTables
|
10
7
|
class Error < StandardError; end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: easy_data_tables
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Pablo Curell
|
@@ -26,11 +26,13 @@ files:
|
|
26
26
|
- LICENSE.txt
|
27
27
|
- README.md
|
28
28
|
- Rakefile
|
29
|
-
- app/
|
30
|
-
- app/
|
31
|
-
- app/models/
|
32
|
-
- app/models/
|
29
|
+
- app/assets/stylesheets/easy_data_tables/application.css
|
30
|
+
- app/helpers/easy_data_tables/table_helper.rb
|
31
|
+
- app/models/easy_data_tables/column.rb
|
32
|
+
- app/models/easy_data_tables/combined_column.rb
|
33
|
+
- app/models/easy_data_tables/data_table.rb
|
33
34
|
- app/views/easy_data_tables/_data_table.html.erb
|
35
|
+
- app/views/easy_data_tables/_download_links.html.erb
|
34
36
|
- bin/rails
|
35
37
|
- easy_data_tables.gemspec
|
36
38
|
- lib/easy_data_tables.rb
|
data/app/helpers/table_helper.rb
DELETED
@@ -1,13 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
# Creates and exposes the helper method
|
4
|
-
module TableHelper
|
5
|
-
def easy_data_table(columns, label, grouping)
|
6
|
-
data_table = DataTable.new(
|
7
|
-
columns,
|
8
|
-
label,
|
9
|
-
grouping
|
10
|
-
)
|
11
|
-
render 'easy_data_tables/data_table', data_table: data_table
|
12
|
-
end
|
13
|
-
end
|
data/app/models/column.rb
DELETED
@@ -1,46 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
# Column class, we can access the formated data and the data of a particular cell
|
4
|
-
class Column
|
5
|
-
attr_reader :label
|
6
|
-
|
7
|
-
# values = {}, label = '', type = 'Integer')
|
8
|
-
def initialize(args = {})
|
9
|
-
@label = args[:label] || ''
|
10
|
-
@type = args[:type] || 'Integer'
|
11
|
-
@default = args[:default] || 0
|
12
|
-
@collection = args[:collection]
|
13
|
-
@grouping = args[:grouping]
|
14
|
-
@agregate_function = args[:agregate_function]
|
15
|
-
@values = construct_values
|
16
|
-
end
|
17
|
-
|
18
|
-
def formated_data_at(row)
|
19
|
-
case @type
|
20
|
-
when 'Integer'
|
21
|
-
helpers.number_with_delimiter(data_at(row))
|
22
|
-
when 'Percentage'
|
23
|
-
helpers.number_to_percentage(data_at(row), precision: 2)
|
24
|
-
when 'Currency'
|
25
|
-
helpers.number_to_currency(data_at(row))
|
26
|
-
else
|
27
|
-
data_at(row)
|
28
|
-
end
|
29
|
-
end
|
30
|
-
|
31
|
-
def data_at(row)
|
32
|
-
@values[row]
|
33
|
-
end
|
34
|
-
|
35
|
-
private
|
36
|
-
|
37
|
-
def construct_values
|
38
|
-
Hash.new(@default)
|
39
|
-
.merge(@collection.send(*@grouping).send(*@agregate_function))
|
40
|
-
.merge({ 'TOTAL' => @collection.send(*@agregate_function) })
|
41
|
-
end
|
42
|
-
|
43
|
-
def helpers
|
44
|
-
ActionController::Base.helpers
|
45
|
-
end
|
46
|
-
end
|
@@ -1,35 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
# combined columns. can substract and create rates
|
4
|
-
class CombinedColumn < Column
|
5
|
-
attr_accessor :columns
|
6
|
-
|
7
|
-
def initialize(args = {})
|
8
|
-
super(args)
|
9
|
-
@columns = args[:columns]
|
10
|
-
@method = args[:method]
|
11
|
-
@type = args[:type]
|
12
|
-
@label = args[:label]
|
13
|
-
end
|
14
|
-
|
15
|
-
def data_at(row)
|
16
|
-
combine(row)
|
17
|
-
end
|
18
|
-
|
19
|
-
private
|
20
|
-
|
21
|
-
def combine(row)
|
22
|
-
case @method
|
23
|
-
when 'rate'
|
24
|
-
columns[0].data_at(row).fdiv(columns[1].data_at(row)) * 100
|
25
|
-
when 'substract'
|
26
|
-
columns[0].data_at(row) - columns[1].data_at(row)
|
27
|
-
end
|
28
|
-
end
|
29
|
-
|
30
|
-
def construct_values; end
|
31
|
-
|
32
|
-
def helpers
|
33
|
-
ActionController::Base.helpers
|
34
|
-
end
|
35
|
-
end
|
data/app/models/data_table.rb
DELETED
@@ -1,37 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
# creates the datatable and it's columns
|
4
|
-
class DataTable
|
5
|
-
attr_reader :columns, :rows, :labels
|
6
|
-
|
7
|
-
def initialize(columns, rows, grouping)
|
8
|
-
@grouping = grouping
|
9
|
-
@rows = rows + ['TOTAL']
|
10
|
-
@columns = treat_columns(columns)
|
11
|
-
@labels = @columns.map(&:label)
|
12
|
-
end
|
13
|
-
|
14
|
-
private
|
15
|
-
|
16
|
-
def treat_columns(columns)
|
17
|
-
convert_columns(columns)
|
18
|
-
columns.map! do |col|
|
19
|
-
if col.is_a?(CombinedColumn)
|
20
|
-
col.columns = columns.find_all { |col2| col.columns.include?(col2.label) }.sort do |column|
|
21
|
-
col.columns.index(column.label)
|
22
|
-
end
|
23
|
-
end
|
24
|
-
col
|
25
|
-
end
|
26
|
-
end
|
27
|
-
|
28
|
-
def convert_columns(columns)
|
29
|
-
columns.map! do |col|
|
30
|
-
if col[:column_type] == 'combined'
|
31
|
-
CombinedColumn.new(col)
|
32
|
-
else
|
33
|
-
Column.new(col.merge(grouping: @grouping))
|
34
|
-
end
|
35
|
-
end
|
36
|
-
end
|
37
|
-
end
|