activeadmin_dynamic_table 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/Gemfile +8 -0
- data/Gemfile.lock +123 -0
- data/LICENSE.txt +21 -0
- data/README.md +39 -0
- data/Rakefile +4 -0
- data/activeadmin_dynamic_table.gemspec +38 -0
- data/app/assets/javascripts/activeadmin_dynamic_table/config.js +1 -0
- data/app/assets/javascripts/activeadmin_dynamic_table/dynamic_table.js +144 -0
- data/app/assets/stylesheets/activeadmin_dynamic_table/all.scss +42 -0
- data/bin/console +15 -0
- data/bin/setup +8 -0
- data/lib/activeadmin_dynamic_table/column_settings.rb +49 -0
- data/lib/activeadmin_dynamic_table/configurator.rb +92 -0
- data/lib/activeadmin_dynamic_table/setting_string_parser.rb +19 -0
- data/lib/activeadmin_dynamic_table/version.rb +5 -0
- data/lib/activeadmin_dynamic_table/views/index_as_dynamic_table.rb +175 -0
- data/lib/activeadmin_dynamic_table.rb +13 -0
- data/sig/activeadmin_dynamic_table.rbs +4 -0
- metadata +75 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: ec7d176dc20e3cb34be2eae984bf87e6c790a3fa79bc61fde512e27b67ce15c9
|
4
|
+
data.tar.gz: bcc2afb91378be40321f206d2ac9d8d284ed22ad213864d1540f542f090e25f1
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: ab184ef277fda19e363634353292983632793e88009ebdd08a071b9f92c226d1bce53461dc43f9c1f42fa19c4a8f1ef954befcd0370b2723b8c6d73b4667f1cf
|
7
|
+
data.tar.gz: e550f74ca22cd8099454e7790c0119803f8a07bb823282c42b9b7aa6d1249a24e4e4f87e6acc0315e39c7acd06a5e0c08f40920e76337750fd2f44c80ef36436
|
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,123 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
activeadmin_dynamic_table (0.1.0)
|
5
|
+
activeadmin (~> 2.9)
|
6
|
+
|
7
|
+
GEM
|
8
|
+
remote: https://rubygems.org/
|
9
|
+
specs:
|
10
|
+
actionpack (7.0.3)
|
11
|
+
actionview (= 7.0.3)
|
12
|
+
activesupport (= 7.0.3)
|
13
|
+
rack (~> 2.0, >= 2.2.0)
|
14
|
+
rack-test (>= 0.6.3)
|
15
|
+
rails-dom-testing (~> 2.0)
|
16
|
+
rails-html-sanitizer (~> 1.0, >= 1.2.0)
|
17
|
+
actionview (7.0.3)
|
18
|
+
activesupport (= 7.0.3)
|
19
|
+
builder (~> 3.1)
|
20
|
+
erubi (~> 1.4)
|
21
|
+
rails-dom-testing (~> 2.0)
|
22
|
+
rails-html-sanitizer (~> 1.1, >= 1.2.0)
|
23
|
+
activeadmin (2.13.1)
|
24
|
+
arbre (~> 1.2, >= 1.2.1)
|
25
|
+
formtastic (>= 3.1, < 5.0)
|
26
|
+
formtastic_i18n (~> 0.4)
|
27
|
+
inherited_resources (~> 1.7)
|
28
|
+
jquery-rails (~> 4.2)
|
29
|
+
kaminari (~> 1.0, >= 1.2.1)
|
30
|
+
railties (>= 6.1, < 7.1)
|
31
|
+
ransack (>= 2.1.1, < 4)
|
32
|
+
activemodel (7.0.3)
|
33
|
+
activesupport (= 7.0.3)
|
34
|
+
activerecord (7.0.3)
|
35
|
+
activemodel (= 7.0.3)
|
36
|
+
activesupport (= 7.0.3)
|
37
|
+
activesupport (7.0.3)
|
38
|
+
concurrent-ruby (~> 1.0, >= 1.0.2)
|
39
|
+
i18n (>= 1.6, < 2)
|
40
|
+
minitest (>= 5.1)
|
41
|
+
tzinfo (~> 2.0)
|
42
|
+
arbre (1.5.0)
|
43
|
+
activesupport (>= 3.0.0, < 7.1)
|
44
|
+
ruby2_keywords (>= 0.0.2, < 1.0)
|
45
|
+
builder (3.2.4)
|
46
|
+
concurrent-ruby (1.1.10)
|
47
|
+
crass (1.0.6)
|
48
|
+
erubi (1.10.0)
|
49
|
+
formtastic (4.0.0)
|
50
|
+
actionpack (>= 5.2.0)
|
51
|
+
formtastic_i18n (0.7.0)
|
52
|
+
has_scope (0.8.0)
|
53
|
+
actionpack (>= 5.2)
|
54
|
+
activesupport (>= 5.2)
|
55
|
+
i18n (1.8.11)
|
56
|
+
concurrent-ruby (~> 1.0)
|
57
|
+
inherited_resources (1.13.1)
|
58
|
+
actionpack (>= 5.2, < 7.1)
|
59
|
+
has_scope (~> 0.6)
|
60
|
+
railties (>= 5.2, < 7.1)
|
61
|
+
responders (>= 2, < 4)
|
62
|
+
jquery-rails (4.5.0)
|
63
|
+
rails-dom-testing (>= 1, < 3)
|
64
|
+
railties (>= 4.2.0)
|
65
|
+
thor (>= 0.14, < 2.0)
|
66
|
+
kaminari (1.2.2)
|
67
|
+
activesupport (>= 4.1.0)
|
68
|
+
kaminari-actionview (= 1.2.2)
|
69
|
+
kaminari-activerecord (= 1.2.2)
|
70
|
+
kaminari-core (= 1.2.2)
|
71
|
+
kaminari-actionview (1.2.2)
|
72
|
+
actionview
|
73
|
+
kaminari-core (= 1.2.2)
|
74
|
+
kaminari-activerecord (1.2.2)
|
75
|
+
activerecord
|
76
|
+
kaminari-core (= 1.2.2)
|
77
|
+
kaminari-core (1.2.2)
|
78
|
+
loofah (2.18.0)
|
79
|
+
crass (~> 1.0.2)
|
80
|
+
nokogiri (>= 1.5.9)
|
81
|
+
method_source (1.0.0)
|
82
|
+
minitest (5.15.0)
|
83
|
+
nokogiri (1.11.5-arm64-darwin)
|
84
|
+
racc (~> 1.4)
|
85
|
+
racc (1.6.0)
|
86
|
+
rack (2.2.3.1)
|
87
|
+
rack-test (1.1.0)
|
88
|
+
rack (>= 1.0, < 3)
|
89
|
+
rails-dom-testing (2.0.3)
|
90
|
+
activesupport (>= 4.2.0)
|
91
|
+
nokogiri (>= 1.6)
|
92
|
+
rails-html-sanitizer (1.4.2)
|
93
|
+
loofah (~> 2.3)
|
94
|
+
railties (7.0.3)
|
95
|
+
actionpack (= 7.0.3)
|
96
|
+
activesupport (= 7.0.3)
|
97
|
+
method_source
|
98
|
+
rake (>= 12.2)
|
99
|
+
thor (~> 1.0)
|
100
|
+
zeitwerk (~> 2.5)
|
101
|
+
rake (13.0.6)
|
102
|
+
ransack (2.5.0)
|
103
|
+
activerecord (>= 5.2.4)
|
104
|
+
activesupport (>= 5.2.4)
|
105
|
+
i18n
|
106
|
+
responders (3.0.1)
|
107
|
+
actionpack (>= 5.0)
|
108
|
+
railties (>= 5.0)
|
109
|
+
ruby2_keywords (0.0.5)
|
110
|
+
thor (1.2.1)
|
111
|
+
tzinfo (2.0.4)
|
112
|
+
concurrent-ruby (~> 1.0)
|
113
|
+
zeitwerk (2.5.4)
|
114
|
+
|
115
|
+
PLATFORMS
|
116
|
+
arm64-darwin-21
|
117
|
+
|
118
|
+
DEPENDENCIES
|
119
|
+
activeadmin_dynamic_table!
|
120
|
+
rake (~> 13.0)
|
121
|
+
|
122
|
+
BUNDLED WITH
|
123
|
+
2.3.4
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2024 Anton Biliaiev
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
# ActiveadminDynamicTable
|
2
|
+
|
3
|
+
Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/activeadmin_dynamic_table`. To experiment with that code, run `bin/console` for an interactive prompt.
|
4
|
+
|
5
|
+
TODO: Delete this and the text above, and describe your gem
|
6
|
+
|
7
|
+
## Installation
|
8
|
+
|
9
|
+
Add this line to your application's Gemfile:
|
10
|
+
|
11
|
+
```ruby
|
12
|
+
gem 'activeadmin_dynamic_table'
|
13
|
+
```
|
14
|
+
|
15
|
+
And then execute:
|
16
|
+
|
17
|
+
$ bundle install
|
18
|
+
|
19
|
+
Or install it yourself as:
|
20
|
+
|
21
|
+
$ gem install activeadmin_dynamic_table
|
22
|
+
|
23
|
+
## Usage
|
24
|
+
|
25
|
+
TODO: Write usage instructions here
|
26
|
+
|
27
|
+
## Development
|
28
|
+
|
29
|
+
After checking out the repo, run `bin/setup` to install dependencies. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
30
|
+
|
31
|
+
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
32
|
+
|
33
|
+
## Contributing
|
34
|
+
|
35
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/activeadmin_dynamic_table.
|
36
|
+
|
37
|
+
## License
|
38
|
+
|
39
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
data/Rakefile
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "lib/activeadmin_dynamic_table/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |spec|
|
6
|
+
spec.name = "activeadmin_dynamic_table"
|
7
|
+
spec.version = ActiveadminDynamicTable::VERSION
|
8
|
+
spec.authors = ["Anton Biliaiev"]
|
9
|
+
spec.email = ["amdj15@gmail.com"]
|
10
|
+
|
11
|
+
spec.summary = ""
|
12
|
+
spec.description = ""
|
13
|
+
spec.homepage = ""
|
14
|
+
spec.license = "MIT"
|
15
|
+
spec.required_ruby_version = ">= 2.6.0"
|
16
|
+
|
17
|
+
# spec.metadata["allowed_push_host"] = "TODO: Set to your gem server 'https://example.com'"
|
18
|
+
# spec.metadata["homepage_uri"] = spec.homepage
|
19
|
+
# spec.metadata["source_code_uri"] = "TODO: Put your gem's public repo URL here."
|
20
|
+
# spec.metadata["changelog_uri"] = "TODO: Put your gem's CHANGELOG.md URL here."
|
21
|
+
|
22
|
+
# Specify which files should be added to the gem when it is released.
|
23
|
+
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
24
|
+
spec.files = Dir.chdir(File.expand_path(__dir__)) do
|
25
|
+
`git ls-files -z`.split("\x0").reject do |f|
|
26
|
+
(f == __FILE__) || f.match(%r{\A(?:(?:test|spec|features)/|\.(?:git|travis|circleci)|appveyor)})
|
27
|
+
end
|
28
|
+
end
|
29
|
+
spec.bindir = "exe"
|
30
|
+
spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
|
31
|
+
spec.require_paths = ["lib"]
|
32
|
+
|
33
|
+
# Uncomment to register a new dependency of your gem
|
34
|
+
spec.add_dependency "activeadmin", "~> 2.9"
|
35
|
+
|
36
|
+
# For more information and examples about making a new gem, check out our
|
37
|
+
# guide at: https://bundler.io/guides/creating_gem.html
|
38
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
//= require ./dynamic_table
|
@@ -0,0 +1,144 @@
|
|
1
|
+
$(function() {
|
2
|
+
const preferencesBtn = $('th.col-table-preferences');
|
3
|
+
const tableConfig = $('ul.dynamic_table_configuration');
|
4
|
+
|
5
|
+
const columnsPattern = 'th[data-column-key]';
|
6
|
+
const columns = $(columnsPattern);
|
7
|
+
|
8
|
+
if (tableConfig.length) {
|
9
|
+
$('#wrapper').css('display', 'block')
|
10
|
+
}
|
11
|
+
|
12
|
+
function parseSearchString(searchString) {
|
13
|
+
return searchString.split('&').reduce((acc, keyval) => {
|
14
|
+
const [key, value] = keyval.split('=');
|
15
|
+
|
16
|
+
if (!key || !value) {
|
17
|
+
return acc;
|
18
|
+
}
|
19
|
+
|
20
|
+
acc[key] = value;
|
21
|
+
|
22
|
+
return acc;
|
23
|
+
}, {});
|
24
|
+
}
|
25
|
+
|
26
|
+
function stringifyParams(params) {
|
27
|
+
const data = filterEmptyKeys(params);
|
28
|
+
const prefix = '?';
|
29
|
+
const searchString = Object.keys(data).map((key) => [key, data[key]].join('=')).join('&');
|
30
|
+
|
31
|
+
return searchString ? prefix + searchString : '';
|
32
|
+
}
|
33
|
+
|
34
|
+
function columnsConfigString(keys, sizes = {}) {
|
35
|
+
const str = keys.map(key => {
|
36
|
+
if (sizes[key]) {
|
37
|
+
return [key, 'w' + sizes[key]].join(':');
|
38
|
+
}
|
39
|
+
|
40
|
+
return key;
|
41
|
+
}).join(';');
|
42
|
+
|
43
|
+
return encodeURIComponent(str);
|
44
|
+
}
|
45
|
+
|
46
|
+
function getSearchParams() {
|
47
|
+
const searchString = decodeURIComponent(window.location.search).slice(1);
|
48
|
+
|
49
|
+
return parseSearchString(searchString);
|
50
|
+
}
|
51
|
+
|
52
|
+
function getColumnsWidths() {
|
53
|
+
return columns.map(function() {
|
54
|
+
const elem = $(this)
|
55
|
+
|
56
|
+
return {
|
57
|
+
width: elem.width(),
|
58
|
+
key: elem.data('column-key'),
|
59
|
+
};
|
60
|
+
})
|
61
|
+
.toArray()
|
62
|
+
.reduce((acc, item) => Object.assign(acc, { [item.key]: item.width }), {});
|
63
|
+
}
|
64
|
+
|
65
|
+
function filterEmptyKeys(params) {
|
66
|
+
return Object.keys(params).reduce((acc, key) => {
|
67
|
+
if (!params[key]) {
|
68
|
+
return acc;
|
69
|
+
}
|
70
|
+
|
71
|
+
acc[key] = params[key];
|
72
|
+
return acc;
|
73
|
+
}, {});
|
74
|
+
}
|
75
|
+
|
76
|
+
preferencesBtn.on('click', function() {
|
77
|
+
const offset = preferencesBtn.offset();
|
78
|
+
offset.top += preferencesBtn.outerHeight();
|
79
|
+
|
80
|
+
tableConfig.removeClass('hidden').offset(offset);
|
81
|
+
|
82
|
+
return false;
|
83
|
+
});
|
84
|
+
|
85
|
+
document.addEventListener('click', () => {
|
86
|
+
if (!tableConfig.length || tableConfig.hasClass('hidden')) {
|
87
|
+
return;
|
88
|
+
}
|
89
|
+
|
90
|
+
const selected = tableConfig.find('input').filter(function() {
|
91
|
+
return $(this).is(':checked');
|
92
|
+
}).map(function() {
|
93
|
+
return $(this).attr('name');
|
94
|
+
}).toArray();
|
95
|
+
|
96
|
+
const current = $(columnsPattern).map(function() {
|
97
|
+
return $(this).data('column-key');
|
98
|
+
}).toArray().filter(key => selected.includes(key));
|
99
|
+
|
100
|
+
const diff = selected.filter(key => !current.includes(key));
|
101
|
+
|
102
|
+
const columnSizes = getColumnsWidths();
|
103
|
+
const params = Object.assign(getSearchParams(), {
|
104
|
+
columns: columnsConfigString(current.concat(diff), columnSizes),
|
105
|
+
});
|
106
|
+
const searchString = stringifyParams(params);
|
107
|
+
|
108
|
+
tableConfig.addClass('hidden');
|
109
|
+
window.location.search = searchString;
|
110
|
+
});
|
111
|
+
|
112
|
+
tableConfig.on('click', function(event) {
|
113
|
+
event.stopPropagation();
|
114
|
+
});
|
115
|
+
|
116
|
+
columns.resizable({
|
117
|
+
stop: function() {
|
118
|
+
const columnSizes = getColumnsWidths();
|
119
|
+
const params = Object.assign(getSearchParams(), {
|
120
|
+
columns: columnsConfigString(Object.keys(columnSizes), columnSizes),
|
121
|
+
});
|
122
|
+
|
123
|
+
const searchString = stringifyParams(params);
|
124
|
+
window.location.search = searchString;
|
125
|
+
},
|
126
|
+
});
|
127
|
+
|
128
|
+
$('.index_as_dynamic_table thead tr').sortable({
|
129
|
+
axis: 'x',
|
130
|
+
update: function() {
|
131
|
+
const columnSizes = getColumnsWidths();
|
132
|
+
const keys = $(columnsPattern).map(function() {
|
133
|
+
return $(this).data('column-key');
|
134
|
+
}).toArray();
|
135
|
+
|
136
|
+
const params = Object.assign(getSearchParams(), {
|
137
|
+
columns: columnsConfigString(keys, columnSizes),
|
138
|
+
});
|
139
|
+
|
140
|
+
const searchString = stringifyParams(params);
|
141
|
+
window.location.search = searchString;
|
142
|
+
},
|
143
|
+
});
|
144
|
+
});
|
@@ -0,0 +1,42 @@
|
|
1
|
+
.index_as_dynamic_table {
|
2
|
+
position: relative;
|
3
|
+
overflow: auto;
|
4
|
+
|
5
|
+
.hidden {
|
6
|
+
display: none;
|
7
|
+
}
|
8
|
+
|
9
|
+
.col-table-preferences {
|
10
|
+
cursor: pointer;
|
11
|
+
}
|
12
|
+
|
13
|
+
.dynamic_table_configuration {
|
14
|
+
position: absolute;
|
15
|
+
background: #fff;
|
16
|
+
padding: 8px;
|
17
|
+
border: 1px solid #c9d0d6;
|
18
|
+
width: max-content;
|
19
|
+
}
|
20
|
+
|
21
|
+
.dynamic_table {
|
22
|
+
table-layout: fixed;
|
23
|
+
width: min-content;
|
24
|
+
}
|
25
|
+
|
26
|
+
.reorder {
|
27
|
+
cursor: move;
|
28
|
+
}
|
29
|
+
|
30
|
+
th {
|
31
|
+
position: relative;
|
32
|
+
|
33
|
+
.ui-resizable-e {
|
34
|
+
cursor: e-resize;
|
35
|
+
width: 7px;
|
36
|
+
right: -5px;
|
37
|
+
top: 0;
|
38
|
+
height: 100%;
|
39
|
+
position: absolute;
|
40
|
+
}
|
41
|
+
}
|
42
|
+
}
|
data/bin/console
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require "bundler/setup"
|
5
|
+
require "activeadmin_dynamic_table"
|
6
|
+
|
7
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
8
|
+
# with your gem easier. You can also use a different console, if you like.
|
9
|
+
|
10
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
11
|
+
# require "pry"
|
12
|
+
# Pry.start
|
13
|
+
|
14
|
+
require "irb"
|
15
|
+
IRB.start(__FILE__)
|
data/bin/setup
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module ActiveadminDynamicTable
|
3
|
+
class RegisteredColumn
|
4
|
+
attr_reader :key, :args, :block, :config, :method
|
5
|
+
|
6
|
+
def initialize(options)
|
7
|
+
@is_default = options[:is_default]
|
8
|
+
@key = options[:key]
|
9
|
+
@args = options[:args]
|
10
|
+
@block = options[:block]
|
11
|
+
@config = options[:config]
|
12
|
+
@method = options[:method]
|
13
|
+
end
|
14
|
+
|
15
|
+
def default?
|
16
|
+
@is_default
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
class ColumnSettings
|
21
|
+
def initialize(column, options = [])
|
22
|
+
@column = column
|
23
|
+
@options = options
|
24
|
+
end
|
25
|
+
|
26
|
+
def column
|
27
|
+
@column.to_sym
|
28
|
+
end
|
29
|
+
|
30
|
+
def width
|
31
|
+
raw_width = @options.detect { |o| o[0] == 'w' }
|
32
|
+
|
33
|
+
return default_width if raw_width.nil?
|
34
|
+
|
35
|
+
width = raw_width[1..-1]
|
36
|
+
width.to_i if Float(width)
|
37
|
+
rescue
|
38
|
+
default_width
|
39
|
+
end
|
40
|
+
|
41
|
+
def default_width
|
42
|
+
@default_width || 50
|
43
|
+
end
|
44
|
+
|
45
|
+
def default_width=(value)
|
46
|
+
@default_width = value
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,92 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveadminDynamicTable
|
4
|
+
class Configurator
|
5
|
+
def initialize(context, settings)
|
6
|
+
@context = context
|
7
|
+
@settings = settings
|
8
|
+
@api_calls = []
|
9
|
+
end
|
10
|
+
|
11
|
+
def register_column(method, *args, &block)
|
12
|
+
options = args[1] || args[0]
|
13
|
+
|
14
|
+
config = settings_hash[options[:key]] || ColumnSettings.new(options[:key])
|
15
|
+
config.default_width = options[:width]
|
16
|
+
|
17
|
+
api_call = RegisteredColumn.new method: method,
|
18
|
+
key: options[:key],
|
19
|
+
is_default: options[:default],
|
20
|
+
args: args,
|
21
|
+
block: block,
|
22
|
+
config: config
|
23
|
+
|
24
|
+
@api_calls << api_call
|
25
|
+
end
|
26
|
+
|
27
|
+
def columns
|
28
|
+
applicable_columns.each do |applicable_column|
|
29
|
+
next @context.id_column *applicable_column.args if applicable_column.method == :id_column
|
30
|
+
next @context.actions(applicable_column.args[1] || applicable_column.args[0]) if applicable_column.method == :actions
|
31
|
+
next @context.index_column *applicable_column.args if applicable_column.method == :index_column
|
32
|
+
|
33
|
+
# next @context.selectable_column *applicable_column.args if applicable_column.method == :selectable_column
|
34
|
+
|
35
|
+
@context.public_send(applicable_column.method, *applicable_column.args, &applicable_column.block)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def applicable_columns
|
40
|
+
applicable_columns = []
|
41
|
+
|
42
|
+
settings.each do |config|
|
43
|
+
applicable_column = @api_calls.detect do |register_call|
|
44
|
+
register_call.key == config.column
|
45
|
+
end
|
46
|
+
|
47
|
+
applicable_columns << applicable_column if applicable_column.present?
|
48
|
+
end
|
49
|
+
|
50
|
+
applicable_columns
|
51
|
+
end
|
52
|
+
|
53
|
+
def registered_columns
|
54
|
+
@api_calls.map do |api_call|
|
55
|
+
args = api_call.args
|
56
|
+
|
57
|
+
{
|
58
|
+
key: api_call.key,
|
59
|
+
selected: selected?(api_call.key),
|
60
|
+
args: args,
|
61
|
+
}
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def width_for(key)
|
66
|
+
col = settings_hash[key]
|
67
|
+
|
68
|
+
return ColumnSettings.new(nil).width if col.nil?
|
69
|
+
|
70
|
+
col.width
|
71
|
+
end
|
72
|
+
|
73
|
+
private
|
74
|
+
|
75
|
+
def selected?(key)
|
76
|
+
settings_hash[key].present?
|
77
|
+
end
|
78
|
+
|
79
|
+
def settings_hash
|
80
|
+
settings.inject({}) do |acc, item|
|
81
|
+
acc[item.column] = item
|
82
|
+
acc
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
def settings
|
87
|
+
return @settings if @settings.size > 0
|
88
|
+
|
89
|
+
@api_calls.select { |rc| rc.default? }.map { |rc| rc.config }
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module ActiveadminDynamicTable
|
2
|
+
class SettingStringParser
|
3
|
+
def initialize(settings_string)
|
4
|
+
@settings_string = settings_string
|
5
|
+
end
|
6
|
+
|
7
|
+
def parse
|
8
|
+
return [] if @settings_string.nil?
|
9
|
+
|
10
|
+
columns = @settings_string.split(';')
|
11
|
+
|
12
|
+
columns.map do |col|
|
13
|
+
name, *options = col.split(':')
|
14
|
+
|
15
|
+
ColumnSettings.new(name, options)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,175 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveAdmin::Views
|
4
|
+
class IndexAsDynamicTable < IndexAsTable
|
5
|
+
class IndexDynamicTableFor < IndexTableFor
|
6
|
+
def build(configurator, *args, &block)
|
7
|
+
@configurator = configurator
|
8
|
+
super(*args, &block)
|
9
|
+
end
|
10
|
+
|
11
|
+
def build_table_header(col)
|
12
|
+
sort_key = sortable? && col.sortable? && col.sort_key
|
13
|
+
params = request.query_parameters.except :page, :order, :commit, :format
|
14
|
+
options = options_for_col(col, sort_key)
|
15
|
+
|
16
|
+
if sort_key
|
17
|
+
th options do
|
18
|
+
span do
|
19
|
+
link_to col.pretty_title, params: params, order: "#{sort_key}_#{order_for_sort_key(sort_key)}"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
else
|
23
|
+
th options do
|
24
|
+
span col.pretty_title
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def options_for_col(col, sort_key)
|
30
|
+
classes = Arbre::HTML::ClassList.new
|
31
|
+
classes << "sortable" if sort_key
|
32
|
+
classes << "sorted-#{current_sort[1]}" if sort_key && current_sort[0] == sort_key
|
33
|
+
classes << "reorder"
|
34
|
+
classes << col.html_class
|
35
|
+
|
36
|
+
options = col.instance_variable_get(:@options)
|
37
|
+
style = options[:style] || ''
|
38
|
+
style = "width: #{@configurator.width_for(options[:key])}px" if options[:key].present?
|
39
|
+
|
40
|
+
{
|
41
|
+
class: classes,
|
42
|
+
style: style,
|
43
|
+
'data-column-key': options[:key],
|
44
|
+
}
|
45
|
+
end
|
46
|
+
|
47
|
+
# Display a column for checkbox
|
48
|
+
def selectable_column
|
49
|
+
return unless active_admin_config.batch_actions.any?
|
50
|
+
|
51
|
+
options = {
|
52
|
+
style: "width: 30px",
|
53
|
+
class: "col-selectable",
|
54
|
+
sortable: false,
|
55
|
+
}
|
56
|
+
|
57
|
+
column resource_selection_toggle_cell, options do |resource|
|
58
|
+
resource_selection_cell resource
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
# Display a column for the id
|
63
|
+
def id_column(*args)
|
64
|
+
raise "#{resource_class.name} has no primary_key!" unless resource_class.primary_key
|
65
|
+
data = args[1] || args[0]
|
66
|
+
|
67
|
+
options = {
|
68
|
+
sortable: resource_class.primary_key,
|
69
|
+
'data-column-key': data[:key],
|
70
|
+
**data,
|
71
|
+
}
|
72
|
+
|
73
|
+
column(resource_class.human_attribute_name(resource_class.primary_key), options) do |resource|
|
74
|
+
if controller.action_methods.include?("show")
|
75
|
+
link_to resource.id, resource_path(resource), class: "resource_id_link"
|
76
|
+
elsif controller.action_methods.include?("edit")
|
77
|
+
link_to resource.id, edit_resource_path(resource), class: "resource_id_link"
|
78
|
+
else
|
79
|
+
resource.id
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
def index_column(*args)
|
85
|
+
data = args[1] || args[0]
|
86
|
+
start_value = data.delete(:start_value) || 1
|
87
|
+
|
88
|
+
options = {
|
89
|
+
class: "col-index",
|
90
|
+
sortable: false,
|
91
|
+
**data,
|
92
|
+
}
|
93
|
+
|
94
|
+
column "#", options do |resource|
|
95
|
+
@collection.offset_value + @collection.index(resource) + start_value
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
def build(page_presenter, collection)
|
101
|
+
settings = ActiveadminDynamicTable::SettingStringParser.new(params[:columns])
|
102
|
+
@configurator = ActiveadminDynamicTable::Configurator.new(self, settings.parse)
|
103
|
+
|
104
|
+
table_options = {
|
105
|
+
id: "index_table_#{active_admin_config.resource_name.plural}",
|
106
|
+
sortable: true,
|
107
|
+
class: "index_table index dynamic_table",
|
108
|
+
i18n: active_admin_config.resource_class,
|
109
|
+
paginator: page_presenter[:paginator] != false,
|
110
|
+
row_class: page_presenter[:row_class]
|
111
|
+
}
|
112
|
+
|
113
|
+
table_for collection, table_options do |t|
|
114
|
+
table_config_block = page_presenter.block || default_table
|
115
|
+
instance_exec(t, &table_config_block)
|
116
|
+
|
117
|
+
apply_configuration
|
118
|
+
end
|
119
|
+
|
120
|
+
columns_list
|
121
|
+
end
|
122
|
+
|
123
|
+
def table_for(*args, &block)
|
124
|
+
insert_tag IndexDynamicTableFor, @configurator, *args, &block
|
125
|
+
end
|
126
|
+
|
127
|
+
def register_column(*args, &block)
|
128
|
+
@configurator.register_column(:column, *args, &block)
|
129
|
+
end
|
130
|
+
|
131
|
+
def register_id_column(*args, &block)
|
132
|
+
@configurator.register_column(:id_column, *args, &block)
|
133
|
+
end
|
134
|
+
|
135
|
+
def register_index_column(*args, &block)
|
136
|
+
@configurator.register_column(:index_column, *args, &block)
|
137
|
+
end
|
138
|
+
|
139
|
+
def register_actions(*args, &block)
|
140
|
+
@configurator.register_column(:actions, *args, &block)
|
141
|
+
end
|
142
|
+
|
143
|
+
private
|
144
|
+
|
145
|
+
def apply_columns
|
146
|
+
@configurator.columns
|
147
|
+
end
|
148
|
+
|
149
|
+
def apply_configuration
|
150
|
+
apply_columns
|
151
|
+
column "⚙️", style: "width: 30px", class: 'col-table-preferences', & proc { '' }
|
152
|
+
end
|
153
|
+
|
154
|
+
def columns_list
|
155
|
+
ul class: 'dynamic_table_configuration hidden' do
|
156
|
+
@configurator.registered_columns.each do |col|
|
157
|
+
args = col[:args]
|
158
|
+
|
159
|
+
options = args.extract_options!
|
160
|
+
title = args[0]
|
161
|
+
data = args[1] || args[0]
|
162
|
+
|
163
|
+
column = ::ActiveAdmin::Views::TableFor::Column.new(title, data, @resource_class, options)
|
164
|
+
|
165
|
+
li do
|
166
|
+
label do
|
167
|
+
input type: :checkbox, name: col[:key], checked: col[:selected]
|
168
|
+
span column.pretty_title
|
169
|
+
end
|
170
|
+
end
|
171
|
+
end
|
172
|
+
end
|
173
|
+
end
|
174
|
+
end
|
175
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "active_admin"
|
4
|
+
require_relative "activeadmin_dynamic_table/version"
|
5
|
+
require_relative "activeadmin_dynamic_table/configurator"
|
6
|
+
require_relative "activeadmin_dynamic_table/setting_string_parser"
|
7
|
+
require_relative "activeadmin_dynamic_table/column_settings"
|
8
|
+
require_relative "activeadmin_dynamic_table/views/index_as_dynamic_table"
|
9
|
+
|
10
|
+
module ActiveadminDynamicTable
|
11
|
+
class Error < StandardError; end
|
12
|
+
class Engine < ::Rails::Engine; end
|
13
|
+
end
|
metadata
ADDED
@@ -0,0 +1,75 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: activeadmin_dynamic_table
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Anton Biliaiev
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2024-01-28 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: activeadmin
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '2.9'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '2.9'
|
27
|
+
description: ''
|
28
|
+
email:
|
29
|
+
- amdj15@gmail.com
|
30
|
+
executables: []
|
31
|
+
extensions: []
|
32
|
+
extra_rdoc_files: []
|
33
|
+
files:
|
34
|
+
- Gemfile
|
35
|
+
- Gemfile.lock
|
36
|
+
- LICENSE.txt
|
37
|
+
- README.md
|
38
|
+
- Rakefile
|
39
|
+
- activeadmin_dynamic_table.gemspec
|
40
|
+
- app/assets/javascripts/activeadmin_dynamic_table/config.js
|
41
|
+
- app/assets/javascripts/activeadmin_dynamic_table/dynamic_table.js
|
42
|
+
- app/assets/stylesheets/activeadmin_dynamic_table/all.scss
|
43
|
+
- bin/console
|
44
|
+
- bin/setup
|
45
|
+
- lib/activeadmin_dynamic_table.rb
|
46
|
+
- lib/activeadmin_dynamic_table/column_settings.rb
|
47
|
+
- lib/activeadmin_dynamic_table/configurator.rb
|
48
|
+
- lib/activeadmin_dynamic_table/setting_string_parser.rb
|
49
|
+
- lib/activeadmin_dynamic_table/version.rb
|
50
|
+
- lib/activeadmin_dynamic_table/views/index_as_dynamic_table.rb
|
51
|
+
- sig/activeadmin_dynamic_table.rbs
|
52
|
+
homepage: ''
|
53
|
+
licenses:
|
54
|
+
- MIT
|
55
|
+
metadata: {}
|
56
|
+
post_install_message:
|
57
|
+
rdoc_options: []
|
58
|
+
require_paths:
|
59
|
+
- lib
|
60
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
61
|
+
requirements:
|
62
|
+
- - ">="
|
63
|
+
- !ruby/object:Gem::Version
|
64
|
+
version: 2.6.0
|
65
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
66
|
+
requirements:
|
67
|
+
- - ">="
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '0'
|
70
|
+
requirements: []
|
71
|
+
rubygems_version: 3.1.4
|
72
|
+
signing_key:
|
73
|
+
specification_version: 4
|
74
|
+
summary: ''
|
75
|
+
test_files: []
|