spotlight_search 0.1.7 → 0.2.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (27) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile.lock +82 -71
  3. data/README.md +92 -45
  4. data/app/controllers/spotlight_search/export_jobs_controller.rb +7 -7
  5. data/app/jobs/spotlight_search/export_job.rb +50 -20
  6. data/app/mailers/spotlight_search/export_mailer.rb +6 -0
  7. data/app/views/spotlight_search/export_mailer/send_error_message.html.erb +7 -0
  8. data/lib/generators/spotlight_search/filter_generator.rb +18 -0
  9. data/lib/generators/spotlight_search/install_generator.rb +31 -0
  10. data/lib/generators/spotlight_search/templates/application.js +15 -0
  11. data/lib/generators/spotlight_search/templates/coffee.js +6 -0
  12. data/lib/generators/spotlight_search/templates/controller.rb.erb +91 -0
  13. data/lib/generators/spotlight_search/templates/environment.js +19 -0
  14. data/lib/generators/spotlight_search/templates/filters.html.erb +12 -0
  15. data/lib/generators/spotlight_search/templates/scaffolds.coffee +6 -0
  16. data/lib/generators/spotlight_search/templates/spotlight_search.rb +1 -0
  17. data/lib/generators/spotlight_search/templates/webpacker.yml +102 -0
  18. data/lib/generators/spotlight_search/templates/webpacker_gem_assets.rb +55 -0
  19. data/lib/spotlight_search.rb +10 -1
  20. data/lib/spotlight_search/exceptions.rb +1 -1
  21. data/lib/spotlight_search/exportable_columns.rb +27 -32
  22. data/lib/spotlight_search/exportable_columns_v2.rb +90 -0
  23. data/lib/spotlight_search/helpers.rb +58 -9
  24. data/lib/spotlight_search/utils.rb +69 -0
  25. data/lib/spotlight_search/version.rb +1 -1
  26. data/spotlight_search.gemspec +3 -4
  27. metadata +27 -27
@@ -6,5 +6,11 @@ module SpotlightSearch
6
6
  attachments[file_path.split('/').last] = File.read(file_path)
7
7
  mail(to: email, subject: subject)
8
8
  end
9
+
10
+ def send_error_message(email, err)
11
+ @error_message = err.message
12
+ mail(to: email, subject: "Error generating CSV file")
13
+ Rollbar.error(err)
14
+ end
9
15
  end
10
16
  end
@@ -0,0 +1,7 @@
1
+ Hi,
2
+ <br>
3
+ There was an error autoexporting the CSV file:
4
+ <%= @error_message %>
5
+ Please find attached the exported contents.
6
+ <br>
7
+ Thanks
@@ -0,0 +1,18 @@
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
+ template 'filters.html.erb', "app/views/admin/#{model}/_filters.html.slim"
12
+ template 'controller.rb.erb', "app/controllers/admin/#{model}_controller.rb"
13
+ end
14
+ end
15
+
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,31 @@
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
+ route "mount SpotlightSearch::Engine => '/spotlight_search'"
15
+ end
16
+
17
+ def add_essentials
18
+ system("yarn add jquery")
19
+ system("yarn add coffeescript")
20
+ system("yarn add select2")
21
+ inject_into_file 'app/assets/stylesheets/application.css.scss', before: " */" do
22
+ " *= require select2\n"
23
+ end
24
+ template "application.js", "app/javascript/packs/application.js"
25
+ template 'scaffolds.coffee', "app/javascript/application/coffee_scripts/scaffolds.coffee"
26
+ gem 'kaminari', '~> 1.2.1' unless File.readlines("Gemfile").grep(/kaminari/).size > 0
27
+ end
28
+
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,15 @@
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
+
12
+ import jQuery from 'jquery';
13
+ window.$ = jQuery
14
+ window.jQuery = jQuery
15
+ import 'select2';
@@ -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 %>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 %> = Profile.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 %> = Profile.new(<%= model.singularize %>_params)
36
+
37
+ respond_to do |format|
38
+ if @<%= model.singularize %>.save
39
+ format.html { redirect_to @<%= model.singularize %>, notice: 'Profile 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 @<%= model.singularize %>, notice: 'Profile 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 <%= model.singularize %>s_url, notice: 'Profile 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 %> = Profile.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,19 @@
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
+ })
10
+ )
11
+
12
+ const { add_paths_to_environment } = require(
13
+ // `${environment.plugins.get('Environment').defaultValues["PWD"]}/config/environments/_add_gem_paths`
14
+ `/tmp/_add_gem_paths`
15
+ )
16
+ add_paths_to_environment(environment)
17
+
18
+ environment.loaders.prepend('coffee', coffee)
19
+ module.exports = environment
@@ -0,0 +1,12 @@
1
+ = filter_wrapper({filter_url: '/admin/<%= model %>', replacement_class: "<%= model %>-table"})
2
+ <%- @options.filters.each do |filter| -%>
3
+ <%- filter_arr = filter.split(':') -%>
4
+ <%- if filter_arr[1].eql?('input') -%>
5
+ = cm_textfield_tag({behaviour: "filter", scope: "<%= filter_arr[0] %>", type: "input-filter"}, nil, "<%= filter_arr[0].titleize %>")
6
+ <%- elsif filter_arr[1].eql?('select') -%>
7
+ = cm_select_tag([["<%= model.titleize %>", "<%= model %>"]], {behaviour: 'filter', scope: "<%= filter_arr[0] %>", type: 'select-filter', placeholder: ''}, "select2-single")
8
+ <%- elsif filter_arr[1].eql?('multi_select') -%>
9
+ = cm_multi_select_tag([["<%= model.titleize %>", "<%= model %>"]], {behaviour: 'filter', scope: "<%= filter_arr[0] %>", type: 'select-filter', placeholder: ''}, "select2-multiple")
10
+ <%- end -%>
11
+ <%- end -%>
12
+ = clear_filters(admin_<%= model %>_path, nil, nil, "Clear all")
@@ -0,0 +1,6 @@
1
+ $(document).on "turbolinks:load", () ->
2
+ $('.select2-multiple').select2()
3
+ $('.select2-single').select2(
4
+ allowClear: true
5
+ )
6
+
@@ -0,0 +1 @@
1
+ ActiveRecord::Base.include SpotlightSearch::ExportableColumns
@@ -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
@@ -1,6 +1,8 @@
1
1
  require 'spotlight_search/engine'
2
2
  require 'spotlight_search/version'
3
3
  require 'spotlight_search/exportable_columns'
4
+ require 'spotlight_search/exportable_columns_v2'
5
+ require 'spotlight_search/utils'
4
6
  require 'spotlight_search/railtie' if defined?(Rails)
5
7
  require 'active_support'
6
8
  require 'active_support/rails'
@@ -10,10 +12,17 @@ module SpotlightSearch
10
12
 
11
13
  autoload :Exceptions, 'spotlight_search/exceptions'
12
14
 
15
+ def self.setup
16
+ yield self
17
+ end
18
+
19
+ mattr_accessor :exportable_columns_version
20
+ @@exportable_columns_version = :v1
21
+
13
22
  module ClassMethods
14
23
  def filter_by(page, filter_params = {}, sort_params = {})
15
24
  filtered_result = OpenStruct.new
16
- sort_column = self.column_names.include?(sort_params[:sort_column]) ? sort_params[:sort_column] : "created_at"
25
+ sort_column = self.column_names.include?(sort_params[:sort_column]) ? sort_params[:sort_column] : "#{self.table_name}.created_at"
17
26
  sort_direction = %w[asc desc].include?(sort_params[:sort_direction]) ? sort_params[:sort_direction] : "asc"
18
27
  sort_params = {sort_column: sort_column, sort_direction: sort_direction}
19
28
  raw_data = self.filter(filter_params).sort_list(sort_column, sort_direction)
@@ -1,7 +1,7 @@
1
1
  module SpotlightSearch
2
2
  module Exceptions
3
3
  class InvalidColumns < StandardError
4
- def initialize(columns: [])
4
+ def initialize(columns = [])
5
5
  message = 'Invalid columns found: ' + columns.map(&:to_s).join(', ')
6
6
  super(message)
7
7
  end
@@ -5,7 +5,7 @@ module SpotlightSearch
5
5
  module ClassMethods
6
6
  # Enables or disables export and specifies which all columns can be
7
7
  # exported. For enabling export for all columns in all models
8
- #
8
+ #
9
9
  # class ApplicationRecord < ActiveRecord::Base
10
10
  # export_columns enabled: true
11
11
  # end
@@ -16,7 +16,7 @@ module SpotlightSearch
16
16
  # export_columns enabled: false
17
17
  # end
18
18
  #
19
- # For allowing export for only specific columns in a model
19
+ # For allowing export for only specific columns in a model
20
20
  #
21
21
  # class Person < ActiveRecord::Base
22
22
  # export_columns enabled: true, only: [:created_at, :updated_at]
@@ -28,41 +28,36 @@ module SpotlightSearch
28
28
  # export_columns enabled: true, except: [:created_at, :updated_at]
29
29
  # end
30
30
  #
31
- def export_columns(enabled: false, only: nil, except: nil)
32
- begin
33
- unless ActiveRecord::Base.connection.migration_context.needs_migration?
34
- if enabled
35
- self.export_enabled = true
36
- all_columns = self.column_names.map(&:to_sym)
37
- if only.present?
38
- unless (valid_columns = only & all_columns).size == only.size
39
- invalid_columns = only - valid_columns
40
- raise SpotlightSearch::Exceptions::InvalidColumns.new(nil, invalid_columns)
41
- end
42
- self.enabled_columns = only
43
- else
44
- self.enabled_columns = all_columns
45
- end
46
- if except.present?
47
- unless (valid_columns = except & all_columns).size == except.size
48
- invalid_columns = except - valid_columns
49
- raise SpotlightSearch::Exceptions::InvalidColumns.new(nil, invalid_columns)
50
- end
51
- self.enabled_columns = self.enabled_columns - except
52
- end
53
- else
54
- self.export_enabled = false
55
- self.enabled_columns = nil
56
- end
31
+ def export_columns(enabled: false, only: nil, except: nil, associated: nil)
32
+ ActiveRecord::Base.connection.migration_context.needs_migration? && return
33
+ return unless enabled
34
+
35
+ self.export_enabled = true
36
+ all_columns = self.column_names.map(&:to_sym)
37
+ if only.present?
38
+ unless (valid_columns = only & all_columns).size == only.size
39
+ invalid_columns = only - valid_columns
40
+ raise SpotlightSearch::Exceptions::InvalidColumns, invalid_columns
41
+ end
42
+ self.enabled_columns = only
43
+ else
44
+ self.enabled_columns = all_columns
45
+ end
46
+ if except.present?
47
+ unless (valid_columns = except & all_columns).size == except.size
48
+ invalid_columns = except - valid_columns
49
+ raise SpotlightSearch::Exceptions::InvalidColumns, invalid_columns
57
50
  end
58
- rescue ActiveRecord::NoDatabaseError
51
+ self.enabled_columns = self.enabled_columns - except
59
52
  end
53
+ rescue ActiveRecord::NoDatabaseError
54
+ Rails.logger.info("No database error")
60
55
  end
61
56
 
62
57
  # Validates whether the selected columns are allowed for export
63
58
  def validate_exportable_columns(columns)
64
59
  unless columns.is_a?(Array)
65
- raise SpotlightSearch::Exceptions::InvalidValue.new('Excepted Array. Invalid type received')
60
+ raise SpotlightSearch::Exceptions::InvalidValue.new('Expected Array. Invalid type received')
66
61
  end
67
62
  unless (self.enabled_columns & columns.map(&:to_sym)) == columns.size
68
63
  return false
@@ -72,8 +67,8 @@ module SpotlightSearch
72
67
  end
73
68
 
74
69
  included do
75
- class_attribute :enabled_columns, instance_accessor: false
76
- class_attribute :export_enabled, instance_accessor: false
70
+ class_attribute :enabled_columns, instance_accessor: false, default: nil
71
+ class_attribute :export_enabled, instance_accessor: false, default: false
77
72
  end
78
73
  end
79
74
  end