spotlight_search 0.2.0 → 0.3.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 54325c91322549c86a04e26eb6dd5872f24aa8d898e9d7310342df5de1a486fb
4
- data.tar.gz: 5061e4fcfac405f679a51f5059eb814ee7dfc582a16ccc118e6dff1ad18a0ac5
3
+ metadata.gz: '099ecfc87e93555a16a5e494f3b88f69cbe8688c967444b5fac831dc62b5b650'
4
+ data.tar.gz: 5d3853b623df2045aadb98b70f69dfd9faf9b8d0878a4cb080bdeccaf6f5f396
5
5
  SHA512:
6
- metadata.gz: 7734aa0197053178b3f40492016aa07bc7a5cd72117b976be40cb89bcdfaf8d855c93136bda421bf270e643d441fecb55c669e9f132bc5722a1f87947e2287b8
7
- data.tar.gz: f4b3b1ad28f0d9859e9c52a82fe098c61e21c1262b087b537b5df80d8f67d5e91b8ccdbb3f1b6015dc2bf243688ed698e899675d000489559d981debd18b2235
6
+ metadata.gz: 651ec6f74e9c8d4bae5678be1636a157e13fa2420446ce50e4f0f7d68a438c0247d3f682f1759aedeed5d99095e5bd4a39957e99cad62ea38d747ad17dd8a068
7
+ data.tar.gz: 909f5d9e9a2472bd63d4d7db9ecd77e9c0007f4b10072eb1106ff7f411b45bf103c47de44dd9e03c1c64d8099bf85aa5cd21780287881036a5c4880ce03a7ab4
@@ -2,8 +2,7 @@ PATH
2
2
  remote: .
3
3
  specs:
4
4
  spotlight_search (0.1.9)
5
- axlsx
6
- zip-zip
5
+ caxlsx (~> 3.0.1)
7
6
 
8
7
  GEM
9
8
  remote: https://rubygems.org/
@@ -50,11 +49,12 @@ GEM
50
49
  minitest (~> 5.1)
51
50
  tzinfo (~> 1.1)
52
51
  arel (9.0.0)
53
- axlsx (2.0.1)
54
- htmlentities (~> 4.3.1)
55
- nokogiri (>= 1.4.1)
56
- rubyzip (~> 1.0.0)
57
52
  builder (3.2.4)
53
+ caxlsx (3.0.1)
54
+ htmlentities (~> 4.3, >= 4.3.4)
55
+ mimemagic (~> 0.3)
56
+ nokogiri (~> 1.10, >= 1.10.4)
57
+ rubyzip (>= 1.3.0, < 3)
58
58
  concurrent-ruby (1.1.6)
59
59
  crass (1.0.6)
60
60
  diff-lcs (1.3)
@@ -77,7 +77,7 @@ GEM
77
77
  mini_portile2 (2.4.0)
78
78
  minitest (5.14.0)
79
79
  nio4r (2.5.2)
80
- nokogiri (1.10.3)
80
+ nokogiri (1.10.9)
81
81
  mini_portile2 (~> 2.4.0)
82
82
  rack (2.2.2)
83
83
  rack-test (1.1.0)
@@ -120,7 +120,7 @@ GEM
120
120
  diff-lcs (>= 1.2.0, < 2.0)
121
121
  rspec-support (~> 3.8.0)
122
122
  rspec-support (3.8.0)
123
- rubyzip (1.0.0)
123
+ rubyzip (2.3.0)
124
124
  sprockets (4.0.0)
125
125
  concurrent-ruby (~> 1.0)
126
126
  rack (> 1, < 3)
@@ -134,9 +134,7 @@ GEM
134
134
  thread_safe (~> 0.1)
135
135
  websocket-driver (0.7.1)
136
136
  websocket-extensions (>= 0.1.0)
137
- websocket-extensions (0.1.4)
138
- zip-zip (0.3)
139
- rubyzip (>= 1.0.0)
137
+ websocket-extensions (0.1.5)
140
138
 
141
139
  PLATFORMS
142
140
  ruby
data/README.md CHANGED
@@ -4,6 +4,13 @@
4
4
 
5
5
  It helps filtering, sorting and exporting tables easier.
6
6
 
7
+ First create a new rails project with the following command. If you are adding to existing project skip this
8
+
9
+ ```
10
+ rails new blog -m https://raw.githubusercontent.com/commutatus/cm-rails-template/devise_integration/template.rb
11
+ ```
12
+
13
+
7
14
  ## Installation
8
15
 
9
16
  Add this line to your application's Gemfile:
@@ -20,7 +27,33 @@ Or install it manually:
20
27
 
21
28
  $ gem install spotlight_search
22
29
 
23
- Include the spotlight_search javascript by adding the line `//= require spotlight_search` to your `app/assets/javascripts/application.js`
30
+ Generator that installs mandatory files and gems to application
31
+
32
+ $ rails g spotlight_search:install
33
+
34
+ The install generator does the following
35
+
36
+ * `require spotlight_search` added to application.js
37
+
38
+ * Copies required files for the spotlight_search to work, Such as gemassets.rb, webpacker.yml, environment.js
39
+
40
+ * Copies initializer file
41
+
42
+ * Adds a line in route for mounting.
43
+
44
+ Generator that installs filter and table files to application
45
+ $ rails g spotlight_search filter orders --filters scope_name:filter_type
46
+ $ rails g spotlight_search filter orders --filters search:input order_status:multi_select status:select
47
+
48
+ scope_name is the model scope name, scope can written after running this generator, it won't throw any error that it has to be present.
49
+
50
+ Following filter type are supported
51
+ * input
52
+ * single-select
53
+ * multi-select
54
+ * datetime
55
+ * daterange
56
+
24
57
 
25
58
  ## Usage
26
59
 
@@ -66,24 +99,20 @@ end
66
99
  #### View
67
100
  Please note that the below code is in haml.
68
101
 
69
- **STEP - 1 Search**
70
-
71
- First step is to add the input box to search. Here there are few elements that should be placed mandatorily.
102
+ **STEP - 1 Filters**
72
103
 
73
- ```
74
- .filters.w-100 data-filter-url="/admin/workshops" data-replacement-class="workshops_table"
75
- .col-md-4.input-group.search
76
- input#workshop-search-filter.form-control.filter-box name=("search_term_for_workshops ") placeholder=("Search Workshops") type="text" data-behaviour="filter" data-scope="search" data-type="input-filter"
77
- ```
104
+ **Filter Wrapper, Select-tags and Inputs**
78
105
 
79
- The elements that should be placed mandatorily are
106
+ | Generator | *Mandatory(Data Attributes, Select options) | *Optional(Classes, Placeholders) |
107
+ |----------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------|
108
+ | `= filter_wrapper(data_behaviours, classes=nil)` | `{filter_url: '/users', replacement_class: 'users-table'}` | "filter-classes" |
109
+ | | | |
110
+ | `= cm_select_tag(select_options, data_behaviours, classes=nil, placeholder=nil)` | `{behaviour: "filter", scope: "status", type: "select-filter}` , User.all.map {\|user\| [user.name.titleize, user.id]} | `"user-select"`, placeholder = `"Users"` |
111
+ | | | |
112
+ | `= cm_textfield_tag(data_behaviours, classes=nil, placeholder=nil)` | `{behaviour: "filter", scope: "search", type: "input-filter}` | `"user-search"`, placeholder = `"Search"` |
113
+ | | | |
114
+ | `= clear_filters(clear_path, classes=nil, data_behaviours=nil, clear_text=nil)` | clear_path = `users_path` | `"clear-filter"`, data_behaviours = `{behaviour: 'clear'}`, clear_text = `"Clear all"` |
80
115
 
81
- * `.filters` All search input / select filter should be nested inside this class name.
82
- * `data-filter-url` Is mandatory, this is the search URL, Mostly this will hit the index action.
83
- * `data-replacement-class` After ajax this is the class name where the data will get appended.
84
- * `data-behaviour="filter"` If the input behaviour is set to filter then this will get added to ajax
85
- * `data-scope="search"` This is the model scope name, The helper method will call this when filter is applied.
86
- * `data-type="input-filter"` This is to tell if the element is input or select other value is `data-type="select-filter"`
87
116
 
88
117
  **STEP - 2 Pagination**
89
118
 
@@ -105,20 +134,6 @@ th = sortable "name", "Name", @filtered_result.sort[:sort_column], @filtered_res
105
134
 
106
135
  You will need to have a background job processor such as `sidekiq`, `resque`, `delayed_job` etc as the file will be generated in the background and will be sent to the email passed. If you need to use any other service for sending emails, you will need to override `ExportMailer` class.
107
136
 
108
- #### Initializer
109
- An initializer will have to be created to extend the functionality to ActiveRecord.
110
-
111
- ```ruby
112
- # config/initializers/spotlight_search.rb
113
- ActiveRecord::Base.include SpotlightSearch::ExportableColumns
114
- ```
115
-
116
- #### Routes
117
- A line has to be added to the routes.
118
-
119
- ```ruby
120
- mount SpotlightSearch::Engine => '/spotlight_search'
121
- ```
122
137
 
123
138
  #### <a name="export-view"></a>View
124
139
 
@@ -74,6 +74,15 @@ $(document).on('keyup', '[data-type="input-filter"]', function() {
74
74
  });
75
75
  });
76
76
 
77
+ $(document).on('change', '[data-type="range-filter"]', function() {
78
+ var thisObj;
79
+ thisObj = $(this);
80
+ return $(function() {
81
+ return get_paginated_list(1, thisObj);
82
+ });
83
+ });
84
+
85
+
77
86
  $(document).on('change', '[data-type="select-filter"]', function() {
78
87
  var thisObj;
79
88
  thisObj = $(this);
@@ -4,7 +4,9 @@ module SpotlightSearch
4
4
  begin
5
5
  klass = params[:class_name].constantize
6
6
  if klass.validate_exportable_columns(params[:columns])
7
- ExportJob.perform_later(klass.name, params[:email], params[:columns], params[:filters], params[:sort])
7
+ (filter_params = params[:filters].permit!) if params[:filters].present?
8
+ (sort_params = params[:sort].permit!) if params[:sort].present?
9
+ ExportJob.perform_later(klass.name, params[:email], params[:columns], filter_params, sort_params)
8
10
  notice = 'Successfully queued for export'
9
11
  else
10
12
  notice = 'Invalid columns found'
@@ -1,4 +1,4 @@
1
- require 'axlsx'
1
+ require 'caxlsx'
2
2
 
3
3
  module SpotlightSearch
4
4
  class ExportJob < ApplicationJob
@@ -15,7 +15,7 @@ module SpotlightSearch
15
15
  subject = "#{klass.name} export at #{Time.now}"
16
16
  ExportMailer.send_excel_file(email, file_path, subject).deliver_now
17
17
  File.delete(file_path)
18
- rescue StandsrdError(e)
18
+ rescue StandardError => e
19
19
  ExportMailer.send_error_message(email, e).deliver_now
20
20
  end
21
21
 
@@ -26,6 +26,11 @@ module SpotlightSearch
26
26
  records = records.send(scope, scope_args)
27
27
  end
28
28
  end
29
+ if klass.default_filters.present?
30
+ klass.default_filters.each do |scope|
31
+ records = records.send(scope)
32
+ end
33
+ end
29
34
  if sort.present?
30
35
  records = records.order("#{sort['sort_column']} #{sort['sort_direction']}")
31
36
  end
@@ -37,7 +42,9 @@ module SpotlightSearch
37
42
  columns = columns.map(&:to_sym)
38
43
  records.select(*columns)
39
44
  when :v2
40
- records.as_json(SpotlightSearch::Utils.deserialize_csv_columns(columns, :as_json_params))
45
+ deserialized_columns = SpotlightSearch::Utils.deserialize_csv_columns(columns, :as_json_params)
46
+ # This includes isn't recursve, a full solution should be recursive
47
+ records.includes(deserialized_columns[:include].keys).find_each.as_json(deserialized_columns)
41
48
  end
42
49
  end
43
50
 
@@ -66,7 +73,7 @@ module SpotlightSearch
66
73
  columns.size.times { size_arr << 22 }
67
74
  xl = Axlsx::Package.new
68
75
  xl.workbook.add_worksheet do |sheet|
69
- sheet.add_row columns, b: true
76
+ sheet.add_row columns&.map(&:titleize), b: true
70
77
  flattened_records.each do |record|
71
78
  sheet.add_row(columns.map { |column| record[column] })
72
79
  end
@@ -0,0 +1,21 @@
1
+ module SpotlightSearch
2
+ module Generators
3
+ class FilterGenerator < Rails::Generators::Base
4
+ source_root File.expand_path('templates', __dir__)
5
+
6
+ argument :model, type: :string, required: true, desc: "Pass a model name"
7
+ class_option :filters, aliases: "-f", type: :array, desc: "Pass filters and scopes as an array. E.x: date_filter:datetime search:input"
8
+
9
+ def copy_filter_contents_to_app
10
+ if @options.filters?
11
+ inject_into_file "app/models/#{model.singularize}.rb", after: "ApplicationRecord" do
12
+ "\n include SpotlightSearch\n"
13
+ end
14
+ template 'filters.html.erb', "app/views/admin/#{model}/_filters.html.slim"
15
+ template 'controller.rb.erb', "app/controllers/admin/#{model}_controller.rb"
16
+ end
17
+ end
18
+
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,27 @@
1
+ require 'yaml'
2
+
3
+ module SpotlightSearch
4
+ module Generators
5
+ class InstallGenerator < Rails::Generators::Base
6
+ source_root File.expand_path('templates', __dir__)
7
+
8
+ def copy_webpacker_gem_assets
9
+ copy_file 'webpacker_gem_assets.rb', 'config/initializers/webpacker_gem_assets.rb'
10
+ copy_file 'webpacker.yml', 'config/webpacker.yml'
11
+ copy_file 'environment.js', 'config/webpack/environment.js'
12
+ copy_file 'coffee.js', 'config/webpack/loaders/coffee.js'
13
+ copy_file 'spotlight_search.rb', 'config/initializers/spotlight_search.rb'
14
+ copy_file 'application.css.scss', 'app/assets/stylesheets/application.css.scss'
15
+ route "mount SpotlightSearch::Engine => '/spotlight_search'"
16
+ end
17
+
18
+ def add_essentials
19
+ system("yarn add jquery coffeescript coffee-loader select2 popper.js daterangepicker bootstrap-datepicker")
20
+ template "application.js", "app/javascript/packs/application.js"
21
+ template 'scaffolds.coffee', "app/javascript/application/coffee_scripts/scaffolds.coffee"
22
+ gem 'kaminari'
23
+ end
24
+
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,26 @@
1
+ /*
2
+ * This is a manifest file that'll be compiled into application.css, which will include all the files
3
+ * listed below.
4
+ *
5
+ * Any CSS and SCSS file within this directory, lib/assets/stylesheets, or any plugin's
6
+ * vendor/assets/stylesheets directory can be referenced here using a relative path.
7
+ *
8
+ * You're free to add application-wide styles to this file and they'll appear at the bottom of the
9
+ * compiled file so the styles you add here take precedence over styles defined in any other CSS/SCSS
10
+ * files in this directory. Styles in this file should be added after the last require_* statement.
11
+ * It is generally better to create a new file per style scope.
12
+ *
13
+ *= require_self
14
+ *= require font-awesome
15
+ *= require 'select2'
16
+ *= require bootstrap/dist/css/bootstrap
17
+ *= require bootstrap-datepicker/dist/css/bootstrap-datepicker3
18
+ *= require daterangepicker
19
+ */
20
+
21
+ $fa-font-path: '@fortawesome/fontawesome-free/webfonts';
22
+ @import '@fortawesome/fontawesome-free/scss/fontawesome';
23
+ @import '@fortawesome/fontawesome-free/scss/solid';
24
+ @import '@fortawesome/fontawesome-free/scss/regular';
25
+ @import '@fortawesome/fontawesome-free/scss/brands';
26
+ @import '@fortawesome/fontawesome-free/scss/v4-shims';
@@ -0,0 +1,19 @@
1
+ // This file is automatically compiled by Webpack, along with any other files
2
+ // present in this directory. You're encouraged to place your actual application logic in
3
+ // a relevant structure within app/javascript and only use these pack files to reference
4
+ // that code so it'll be compiled.
5
+
6
+
7
+ require("@rails/ujs").start()
8
+ require("turbolinks").start()
9
+ require("@rails/activestorage").start()
10
+ require("spotlight_search")
11
+ require("daterangepicker")
12
+
13
+ import jQuery from 'jquery';
14
+ window.$ = jQuery
15
+ window.jQuery = jQuery
16
+ import 'select2';
17
+ import 'bootstrap/dist/js/bootstrap'
18
+ import 'bootstrap-datepicker/dist/js/bootstrap-datepicker.js';
19
+ import '../application/coffee_scripts/scaffolds.coffee';
@@ -0,0 +1,6 @@
1
+ module.exports = {
2
+ test: /\.coffee(\.erb)?$/,
3
+ use: [{
4
+ loader: 'coffee-loader'
5
+ }]
6
+ }
@@ -0,0 +1,91 @@
1
+ class Admin::<%= model.titleize.gsub(' ', '') %>Controller < ApplicationController
2
+ before_action :set_<%= model.singularize %>, only: [:show, :edit, :update, :destroy]
3
+
4
+ # GET /<%= model %>
5
+ # GET /<%= model %>.json
6
+ def index
7
+ @filtered_result = <%= model.classify %>.all.filter_by(params[:page], filter_params.to_h, sort_params.to_h)
8
+ respond_to do |format|
9
+ if request.xhr?
10
+ format.html { render partial: 'table' }
11
+ format.json
12
+ else
13
+ format.html
14
+ end
15
+ end
16
+ end
17
+
18
+ # GET /<%= model %>/1
19
+ # GET /<%= model %>/1.json
20
+ def show
21
+ end
22
+
23
+ # GET /<%= model %>/new
24
+ def new
25
+ @<%= model.singularize %> = <%= model.singularize.titleize.gsub(' ', '') %>.new
26
+ end
27
+
28
+ # GET /<%= model %>/1/edit
29
+ def edit
30
+ end
31
+
32
+ # POST /<%= model %>
33
+ # POST /<%= model %>.json
34
+ def create
35
+ @<%= model.singularize %> = <%= model.singularize.titleize.gsub(' ', '') %>.new(<%= model.singularize %>_params)
36
+
37
+ respond_to do |format|
38
+ if @<%= model.singularize %>.save
39
+ format.html { redirect_to admin_<%= model.singularize %>_path(@<%= model.singularize %>), notice: '<%= model.singularize.titleize.gsub(' ', '') %> was successfully created.' }
40
+ format.json { render :show, status: :created, location: @<%= model.singularize %> }
41
+ else
42
+ format.html { render :new }
43
+ format.json { render json: @<%= model.singularize %>.errors, status: :unprocessable_entity }
44
+ end
45
+ end
46
+ end
47
+
48
+ # PATCH/PUT /<%= model %>/1
49
+ # PATCH/PUT /<%= model %>/1.json
50
+ def update
51
+ respond_to do |format|
52
+ if @<%= model.singularize %>.update(<%= model.singularize %>_params)
53
+ format.html { redirect_to admin_<%= model.singularize %>_path(@<%= model.singularize %>), notice: '<%= model.singularize.titleize.gsub(' ', '') %> was successfully updated.' }
54
+ format.json { render :show, status: :ok, location: @<%= model.singularize %> }
55
+ else
56
+ format.html { render :edit }
57
+ format.json { render json: @<%= model.singularize %>.errors, status: :unprocessable_entity }
58
+ end
59
+ end
60
+ end
61
+
62
+ # DELETE /<%= model %>/1
63
+ # DELETE /<%= model %>/1.json
64
+ def destroy
65
+ @<%= model.singularize %>.destroy
66
+ respond_to do |format|
67
+ format.html { redirect_to admin_<%= model %>_path, notice: '<%= model.singularize.titleize.gsub(' ', '') %> was successfully destroyed.' }
68
+ format.json { head :no_content }
69
+ end
70
+ end
71
+
72
+ private
73
+
74
+ # Use callbacks to share common setup or constraints between actions.
75
+ def set_<%= model.singularize %>
76
+ @<%= model.singularize %> = <%= model.singularize.titleize.gsub(' ', '') %>.find(params[:id])
77
+ end
78
+
79
+ # Only allow a list of trusted parameters through.
80
+ def <%= model.singularize %>_params
81
+ params.require(:<%= model.singularize %>).permit()
82
+ end
83
+
84
+ def filter_params
85
+ params.require(:filters).permit(<%= @options.filters.map{ |f| ':' + f.split(':')[0] }.join(', ') %>) if params[:filters]
86
+ end
87
+
88
+ def sort_params
89
+ params.require(:sort).permit(:sort_column, :sort_direction) if params[:sort]
90
+ end
91
+ end
@@ -0,0 +1,20 @@
1
+ const { environment } = require('@rails/webpacker')
2
+ const coffee = require('./loaders/coffee')
3
+
4
+ const webpack = require('webpack')
5
+ environment.plugins.prepend('Provide',
6
+ new webpack.ProvidePlugin({
7
+ $: require.resolve('jquery'),
8
+ jQuery: require.resolve('jquery'),
9
+ Popper: ['popper.js', 'default']
10
+ })
11
+ )
12
+
13
+ const { add_paths_to_environment } = require(
14
+ // `${environment.plugins.get('Environment').defaultValues["PWD"]}/config/environments/_add_gem_paths`
15
+ `/tmp/_add_gem_paths`
16
+ )
17
+ add_paths_to_environment(environment)
18
+
19
+ environment.loaders.prepend('coffee', coffee)
20
+ module.exports = environment
@@ -0,0 +1,10 @@
1
+ .filter-section
2
+ .filter-section__lhs
3
+ = filter_wrapper({filter_url: '/admin/<%= model %>', replacement_class: "<%= model %>-table"})
4
+ <%- @options.filters.each do |filter| -%>
5
+ <%- filter_arr = filter.split(':') -%>
6
+ = cm_filter_tag("<%= filter_arr[1] %>", "<%= filter_arr[0] %>", "", 'field-area', "<%= filter_arr[0].titleize %>")
7
+ <%- end -%>
8
+ = clear_filters(admin_<%= model %>_path, nil, nil, "Clear all")
9
+ .filter-section__rhs
10
+ = link_to 'Add', <%= "new_admin_" + model.singularize + "_path" %>, class: 'filter-btn'
@@ -0,0 +1,11 @@
1
+ $(document).on "turbolinks:load", () ->
2
+ $('.select2-multiple').select2()
3
+ $('.select2-single').select2(
4
+ allowClear: true
5
+ )
6
+ $('.filter-rangepicker').daterangepicker()
7
+ $('.datepicker').datepicker({
8
+ format: 'dd/mm/yyyy',
9
+ todayHighlight: true,
10
+ autoclose: true,
11
+ })
@@ -0,0 +1,5 @@
1
+ ActiveRecord::Base.include SpotlightSearch::ExportableColumnsV2
2
+
3
+ SpotlightSearch.setup do |config|
4
+ config.exportable_columns_version = :v2
5
+ end
@@ -0,0 +1,102 @@
1
+ # Note: You must restart bin/webpack-dev-server for changes to take effect
2
+
3
+ default: &default
4
+ source_path: app/javascript
5
+ source_entry_path: packs
6
+ public_root_path: public
7
+ public_output_path: packs
8
+ cache_path: tmp/cache/webpacker
9
+ check_yarn_integrity: false
10
+ webpack_compile_output: true
11
+
12
+ # Additional paths webpack should lookup modules
13
+ # ['app/assets', 'engine/foo/app/assets']
14
+ resolved_paths: []
15
+ resolved_gems_output_path: '/tmp/_add_gem_paths.js'
16
+ resolved_gems: [
17
+ 'spotlight_search'
18
+ ]
19
+
20
+ # Reload manifest.json on all requests so we reload latest compiled packs
21
+ cache_manifest: false
22
+
23
+ # Extract and emit a css file
24
+ extract_css: false
25
+
26
+ static_assets_extensions:
27
+ - .jpg
28
+ - .jpeg
29
+ - .png
30
+ - .gif
31
+ - .tiff
32
+ - .ico
33
+ - .svg
34
+ - .eot
35
+ - .otf
36
+ - .ttf
37
+ - .woff
38
+ - .woff2
39
+
40
+ extensions:
41
+ - .coffee
42
+ - .mjs
43
+ - .js
44
+ - .sass
45
+ - .scss
46
+ - .css
47
+ - .module.sass
48
+ - .module.scss
49
+ - .module.css
50
+ - .png
51
+ - .svg
52
+ - .gif
53
+ - .jpeg
54
+ - .jpg
55
+
56
+ development:
57
+ <<: *default
58
+ compile: true
59
+
60
+ # Verifies that correct packages and versions are installed by inspecting package.json, yarn.lock, and node_modules
61
+ check_yarn_integrity: true
62
+
63
+ # Reference: https://webpack.js.org/configuration/dev-server/
64
+ dev_server:
65
+ https: false
66
+ host: localhost
67
+ port: 3035
68
+ public: localhost:3035
69
+ hmr: false
70
+ # Inline should be set to true if using HMR
71
+ inline: true
72
+ overlay: true
73
+ compress: true
74
+ disable_host_check: true
75
+ use_local_ip: false
76
+ quiet: false
77
+ pretty: false
78
+ headers:
79
+ 'Access-Control-Allow-Origin': '*'
80
+ watch_options:
81
+ ignored: '**/node_modules/**'
82
+
83
+
84
+ test:
85
+ <<: *default
86
+ compile: true
87
+
88
+ # Compile test packs to a separate directory
89
+ public_output_path: packs-test
90
+
91
+ production:
92
+ <<: *default
93
+ webpack_compile_output: true
94
+
95
+ # Production depends on precompilation of packs prior to booting for performance.
96
+ compile: false
97
+
98
+ # Extract and emit a css file
99
+ extract_css: true
100
+
101
+ # Cache manifest.json for performance
102
+ cache_manifest: true
@@ -0,0 +1,55 @@
1
+ # config/initializers/webpacker_gem_assets.rb
2
+
3
+ def default_assets_path
4
+ 'app/assets/javascripts'
5
+ end
6
+
7
+ def output_path
8
+ Webpacker.config.send(:data)[:resolved_gems_output_path] || '/tmp/_add_gem_paths.js'
9
+ end
10
+
11
+ def resolve_gem_path(gem)
12
+ if gem.present?
13
+ gem_path = Gem.loaded_specs[gem]&.full_gem_path
14
+ if gem_path.present?
15
+ return "#{gem_path}/#{default_assets_path}"
16
+ end
17
+ end
18
+ abort("Gem '#{gem}' not found, please check webpacker config (#{Webpacker.config.config_path})")
19
+ end
20
+
21
+ buffer = []
22
+ buffer << "
23
+ /*
24
+ * THIS IS A GENERATED FILE.
25
+ * DO NOT CHECK IT INTO SOURCE CONTROL
26
+ */
27
+ function add_paths_to_environment(environment) {".strip
28
+
29
+ resolved_gems = Webpacker.config.send(:data)[:resolved_gems]
30
+ if resolved_gems.any?
31
+ buffer << "\n environment.resolvedModules.add(\n"
32
+ buffer << resolved_gems.map do |gem|
33
+ " { key: 'gem-#{gem}', value: '#{resolve_gem_path(gem)}' }"
34
+ end.join(",\n")
35
+ buffer << "\n )\n"
36
+ end
37
+
38
+ buffer << "}\nexports.add_paths_to_environment = add_paths_to_environment\n"
39
+
40
+ File.write(
41
+ output_path,
42
+ buffer.join
43
+ )
44
+
45
+ module WebpackerGemAssets
46
+ def resolved_paths
47
+ self.send(:data)[:resolved_gems].map do |gem|
48
+ resolve_gem_path gem
49
+ end.compact.concat(super)
50
+ end
51
+ end
52
+
53
+ class Webpacker::Configuration
54
+ prepend WebpackerGemAssets
55
+ end
@@ -32,6 +32,10 @@ module SpotlightSearch
32
32
  self.enabled_columns = [*record_fields, **associated_fields]
33
33
  end
34
34
 
35
+ def default_scopes_for_export(*filter_scopes)
36
+ self.default_filters = filter_scopes
37
+ end
38
+
35
39
  def _model_exportable_columns(klass, *record_fields, **associated_fields)
36
40
  # Gets all the valid columns of a model
37
41
  # If any column is invalid, it also returns it
@@ -85,6 +89,7 @@ module SpotlightSearch
85
89
 
86
90
  included do
87
91
  class_attribute :enabled_columns, instance_accessor: false, default: nil
92
+ class_attribute :default_filters, instance_accessor: false, default: nil
88
93
  end
89
94
  end
90
95
  end
@@ -12,26 +12,26 @@ module SpotlightSearch
12
12
  end
13
13
 
14
14
  def exportable(email, klass, html_class: [])
15
- tag.div do
16
- concat tag.button "Export as excel", class: html_class.append("modal-btn"), data: {toggle: "modal", target: "#exportmodal"}
17
- concat column_pop_up(email, klass)
15
+ tag.a "Export as excel", class: html_class.append("filter-btn modal-btn mr-2"), data: {toggle: "modal", target: "#exportmodal"} do
16
+ concat tag.i class: 'fa fa-download'
17
+ concat tag.span " Excel"
18
18
  end
19
19
  end
20
20
 
21
- def column_pop_up(email, klass)
21
+ def column_pop_up(email, klass, required_filters = nil)
22
22
  tag.div class: "modal fade", id: "exportmodal", tabindex: "-1", role: "dialog", aria: {labelledby: "exportModal"} do
23
23
  tag.div class: "modal-dialog modal-lg", role: "document" do
24
24
  tag.div class: "modal-content" do
25
- concat pop_ups(email, klass)
25
+ concat pop_ups(email, klass, required_filters)
26
26
  end
27
27
  end
28
28
  end
29
29
  end
30
30
 
31
- def pop_ups(email, klass)
31
+ def pop_ups(email, klass, required_filters)
32
32
  tag.div do
33
33
  concat pop_up_header
34
- concat pop_up_body(email, klass)
34
+ concat pop_up_body(email, klass, required_filters)
35
35
  end
36
36
  end
37
37
 
@@ -44,11 +44,12 @@ module SpotlightSearch
44
44
  end
45
45
  end
46
46
 
47
- def pop_up_body(email, klass)
47
+ def pop_up_body(email, klass, required_filters)
48
48
  tag.div class: "modal-body" do
49
49
  form_tag '/spotlight_search/export_to_file', id: 'export-to-file-form', style: "width: 100%;", class:"spotlight-csv-export-form" do
50
50
  concat hidden_field_tag 'email', email, id: 'export-to-file-email'
51
51
  concat hidden_field_tag 'class_name', klass.to_s, id: 'export-to-file-klass'
52
+ filters_to_post_helper(required_filters) if required_filters
52
53
  params_to_post_helper(filters: controller.filter_params) if controller.filter_params
53
54
  params_to_post_helper(sort: controller.sort_params) if controller.sort_params
54
55
  case SpotlightSearch.exportable_columns_version
@@ -57,11 +58,18 @@ module SpotlightSearch
57
58
  when :v2
58
59
  concat checkbox_row_v2(klass)
59
60
  end
60
- concat submit_tag 'Export as excel', class: 'btn btn-bordered export-to-file-btn'
61
+ concat tag.hr
62
+ concat submit_tag 'Export as excel', class: 'btn btn-primary btn-bordered export-to-file-btn'
61
63
  end
62
64
  end
63
65
  end
64
66
 
67
+ def filters_to_post_helper(required_filters)
68
+ URI.decode_www_form(required_filters.to_param).each do |param|
69
+ concat hidden_field_tag "filters[#{param[0]}]", param[1]
70
+ end
71
+ end
72
+
65
73
  def params_to_post_helper(params)
66
74
  URI.decode_www_form(params.to_param).each do |param|
67
75
  concat hidden_field_tag param[0], param[1]
@@ -83,6 +91,44 @@ module SpotlightSearch
83
91
  end
84
92
  end
85
93
 
94
+ def filter_wrapper(data_behaviours, classes=nil)
95
+ tag.div class: "filter-wrapper d-flex filters #{classes}", data: data_behaviours do
96
+ yield
97
+ end
98
+ end
99
+
100
+ def cm_filter_tag(input_type, scope_name, value, classes = nil, placeholder = nil)
101
+ case input_type
102
+ when 'input'
103
+ tag.div class: 'filter-field' do
104
+ concat text_field_tag scope_name, '', class: "#{classes}", data: {behaviour: "filter", scope: scope_name, type: "input-filter"}, placeholder: "#{placeholder}"
105
+ concat tag.span class: 'fa fa-search search-icon'
106
+ end
107
+ when 'single-select'
108
+ tag.div class: 'filter-field' do
109
+ select_tag scope_name, options_for_select(value), class: "#{classes} select2-single", data: {behaviour: "filter", scope: scope_name, type: "select-filter"}, include_blank: "#{placeholder}"
110
+ end
111
+ when 'multi-select'
112
+ tag.div class: 'filter-field' do
113
+ select_tag scope_name, options_for_select(value), class: "#{classes} select2-single", data: {behaviour: "filter", scope: scope_name, type: "select-filter"}, include_blank: "#{placeholder}", multiple: true
114
+ end
115
+ when 'datetime'
116
+ tag.div class: 'filter-field' do
117
+ concat text_field_tag scope_name, '', class: "#{classes}", data: {behaviour: "filter", scope: scope_name, type: "input-filter", provide: "datepicker"}, placeholder: "#{placeholder}"
118
+ concat tag.span class: 'fa fa-search search-icon'
119
+ end
120
+ when 'daterange'
121
+ tag.div class: 'filter-field' do
122
+ concat text_field_tag scope_name, '', class: "#{classes} filter-rangepicker", data: {behaviour: "filter", scope: scope_name, type: "range-filter"}, placeholder: "#{placeholder}"
123
+ concat tag.span class: 'fa fa-search search-icon'
124
+ end
125
+ end
126
+ end
127
+
128
+ def clear_filters(clear_path, classes=nil, data_behaviours=nil, clear_text=nil)
129
+ link_to "#{clear_text}", clear_path, class: "#{classes}", data: data_behaviours
130
+ end
131
+
86
132
  def checkbox_row_v2(klass)
87
133
  tag.div class: "row" do
88
134
  SpotlightSearch::Utils.serialize_csv_columns(*klass.enabled_columns).each do |column_path|
@@ -94,30 +140,30 @@ module SpotlightSearch
94
140
  def create_checkbox_v2(column_path)
95
141
  tag.div class: "col-md-4" do
96
142
  concat check_box_tag "columns[]", column_path, id: column_path.to_s.gsub('/', '-')
97
- concat column_path.to_s.gsub('/', '_').humanize
143
+ concat " " + column_path.to_s.gsub('/', '_').humanize
98
144
  end
99
145
  end
100
146
 
101
147
  def cm_paginate(facets)
102
- tag.div class: 'text-center' do
148
+ tag.div class: 'cm-pagination' do
103
149
  tag.div class: 'nav navbar navbar-inner' do
104
150
  tag.ul class: 'pagination' do
105
151
  if facets.previous_page != false
106
152
  previous_page = tag.li do
107
- tag.button class: 'btn btn-bordered', data: { behaviour: 'previous-page'} do
153
+ tag.button class: 'cm-pagination__item', data: { behaviour: 'previous-page'} do
108
154
  tag.span "Previous"
109
155
  end
110
156
  end
111
157
  end
112
158
  current_page = content_tag :li do
113
- tag.a class: 'btn btn-bordered mx-2', data: {sort_column: facets.sort[:sort_column], sort_direction: facets.sort[:sort_direction], page: facets.current_page, behaviour: 'current-page' } do
159
+ tag.button class: 'cm-pagination__item', data: {sort_column: facets.sort[:sort_column], sort_direction: facets.sort[:sort_direction], page: facets.current_page, behaviour: 'current-page' } do
114
160
  "Showing #{facets.current_page} of #{facets.total_pages} pages"
115
161
  end
116
162
  end
117
163
 
118
164
  if facets.next_page != false
119
165
  next_page = tag.li do
120
- tag.button class: 'btn btn-bordered', data: { behaviour: 'next-page'} do
166
+ tag.button class: 'cm-pagination__item', data: { behaviour: 'next-page'} do
121
167
  tag.span "Next"
122
168
  end
123
169
  end
@@ -1,3 +1,3 @@
1
1
  module SpotlightSearch
2
- VERSION = "0.2.0"
2
+ VERSION = "0.3.2"
3
3
  end
@@ -24,9 +24,8 @@ Gem::Specification.new do |s|
24
24
  # s.require_paths = ["lib"]
25
25
 
26
26
  s.add_development_dependency "bundler", "~> 2.0"
27
- s.add_development_dependency "rake", ">= 12.3.3"
27
+ s.add_development_dependency "rake", "~> 13.0.1"
28
28
  s.add_development_dependency "rails", "~> 5.2.4.2"
29
29
  s.add_development_dependency "rspec", "~> 3.0"
30
- s.add_runtime_dependency 'axlsx'
31
- s.add_runtime_dependency 'zip-zip'
30
+ s.add_runtime_dependency 'caxlsx', "~> 3.0.1"
32
31
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: spotlight_search
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.3.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Anbazhagan Palani
@@ -28,16 +28,16 @@ dependencies:
28
28
  name: rake
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - ">="
31
+ - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: 12.3.3
33
+ version: 13.0.1
34
34
  type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - ">="
38
+ - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: 12.3.3
40
+ version: 13.0.1
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: rails
43
43
  requirement: !ruby/object:Gem::Requirement
@@ -67,33 +67,19 @@ dependencies:
67
67
  - !ruby/object:Gem::Version
68
68
  version: '3.0'
69
69
  - !ruby/object:Gem::Dependency
70
- name: axlsx
70
+ name: caxlsx
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
- - - ">="
74
- - !ruby/object:Gem::Version
75
- version: '0'
76
- type: :runtime
77
- prerelease: false
78
- version_requirements: !ruby/object:Gem::Requirement
79
- requirements:
80
- - - ">="
81
- - !ruby/object:Gem::Version
82
- version: '0'
83
- - !ruby/object:Gem::Dependency
84
- name: zip-zip
85
- requirement: !ruby/object:Gem::Requirement
86
- requirements:
87
- - - ">="
73
+ - - "~>"
88
74
  - !ruby/object:Gem::Version
89
- version: '0'
75
+ version: 3.0.1
90
76
  type: :runtime
91
77
  prerelease: false
92
78
  version_requirements: !ruby/object:Gem::Requirement
93
79
  requirements:
94
- - - ">="
80
+ - - "~>"
95
81
  - !ruby/object:Gem::Version
96
- version: '0'
82
+ version: 3.0.1
97
83
  description: |-
98
84
  This gem should help reduce the efforts in the admin panel.
99
85
  It has search, sort and pagination included
@@ -120,6 +106,18 @@ files:
120
106
  - bin/console
121
107
  - bin/setup
122
108
  - config/routes.rb
109
+ - lib/generators/spotlight_search/filter_generator.rb
110
+ - lib/generators/spotlight_search/install_generator.rb
111
+ - lib/generators/spotlight_search/templates/application.css.scss
112
+ - lib/generators/spotlight_search/templates/application.js
113
+ - lib/generators/spotlight_search/templates/coffee.js
114
+ - lib/generators/spotlight_search/templates/controller.rb.erb
115
+ - lib/generators/spotlight_search/templates/environment.js
116
+ - lib/generators/spotlight_search/templates/filters.html.erb
117
+ - lib/generators/spotlight_search/templates/scaffolds.coffee
118
+ - lib/generators/spotlight_search/templates/spotlight_search.rb
119
+ - lib/generators/spotlight_search/templates/webpacker.yml
120
+ - lib/generators/spotlight_search/templates/webpacker_gem_assets.rb
123
121
  - lib/spotlight_search.rb
124
122
  - lib/spotlight_search/engine.rb
125
123
  - lib/spotlight_search/exceptions.rb