rolemodel_tables 0.0.1 → 0.0.2
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/app/javascript/controllers/advanced_table_search_controller.js +53 -0
- data/app/views/kaminari/_first_page.html.slim +10 -0
- data/app/views/kaminari/_gap.html.slim +9 -0
- data/app/views/kaminari/_last_page.html.slim +10 -0
- data/app/views/kaminari/_next_page.html.slim +10 -0
- data/app/views/kaminari/_page.html.slim +14 -0
- data/app/views/kaminari/_paginator.html.slim +20 -0
- data/app/views/kaminari/_prev_page.html.slim +10 -0
- data/app/views/rolemodel_tables/_advanced_search_controls.html.slim +21 -0
- data/lib/rolemodel_tables/engine.rb +4 -0
- data/lib/rolemodel_tables/models/filter_view.rb +39 -0
- data/lib/rolemodel_tables/models/filters/collection_filter.rb +30 -0
- data/lib/rolemodel_tables/models/filters/date_filter.rb +23 -0
- data/lib/rolemodel_tables/models/filters/date_range_filter.rb +29 -0
- data/lib/rolemodel_tables/models/filters/number_range_filter.rb +33 -0
- data/lib/rolemodel_tables/models/filters/text_filter.rb +27 -0
- data/lib/rolemodel_tables/models/ransack_filter.rb +33 -0
- data/lib/rolemodel_tables/version.rb +5 -0
- data/lib/rolemodel_tables.rb +13 -0
- data/rolemodel_tables.gemspec +32 -0
- metadata +21 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6f1a42253a5583547dba681eda52f60b16127b513500d0ae4b05257e5dbd6945
|
4
|
+
data.tar.gz: 0b8b0c4ffe45ff940cde6041013b2b2fafb39e440cfd3294ca8648a5096961c6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 06556643aff1a83c64d7c9e443009a2e0c835d6d6921331dfd5c0c29cbbc473f3744129a616964f08f59ddd454d9d8c8d98f358e0d508376bd55c9c16c99f9ba
|
7
|
+
data.tar.gz: b040bfe87341bda6a691467f5b582d4b16b149b503d0bad845e90cf0295c64cd39214af49c6b7cf503e5450fe9e6d73c31a5a49d84c7777996348bb72ab59f65
|
@@ -0,0 +1,53 @@
|
|
1
|
+
const { Controller } = require("@hotwired/stimulus")
|
2
|
+
|
3
|
+
class AdvancedTableSearchController extends Controller {
|
4
|
+
static values = {
|
5
|
+
advancedLabel: String,
|
6
|
+
}
|
7
|
+
|
8
|
+
static targets = [
|
9
|
+
'showSearchHiddenInput',
|
10
|
+
'toggleButton',
|
11
|
+
'controlsContainer',
|
12
|
+
'keywordSearchButton',
|
13
|
+
'toggleableArea',
|
14
|
+
]
|
15
|
+
|
16
|
+
connect() {
|
17
|
+
/* global window */
|
18
|
+
// Did the user initiate a search via the form? If so, reveal the form
|
19
|
+
// on page load. The form is initially hidden.
|
20
|
+
const searchParams = new URLSearchParams(window.location.search)
|
21
|
+
if (searchParams.get('show_advanced_search') === 'true') {
|
22
|
+
this.toggle()
|
23
|
+
}
|
24
|
+
}
|
25
|
+
|
26
|
+
toggle() {
|
27
|
+
this.toggleableAreaTarget.classList.toggle('hidden')
|
28
|
+
|
29
|
+
this.keywordSearchButtonTarget.classList.toggle('hidden')
|
30
|
+
|
31
|
+
const text = this.toggleableAreaTarget.classList.contains('hidden') ? 'Show' : 'Hide'
|
32
|
+
this.toggleButtonTarget.innerText = `${text} ${this.advancedLabelValue}`
|
33
|
+
|
34
|
+
const advancedSearchState = this.toggleableAreaTarget.classList.contains('hidden') ? 'false' : 'true'
|
35
|
+
this.showSearchHiddenInputTarget.value = advancedSearchState
|
36
|
+
|
37
|
+
const searchParams = new URLSearchParams(window.location.search)
|
38
|
+
searchParams.set('show_advanced_search', advancedSearchState)
|
39
|
+
const newRelativePathQuery = this._newRelativePathQuery(searchParams)
|
40
|
+
window.history.pushState(null, '', newRelativePathQuery)
|
41
|
+
}
|
42
|
+
|
43
|
+
clear() {
|
44
|
+
const searchParams = new URLSearchParams({ show_advanced_search: 'true' })
|
45
|
+
window.location = this._newRelativePathQuery(searchParams)
|
46
|
+
}
|
47
|
+
|
48
|
+
_newRelativePathQuery(searchParams) {
|
49
|
+
return `${window.location.pathname}?${searchParams.toString()}`
|
50
|
+
}
|
51
|
+
}
|
52
|
+
|
53
|
+
export default AdvancedTableSearchController
|
@@ -0,0 +1,10 @@
|
|
1
|
+
/ Link to the "First" page
|
2
|
+
/ - available local variables
|
3
|
+
/ url: url to the first page
|
4
|
+
/ current_page: a page object for the currently displayed page
|
5
|
+
/ total_pages: total number of pages
|
6
|
+
/ per_page: number of items to fetch per page
|
7
|
+
/ remote: data-remote
|
8
|
+
|
9
|
+
span
|
10
|
+
= link_to_unless current_page.first?, icon('first_page'), url, remote: remote, class: 'btn btn--outline btn--small'
|
@@ -0,0 +1,9 @@
|
|
1
|
+
/ Non-link tag that stands for skipped pages...
|
2
|
+
/ - available local variables
|
3
|
+
/ current_page: a page object for the currently displayed page
|
4
|
+
/ total_pages: total number of pages
|
5
|
+
/ per_page: number of items to fetch per page
|
6
|
+
/ remote: data-remote
|
7
|
+
|
8
|
+
span
|
9
|
+
.btn.btn--small.pagination__gap = t('views.pagination.truncate').html_safe
|
@@ -0,0 +1,10 @@
|
|
1
|
+
/ Link to the "Last" page
|
2
|
+
/ - available local variables
|
3
|
+
/ url: url to the last page
|
4
|
+
/ current_page: a page object for the currently displayed page
|
5
|
+
/ total_pages: total number of pages
|
6
|
+
/ per_page: number of items to fetch per page
|
7
|
+
/ remote: data-remote
|
8
|
+
|
9
|
+
span
|
10
|
+
= link_to_unless current_page.last?, icon('last_page'), url, remote: remote, class: 'btn btn--outline btn--small'
|
@@ -0,0 +1,10 @@
|
|
1
|
+
/ Link to the "Next" page
|
2
|
+
/ - available local variables
|
3
|
+
/ url: url to the next page
|
4
|
+
/ current_page: a page object for the currently displayed page
|
5
|
+
/ total_pages: total number of pages
|
6
|
+
/ per_page: number of items to fetch per page
|
7
|
+
/ remote: data-remote
|
8
|
+
|
9
|
+
span
|
10
|
+
= link_to_unless current_page.last?, icon('chevron_right'), url, rel: 'next', remote: remote, class: 'btn btn--outline btn--small'
|
@@ -0,0 +1,14 @@
|
|
1
|
+
/ Link showing page number
|
2
|
+
/ - available local variables
|
3
|
+
/ page: a page object for "this" page
|
4
|
+
/ url: url to this page
|
5
|
+
/ current_page: a page object for the currently displayed page
|
6
|
+
/ total_pages: total number of pages
|
7
|
+
/ per_page: number of items to fetch per page
|
8
|
+
/ remote: data-remote
|
9
|
+
|
10
|
+
span.page
|
11
|
+
- if page.current?
|
12
|
+
.btn.btn--small.pagination__current = page
|
13
|
+
- else
|
14
|
+
= link_to page, url, remote: remote, rel: page.rel, class: 'btn btn--small btn--outline'
|
@@ -0,0 +1,20 @@
|
|
1
|
+
/ The container tag
|
2
|
+
/ - available local variables
|
3
|
+
/ current_page: a page object for the currently displayed page
|
4
|
+
/ total_pages: total number of pages
|
5
|
+
/ per_page: number of items to fetch per page
|
6
|
+
/ remote: data-remote
|
7
|
+
/ paginator: the paginator that renders the pagination tags inside
|
8
|
+
|
9
|
+
== paginator.render do
|
10
|
+
nav.pagination role="navigation" aria-label="pager"
|
11
|
+
== first_page_tag unless current_page.first?
|
12
|
+
== prev_page_tag unless current_page.first?
|
13
|
+
- each_page do |page|
|
14
|
+
- if page.display_tag?
|
15
|
+
== page_tag page
|
16
|
+
- elsif !page.was_truncated?
|
17
|
+
== gap_tag
|
18
|
+
- unless current_page.out_of_range?
|
19
|
+
== next_page_tag unless current_page.last?
|
20
|
+
== last_page_tag unless current_page.last?
|
@@ -0,0 +1,10 @@
|
|
1
|
+
/ Link to the "Previous" page
|
2
|
+
/ - available local variables
|
3
|
+
/ url: url to the previous page
|
4
|
+
/ current_page: a page object for the currently displayed page
|
5
|
+
/ total_pages: total number of pages
|
6
|
+
/ per_page: number of items to fetch per page
|
7
|
+
/ remote: data-remote
|
8
|
+
|
9
|
+
span
|
10
|
+
= link_to_unless current_page.first?, icon('chevron_left'), url, rel: 'prev', remote: remote, class: 'btn btn--outline btn--small'
|
@@ -0,0 +1,21 @@
|
|
1
|
+
.margin-y-md data-controller='advanced-table-search submit-on-select' data-advanced-table-search-advanced-label-value='Advanced Filters'
|
2
|
+
= search_form_for filter_view.ransack, url: request.path, html: { class: 'simple_form' , data: { 'submit-on-select-target' => 'form' }} do |f|
|
3
|
+
= hidden_field_tag :show_advanced_search, params.fetch(:show_advanced_search, false), data: { 'advanced-table-search-target': 'showSearchHiddenInput' }
|
4
|
+
|
5
|
+
.card.margin-bottom-md data-advanced-table-search-target='controlsContainer'
|
6
|
+
.flex.items-center.gap-sm
|
7
|
+
/ TODO: INLINE STYLES BAD
|
8
|
+
.flex.items-center.gap-sm style='width: 300px'
|
9
|
+
= f.search_field filter_view.quick_search, placeholder: 'Keyword', class: 'form__input'
|
10
|
+
= f.button :search, class: 'btn btn--primary', data: { 'advanced-table-search-target': 'keywordSearchButton' }
|
11
|
+
|
12
|
+
button.project-search-toggle data-advanced-table-search-target='toggleButton' type='button' data-action='click->advanced-table-search#toggle' Show Advanced Filters
|
13
|
+
|
14
|
+
.margin-top-md.hidden data-advanced-table-search-target='toggleableArea'
|
15
|
+
.flex.flex-wrap
|
16
|
+
- filter_view.advanced_filters.each do |filter|
|
17
|
+
= filter.form_row(f).html_safe
|
18
|
+
|
19
|
+
.flex.justify-end.items-center.gap-sm.margin-top-md
|
20
|
+
button.btn.btn--outline type='button' data-action='click->advanced-table-search#clear' Clear
|
21
|
+
= f.button :search, class: 'btn btn--primary'
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RoleModelTables
|
4
|
+
# Parent class for all filter views.
|
5
|
+
class FilterView
|
6
|
+
class_attribute :default_sort, :quick_search, :advanced_filters
|
7
|
+
attr_reader :ransack
|
8
|
+
|
9
|
+
def initialize(scoped_collection)
|
10
|
+
@scoped_collection = scoped_collection
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.default_sort(sort_option)
|
14
|
+
self.default_sort = sort_option
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.quick_search(ransack_matcher)
|
18
|
+
self.quick_search = ransack_matcher
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.advanced_filter(ransack_matcher, klass_name, form_options = {})
|
22
|
+
self.advanced_filters ||= {}
|
23
|
+
self.advanced_filters[ransack_matcher] = "RoleModelTables::Filters::#{klass_name}".constantize.new(ransack_matcher, form_options)
|
24
|
+
end
|
25
|
+
|
26
|
+
def advanced_filters
|
27
|
+
self.class.advanced_filters.map do |_, filter_instance|
|
28
|
+
filter_instance.filter = self
|
29
|
+
filter_instance
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def search(params)
|
34
|
+
@ransack = @scoped_collection.ransack(params[:query])
|
35
|
+
@ransack.sorts = default_sort if @ransack.sorts.empty?
|
36
|
+
@ransack.result.page(params[:page])
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RoleModelTables
|
4
|
+
module Filters
|
5
|
+
# Handle collection dropdowns.
|
6
|
+
class CollectionFilter < RansackFilter
|
7
|
+
def form_row(form)
|
8
|
+
content_tag(:div, class: 'form__group') do
|
9
|
+
[
|
10
|
+
label(form),
|
11
|
+
collection_select(form)
|
12
|
+
].join(' ').html_safe
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def collection_select(form)
|
19
|
+
form.collection_select(
|
20
|
+
ransack_matcher,
|
21
|
+
form_options.fetch(:collection, -> { [] }).call(filter),
|
22
|
+
form_options.fetch(:option_value, ''),
|
23
|
+
form_options.fetch(:option_label, ''),
|
24
|
+
{ include_blank: 'Any' },
|
25
|
+
{ class: 'form__dropdown' }
|
26
|
+
)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RoleModelTables
|
4
|
+
module Filters
|
5
|
+
# Handles a single date field filter.
|
6
|
+
class DateFilter < RansackFilter
|
7
|
+
def form_row(form)
|
8
|
+
content_tag(:div, class: 'form__group') do
|
9
|
+
[
|
10
|
+
label(form),
|
11
|
+
date_field(form)
|
12
|
+
].join(' ').html_safe
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def date_field(form)
|
19
|
+
form.date_field(ransack_matcher, { class: 'form__input' })
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RoleModelTables
|
4
|
+
module Filters
|
5
|
+
# Handles a date range filter.
|
6
|
+
class DateRangeFilter < RansackFilter
|
7
|
+
def form_row(form)
|
8
|
+
content_tag(:div, class: 'form__group') do
|
9
|
+
[
|
10
|
+
label(form),
|
11
|
+
content_tag(:div, class: 'flex items-center gap-sm') do
|
12
|
+
[
|
13
|
+
date_field(form, :gteq),
|
14
|
+
content_tag(:span, '-'),
|
15
|
+
date_field(form, :lteq)
|
16
|
+
].join(' ').html_safe
|
17
|
+
end
|
18
|
+
].join(' ').html_safe
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def date_field(form, predicate)
|
25
|
+
form.date_field("#{ransack_matcher}_#{predicate}", { class: 'form__input' })
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RoleModelTables
|
4
|
+
module Filters
|
5
|
+
# Handles a number range filter.
|
6
|
+
class NumberRangeFilter < RansackFilter
|
7
|
+
def form_row(form)
|
8
|
+
content_tag(:div, class: 'form__group') do
|
9
|
+
[
|
10
|
+
label(form),
|
11
|
+
content_tag(:div, class: 'flex items-center gap-sm') do
|
12
|
+
[
|
13
|
+
search_field(form, :gteq),
|
14
|
+
content_tag(:span, '-'),
|
15
|
+
search_field(form, :lteq)
|
16
|
+
].join(' ').html_safe
|
17
|
+
end
|
18
|
+
].join(' ').html_safe
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def search_field(form, predicate)
|
25
|
+
form.search_field(
|
26
|
+
"#{ransack_matcher}_#{predicate}",
|
27
|
+
class: 'form__input',
|
28
|
+
placeholder: form_options.fetch(:range_begin_placeholder, '')
|
29
|
+
)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RoleModelTables
|
4
|
+
module Filters
|
5
|
+
# Handles a text field filter.
|
6
|
+
class TextFilter < RansackFilter
|
7
|
+
def form_row(form)
|
8
|
+
content_tag(:div, class: 'form__group') do
|
9
|
+
[
|
10
|
+
label(form),
|
11
|
+
search_field(form)
|
12
|
+
].join(' ').html_safe
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def search_field(form)
|
19
|
+
form.search_field(
|
20
|
+
ransack_matcher,
|
21
|
+
class: 'form__input',
|
22
|
+
placeholder: form_options.fetch(:placeholder, '')
|
23
|
+
)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RoleModelTables
|
4
|
+
module Filters
|
5
|
+
# Parent class for all custom filters.
|
6
|
+
class RansackFilter
|
7
|
+
include ActionView::Context
|
8
|
+
include ActionView::Helpers::TagHelper
|
9
|
+
|
10
|
+
attr_reader :ransack_matcher, :form_options
|
11
|
+
attr_accessor :filter
|
12
|
+
|
13
|
+
def initialize(ransack_matcher, form_options = {})
|
14
|
+
@ransack_matcher = ransack_matcher
|
15
|
+
@form_options = form_options
|
16
|
+
end
|
17
|
+
|
18
|
+
def form_row(_form)
|
19
|
+
throw 'Subclass must override'
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def label(form)
|
25
|
+
form.label(
|
26
|
+
ransack_matcher,
|
27
|
+
form_options.fetch(:label, ransack_matcher.to_s.humanize),
|
28
|
+
class: 'form__label'
|
29
|
+
)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RoleModelTables
|
4
|
+
class Error < StandardError; end
|
5
|
+
end
|
6
|
+
|
7
|
+
require 'rolemodel_tables/engine'
|
8
|
+
require 'rolemodel_tables/models/filter_view'
|
9
|
+
require 'rolemodel_tables/models/ransack_filter'
|
10
|
+
|
11
|
+
Dir.chdir(__dir__) do
|
12
|
+
Dir['rolemodel_tables/models/filters/*.rb'].each { |file| require file }
|
13
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
lib = File.expand_path('lib', __dir__)
|
4
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
5
|
+
require 'rolemodel_tables/version'
|
6
|
+
|
7
|
+
Gem::Specification.new do |s|
|
8
|
+
s.name = 'rolemodel_tables'
|
9
|
+
s.version = RoleModelTables::VERSION
|
10
|
+
s.platform = Gem::Platform::RUBY
|
11
|
+
s.authors = ['Jeremy Walton']
|
12
|
+
s.email = 'consult@rolemodelsoftware.com'
|
13
|
+
|
14
|
+
s.summary = 'Rolemodel Tables!'
|
15
|
+
s.description = 'Helpers for advanced table functionality.'
|
16
|
+
s.homepage = 'https://github.com/RoleModel/rolemodel_tables'
|
17
|
+
|
18
|
+
s.license = 'MIT'
|
19
|
+
|
20
|
+
# Specify which files should be added to the gem when it is released.
|
21
|
+
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
22
|
+
s.files = Dir.chdir(File.expand_path(__dir__)) do
|
23
|
+
`git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
24
|
+
end
|
25
|
+
s.require_paths = ['lib']
|
26
|
+
|
27
|
+
s.required_ruby_version = '>= 2.1.0'
|
28
|
+
|
29
|
+
s.add_dependency 'kaminari', '~> 1.2'
|
30
|
+
s.add_dependency 'ransack', '~> 2.5'
|
31
|
+
s.add_dependency 'slim', '~> 4.1'
|
32
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rolemodel_tables
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jeremy Walton
|
@@ -61,6 +61,26 @@ files:
|
|
61
61
|
- ".gitignore"
|
62
62
|
- LICENSE
|
63
63
|
- README.md
|
64
|
+
- app/javascript/controllers/advanced_table_search_controller.js
|
65
|
+
- app/views/kaminari/_first_page.html.slim
|
66
|
+
- app/views/kaminari/_gap.html.slim
|
67
|
+
- app/views/kaminari/_last_page.html.slim
|
68
|
+
- app/views/kaminari/_next_page.html.slim
|
69
|
+
- app/views/kaminari/_page.html.slim
|
70
|
+
- app/views/kaminari/_paginator.html.slim
|
71
|
+
- app/views/kaminari/_prev_page.html.slim
|
72
|
+
- app/views/rolemodel_tables/_advanced_search_controls.html.slim
|
73
|
+
- lib/rolemodel_tables.rb
|
74
|
+
- lib/rolemodel_tables/engine.rb
|
75
|
+
- lib/rolemodel_tables/models/filter_view.rb
|
76
|
+
- lib/rolemodel_tables/models/filters/collection_filter.rb
|
77
|
+
- lib/rolemodel_tables/models/filters/date_filter.rb
|
78
|
+
- lib/rolemodel_tables/models/filters/date_range_filter.rb
|
79
|
+
- lib/rolemodel_tables/models/filters/number_range_filter.rb
|
80
|
+
- lib/rolemodel_tables/models/filters/text_filter.rb
|
81
|
+
- lib/rolemodel_tables/models/ransack_filter.rb
|
82
|
+
- lib/rolemodel_tables/version.rb
|
83
|
+
- rolemodel_tables.gemspec
|
64
84
|
homepage: https://github.com/RoleModel/rolemodel_tables
|
65
85
|
licenses:
|
66
86
|
- MIT
|