administrate_filterable 0.0.2 → 0.0.4

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 655e44dca6e45d18592d84ccc20dbc79f47da6f79e5c7995c32cc2553f8d1a29
4
- data.tar.gz: 05d8c8e708c9d6a08a1a917938f5c26b67e49872374b08206e4167de82b17721
3
+ metadata.gz: bcbe156b91c20f14f2353af7c49bc072a9628955dce901cad747bddf89fd43e2
4
+ data.tar.gz: 120717fc6b4ff1da533b22760146dbbfc0e5c15a7e3602b9cfdd5e67b18b3739
5
5
  SHA512:
6
- metadata.gz: d4c07a5076e76713970cdacad3fa7b90a56cefe00a4aa4fa385f20389642c39e284ea72a9528d6f9111b422f45ad197517269d5c4c6ceb6f574c811914ea9a6b
7
- data.tar.gz: 6f2a3adc9344bb6014f9a61b1048f012a87d60418d363df6e9f40a9caa2df2d67fa95f574d6d4af641ecc271fcd762942b18a37075ef8b9c59fccca29e94afe5
6
+ metadata.gz: 8e3f47f07885b9b88eca9f28f30dd663ca391f802821b6a49ccdb1ac6206eeb0b2ffc896e84b173f09d2c3cff9d7fc04e02127e0a27a26ae003f4a629fbacf6f
7
+ data.tar.gz: d9dad475889e2ea75a0034e229820218978922fa2db3dfe2d01a9a78faff4b45abb65ed8b22780815edb8e23ea2bb6246579db82e65061a87a1a5db937b0897a
data/.gitignore CHANGED
@@ -10,6 +10,8 @@
10
10
  # rspec failure tracking
11
11
  .rspec_status
12
12
 
13
+ # Ignore byebug command history file.
14
+ .byebug_history
13
15
 
14
16
  # Ignore the default SQLite database.
15
17
  spec/dummy/db/*.sqlite3
@@ -18,3 +20,6 @@ spec/dummy/db/*.sqlite3-journal
18
20
  # Ignore all logfiles and tempfiles.
19
21
  spec/dummy/log/*
20
22
  spec/dummy/tmp/*
23
+
24
+ # Ignore gem build artifacts
25
+ *.gem
data/CHANGELOG.md ADDED
@@ -0,0 +1,11 @@
1
+ # CHANGELOG
2
+
3
+ ## 0.0.3
4
+ * Move `_index_filter.html.erb` render location to `_search.html.erb`
5
+
6
+ ## 0.0.2
7
+ * Refactor filterer resource to use new_resource instead of resource_name
8
+
9
+ ## 0.0.1
10
+
11
+ * Initial release with basic filter functionality
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- administrate_filterable (0.0.2)
4
+ administrate_filterable (0.0.3)
5
5
  actionview (>= 5.2.2.1)
6
6
  administrate (>= 0.17.0)
7
7
  rails (>= 4.2)
data/README.md CHANGED
@@ -1,18 +1,20 @@
1
- # Administrate Custom Filter
2
-
3
1
  ![Gem](https://img.shields.io/gem/v/administrate_filterable.svg)
4
2
  ![CI](https://github.com/IrvanFza/administrate_filterable/workflows/CI/badge.svg)
5
3
 
6
- An [Administrate](https://github.com/thoughtbot/administrate/) plugin to add custom filter in your index page. Highly inspired by [ActiveAdmin](https://github.com/activeadmin/activeadmin)'s filter.
4
+ # Administrate Custom Filter
5
+
6
+ An [Administrate](https://github.com/thoughtbot/administrate/) plugin to add a custom filter to your index page. The filter will be rendered as an off-canvas component, so it won't take up too much space on your index page. Highly inspired by [ActiveAdmin](https://github.com/activeadmin/activeadmin)'s filter.
7
7
 
8
- ## Why you need this?
8
+ ![administrate_filterable-open](https://github.com/IrvanFza/administrate_filterable/assets/4778169/c127f425-ed7b-4ea8-b92f-4644072b1576)
9
9
 
10
- Let's agree that the Administrate's team has done a great job with the default search or filter functionality. It's simple and easy to use. It supports multiple search fields, cross relation search, and it's easy to customize (like enable/disable the search, defining custom search fields, etc).
10
+ ## Why do you need this?
11
+
12
+ Let's agree that the Administrate's team has done a great job with the default search or filter functionality. It already supports multiple search fields and relational table searches. It's easy to customize (like enabling/disabling the search, defining custom search fields, etc).
11
13
 
12
14
  But there are some drawbacks that I found:
13
- 1. Since it uses single search box, the search process behind it is quite heavy. It will search all the attributes of the model, and it will be slower if you have a lot of data.
14
- 2. Again, because it search all the attributes, it will be hard to search for a specific attribute. For example, if you have `registration_status` and `employment_status`, and you want to search for "active" registration status only, you will get all the "active" records, including the employment status.
15
- 3. It's not user friendly when it comes to defined search list (e.g. dropdown list). The user will have to type the value manually, and it's not good for the user experience.
15
+ 1. Since it uses a single search box, the search process behind it is quite heavy. It will search all the attributes of the model, and it will be slower if you have a lot of data.
16
+ 2. Again, because it searches all the attributes, it will be hard to search for a specific attribute. For example, if you have `registration_status` and `employment_status`, and you want to search for "active" registration status only, you will get all the "active" records, including the employment status.
17
+ 3. It's not user-friendly when it comes to a defined search list (e.g. dropdown list). The user will have to type the value manually, and it's not good for the user experience.
16
18
 
17
19
  Please share your thoughts if you have any other reasons.
18
20
 
@@ -41,7 +43,8 @@ $ bundle add administrate_filterable
41
43
 
42
44
  ## Usage
43
45
 
44
- For each resource you want to add custom filter, add the following line to the their respective Administrate controller.
46
+ ### Enable the filter
47
+ For each resource you want to add a custom filter, add the following line to their Administrate controller, respectively.
45
48
  ```ruby
46
49
  include AdministrateFilterable::Filterer
47
50
  ```
@@ -55,7 +58,8 @@ class UsersController < Administrate::ApplicationController
55
58
  end
56
59
  ```
57
60
 
58
- By default all the attributes from COLLECTION_ATTRIBUTES will be rendered as the filter fields. You can override this by adding FILTER_ATTRIBUTES to your Administrate's dashboard file.
61
+ ### Customizing the filter fields
62
+ By default, all the attributes from `COLLECTION_ATTRIBUTES` will be rendered as the filter fields. You can override this by adding `FILTER_ATTRIBUTES` to your Administrate's dashboard file.
59
63
 
60
64
  Example (`app/dashboards/user_dashboard.rb`):
61
65
  ```ruby
@@ -71,50 +75,87 @@ class UserDashboard < Administrate::BaseDashboard
71
75
  end
72
76
  ```
73
77
 
74
- By default this gem will add a filter button to the partial `views/admin/application/_index_header.html.erb`. But if you have your own Administrate index views or override that partial in your application you can add the button manually by adding the following line:
78
+ ### Customizing the filter template
79
+ It is possible to customize the filter template (e.g. changing the filter button icon, etc). You can do this by overriding the default template in your application, just create a new file called `_index_filter.html.erb` in your desired resource folder.
80
+
81
+ For example, if you want to override the filter template for the `users` resource, you need to create the file in `app/views/admin/users/_index_filter.html.erb`. Then just copy and paste the content from the default template [here](app/views/admin/application/_index_filter.html.erb) and modify it to suit your needs.
82
+
83
+ ### Asset Pipeline
84
+ If you use an assets pipeline, you need to include this gem's assets in your `app/assets/config/manifest.js` file:
85
+ ```javascript
86
+ // ... other code here ...
87
+
88
+ //= link administrate_filterable/application.css
89
+ //= link administrate_filterable/application.js
90
+ ```
91
+
92
+ Run `rails assets:precompile` if the assets are not loaded.
93
+
94
+
95
+ ## Troubleshooting
96
+ ### Overridden default search template
97
+ By default, this gem will add a filter button to `views/admin/application/_search.html.erb` partial. But if you have overridden that partial in your application you can add the button manually by adding the following line:
75
98
  ```erb
76
- <%= render('index_filter', page: page) %>
99
+ <%= render 'index_filter' %>
77
100
  ```
78
101
 
79
- Example (`app/views/admin/users/_index_header.html.erb`):
102
+ Example (`app/views/admin/users/_search.html.erb`):
80
103
  ```erb
81
- ... other code here ...
82
- <header class="main-content__header">
104
+ <form class="search" role="search">
83
105
  ... other code here ...
106
+ </form>
84
107
 
85
- <%= render('index_filter', page: page) %>
86
- </header>
108
+ <%= render 'index_filter' %>
87
109
  ```
88
110
 
89
- If you use assets pipeline, you need to include this gem's assets to your `app/assets/config/manifest.js` file:
90
- ```javascript
91
- // ... other code here ...
111
+ ### Overridden `scoped_resource` method
112
+ This gem utilizes the `scoped_resource` method to filter the resources by overriding its default behavior. If you by any chance also override this method in your application controller, you will also override the filter functionality and it won't work.
92
113
 
93
- //= link administrate_filterable/application.css
94
- //= link administrate_filterable/application.js
114
+ To fix this, you need to add the following code in the last line of your overridden `scoped_resource` method:
115
+ ```ruby
116
+ filtered_resources(your_scoped_resource)
117
+ ```
118
+
119
+ For example:
120
+ ```ruby
121
+ def scoped_resource
122
+ # Your custom filter logic here
123
+ resources = super.where(status: 'active')
124
+ # Add this line to make the filter work
125
+ filtered_resources(resources)
126
+ end
95
127
  ```
96
128
 
129
+ ### Filter button not showing
130
+ Since I use the `_search.html.erb` partial to add the filter button, it may not be showing if you turn all the searchable attributes to false in the model dashboard. So make sure you have at least one searchable attribute to make the filter button show up.
131
+
132
+ The reason why I use the partial is because:
133
+ 1. It is rarely overridden by the user, so you won't have to add the button manually in most cases.
134
+ 2. Previously, I used the `_index_header.html.erb` partial, but it conflicts with the export button from [administrate_exportable](https://github.com/SourceLabsLLC/administrate_exportable). Using both gems results in one button missing, due to the partial override.
135
+
97
136
  ## To Do
98
- There are still a lot of things to do to make this gem better. Here are some of them (sorted highest priority first):
99
- - [ ] Add support for relational filter (e.g. filter by `belongs_to` association, etc)
137
+ There are still a lot of things to do to make this gem better. Here are some of them (sorted by highest priority first):
138
+ - [ ] Add support for the relational filter (e.g. filter by `belongs_to` association, etc)
100
139
  - [ ] Add support to customize the dropdown list (e.g. add `prompt` option, add `include_blank` option, etc)
101
140
  - [ ] Exclude checkbox, radio, or select value from the filter params if no action is performed on them
102
141
  - [ ] Figure out a better way to implement the filter functionality (currently I override the `scoped_resource` method)
103
- - [ ] Figure out a better way to pass the filter attributes to the form (currently I use instance variable in the overridden `scoped_resource` method)
142
+ - [ ] Figure out a better way to pass the filter attributes to the form (currently I use an instance variable in the overridden `scoped_resource` method)
104
143
  - [ ] Add capability to customize the filter behavior (e.g. search by exact match, search by partial match, etc just like in the ActiveAdmin filter)
105
144
  - [ ] Improve the toggle button user experience (e.g. add open/close animation, add dynamic open/close title, etc)
106
145
 
107
- ## Contributing
146
+ If you have any ideas or suggestions, please let me know by creating an issue or pull request.
108
147
 
109
- 1. Contribution are welcome (codes, suggestions, and bugs)
148
+ ## Contributing
149
+ You can help me to improve this gem by contributing to this project. Any help is highly appreciated.
150
+ 1. Fork this repo and create a pull request
110
151
  2. Please test your code: `bundle exec rspec`
111
- 3. Please document your code
152
+ 3. Please document your code if needed
112
153
 
113
154
  ## License
114
155
 
115
156
  [MIT License](https://github.com/IrvanFza/administrate_filterable/blob/master/LICENSE)
116
157
 
117
158
  ## Credits
118
- Huge thanks for the following resources that help me a lot in creating this gem:
119
- - [administrate_filterable](https://github.com/SourceLabsLLC/administrate_exportable): Basically I just copy the code from this gem and modify it to suit my needs, highly recommended if you need to export your data from Administrate.
120
- - [Off-Canvas Menu](https://web.archive.org/web/20210304195120/https://codepen.io/11bits/pen/jryEGW): I found this CodePen from Google Images when I was looking for a way to create an off-canvas menu. I modified it a little bit to suit my needs. But it seems the codepen is no longer available, so I put the archived version here. If any of you know the original author, please let me know so I can give the proper credit.
159
+ Huge thanks for the following resources that helped me a lot in creating this gem:
160
+ - [administrate_exportable](https://github.com/SourceLabsLLC/administrate_exportable): I just copy and paste the code from this gem and modify it to suit my needs, highly recommended if you need to export your data from Administrate.
161
+ - [Off-Canvas Menu](https://web.archive.org/web/20210304195120/https://codepen.io/11bits/pen/jryEGW): I found this code from Google Images when I was looking for a way to create an off-canvas filter component. I modified it a little bit to suit my needs. But it seems the CodePen is no longer available, so I put the archived version here. If any of you know the original author, please let me know so I can give the proper credit.
@@ -2,7 +2,7 @@
2
2
  position: fixed;
3
3
  z-index: 4;
4
4
  top: 38px;
5
- right: 10px;
5
+ right: 0;
6
6
  }
7
7
 
8
8
  .administrate-filterable__overlay {
@@ -1,5 +1,5 @@
1
- <% if @administrate_filterable_attributes.present? %>
2
- <% resource_title = display_resource_name(page.resource_name) %>
1
+ <% if @filterable_attributes.present? %>
2
+ <% resource_title = display_resource_name(resource_name) %>
3
3
 
4
4
  <% # TODO: Improve the toggle button user experience (e.g. add open/close animation, add dynamic open/close title, etc) %>
5
5
  <a href="#administrate-filterable" class="administrate-filterable__toggle-button" title="Filter <%= resource_title %>">
@@ -13,8 +13,8 @@
13
13
  <h2>Filter <%= resource_title %></h2>
14
14
  </header>
15
15
 
16
- <%= form_with(model: [:admin, @administrate_filterable_resource], method: :get, html: { class: "form administrate-filterable__form" }) do |f| %>
17
- <% @administrate_filterable_attributes.each do |attribute| -%>
16
+ <%= form_with(model: [:admin, new_resource], method: :get, html: { class: "form administrate-filterable__form" }) do |f| %>
17
+ <% @filterable_attributes.each do |attribute| -%>
18
18
  <% # TODO: Add capability to customize the filter behavior (e.g. search by exact match, search by partial match, etc just like in the ActiveAdmin filter) %>
19
19
  <div class="field-unit field-unit--<%= attribute.html_class %> administrate-filterable__field">
20
20
  <%= render_field attribute, f: f %>
@@ -0,0 +1,27 @@
1
+ <form class="search" role="search">
2
+ <label class="search__label" for="search">
3
+ <svg class="search__eyeglass-icon" role="img">
4
+ <title>
5
+ <%= t("administrate.search.label", resource: resource_name) %>
6
+ </title>
7
+ <use xlink:href="#icon-eyeglass" />
8
+ </svg>
9
+ </label>
10
+
11
+ <input class="search__input"
12
+ id="search"
13
+ type="search"
14
+ name="search"
15
+ placeholder="<%= t("administrate.search.label",
16
+ resource: resource_name) %>"
17
+ value="<%= search_term %>">
18
+
19
+ <%= link_to clear_search_params, class: "search__clear-link" do %>
20
+ <svg class="search__clear-icon" role="img">
21
+ <title><%= t("administrate.search.clear") %></title>
22
+ <use xlink:href="#icon-cancel" />
23
+ </svg>
24
+ <% end %>
25
+ </form>
26
+
27
+ <%= render 'index_filter' %>
@@ -9,31 +9,32 @@ module AdministrateFilterable
9
9
  class_methods do
10
10
  def filterable
11
11
  # TODO: Figure out a better way to implement the filter functionality
12
- # This is a hack to implement the filter functionality by overriding the scoped_resource method
13
- # It would be better to implement this as a separate controller action, but I don't have time to explore that right now
12
+ # I don't think overriding `scoped_resource` is the ideal solution to implement the filter functionality.
13
+ # Because when the Administrate controller is generated, it includes suggestion for overriding `scoped_resource`.
14
+ # I already tried to override Administrate `filter_resources` method, but it doesn't work as expected.
15
+ # So, let's stick with this solution for now. Suggestions are very welcomed!
14
16
  define_method(:scoped_resource) do
15
- # TODO: Figure out a better way to pass the filter data to the form
16
- # This is a hack to get the filter resource and attributes to show up in the form, but it's not ideal
17
- # So I tried to make the variable name as unique as possible to avoid collisions
18
- @administrate_filterable_resource = resource_name.to_s.titleize.constantize.new
19
- @administrate_filterable_attributes = FiltererService.filter_attributes(dashboard, @administrate_filterable_resource)
20
-
21
- data = resource_class.all
17
+ resources = resource_class.default_scoped
18
+ filtered_resources(resources)
19
+ end
20
+ end
21
+ end
22
22
 
23
- filter_params = params[resource_name]
24
- return data if filter_params.blank?
23
+ def filtered_resources(resources)
24
+ @filterable_attributes = AdministrateFilterable::FiltererService.filter_attributes(dashboard, new_resource)
25
25
 
26
- filter_params.each do |key, value|
27
- next unless data.column_names.include?(key.to_s) && value.present?
26
+ filter_params = params[resource_name]
27
+ return resources if filter_params.blank?
28
28
 
29
- # TODO: Add support for relational filter (e.g. filter by `belongs_to` association, etc)
30
- sanitized_query = ActiveRecord::Base.send(:sanitize_sql_array, ["#{key} LIKE ?", "%#{value}%"])
31
- data = data.where(sanitized_query)
32
- end
29
+ filter_params.each do |key, value|
30
+ next unless resources.column_names.include?(key.to_s) && value.present?
33
31
 
34
- data
35
- end
32
+ # TODO: Add support for relational filter (e.g. filter by `belongs_to` association, etc)
33
+ sanitized_query = ActiveRecord::Base.send(:sanitize_sql_array, ["#{key} LIKE ?", "%#{value}%"])
34
+ resources = resources.where(sanitized_query)
36
35
  end
36
+
37
+ resources
37
38
  end
38
39
  end
39
40
  end
@@ -1,3 +1,3 @@
1
1
  module AdministrateFilterable
2
- VERSION = "0.0.2"
2
+ VERSION = "0.0.4"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: administrate_filterable
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.0.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Irvan Fauziansyah
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2023-11-13 00:00:00.000000000 Z
11
+ date: 2023-12-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -133,7 +133,7 @@ files:
133
133
  - ".github/workflows/main.yml"
134
134
  - ".gitignore"
135
135
  - ".rspec"
136
- - CHANGELOG
136
+ - CHANGELOG.md
137
137
  - Gemfile
138
138
  - Gemfile.lock
139
139
  - LICENSE
@@ -143,7 +143,7 @@ files:
143
143
  - app/assets/javascripts/administrate_filterable/application.js
144
144
  - app/assets/stylesheets/administrate_filterable/application.css
145
145
  - app/views/admin/application/_index_filter.html.erb
146
- - app/views/admin/application/_index_header.html.erb
146
+ - app/views/admin/application/_search.html.erb
147
147
  - bin/console
148
148
  - bin/setup
149
149
  - lib/administrate_filterable.rb
data/CHANGELOG DELETED
@@ -1,5 +0,0 @@
1
- # CHANGELOG
2
-
3
- ## 0.0.1
4
-
5
- * Initial release with basic filter functionality
@@ -1,19 +0,0 @@
1
- <% content_for(:title) do %>
2
- <%= display_resource_name(page.resource_name) %>
3
- <% end %>
4
-
5
- <header class="main-content__header">
6
- <h1 class="main-content__page-title" id="page-title">
7
- <%= content_for(:title) %>
8
- </h1>
9
-
10
- <% if show_search_bar %>
11
- <%= render(
12
- "search",
13
- search_term: search_term,
14
- resource_name: display_resource_name(page.resource_name)
15
- ) %>
16
- <% end %>
17
-
18
- <%= render('index_filter', page: page) %>
19
- </header>