five-two-nw-olivander 0.2.0.1 → 0.2.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5d247c42715b68ca77e28f0b8d99f48b466d042ba197aad6a0fa5694d344d7d3
4
- data.tar.gz: 5d4f1e94e9c1d85378a0586481ecf276b34d65364fb341e95ae9020f437293f2
3
+ metadata.gz: 76ede3e2ce50954cf786b9b30fabed5c294bb1b174a78f8493e331be73eb1b14
4
+ data.tar.gz: 7f23d18fe4144d9a0ce8829be386033a8e29e116186590d00c66339adbfdbddc
5
5
  SHA512:
6
- metadata.gz: 336beef33e5b2f9b3242a654d9de9b5cb2b19ef30b25b62ccb0b2bbb74753afbdddf027a289ec6dc65d873e9a53acab6998983f0394aa8162a1c516976c8f8f7
7
- data.tar.gz: aee825f87643bebac907ccfdf499b1f8d76f1a8e4049f58fa35856eaea663f8d175f808f7b04aa56b1ff0b704f7e1a7c322d6568e945b555c01423c0e6ec29e9
6
+ metadata.gz: 9fffc213421e65a2c263771e6071d7ff4f8ca97b74b2f9bb30eb7be49180cb97da2beda9bebd2b68e7117504a35b8ecfadfa39056ab17950a69d5dc076ba837f
7
+ data.tar.gz: 17a316a14e4406b136158ef9100bca6de6249e3ac96eb600dab8983d7f8b6cd21d5a6723e6d2ee3d1715ee4d0529151b82a5948402de517b5af37565f45f6832
@@ -1 +1,5 @@
1
1
  //= link_directory ../stylesheets/olivander .css
2
+ //= link controllers/datatable_index_charts_controller.js
3
+ //= link controllers/datatable_expandable_chart_controller.js
4
+ //= link controllers/turbo_flash_controller.js
5
+ //= link controllers/input_control_association_controller.js
@@ -11,13 +11,13 @@ $.fn.select2.defaults.set('dropdownParent', $('#modal-root'))
11
11
  #
12
12
  # TODO: Recheck with the select2 GH issue and remove once this is fixed on their side
13
13
  #
14
- $(document).on 'select2:open', () =>
15
- document.querySelector('.select2-search__field').focus()
14
+ $(document).on 'select2:open', (evt) =>
15
+ evt.target.parent.querySelector('.select2-search__field').focus()
16
16
 
17
17
  initSelect2s = () -> $('select').not('.no-select2').each (k,v) =>
18
18
  $(v).select2({ dropdownParent: $(v).parent() })
19
19
 
20
- $(document).ready -> initSelect2s()
20
+ # $(document).ready -> initSelect2s()
21
21
  $(document).on 'show.bs.modal', (e) =>
22
22
  $('select').not('.no-select2').each (k,v) =>
23
23
  $(v).select2({ dropdownParent: $(v).parent() })
@@ -0,0 +1,25 @@
1
+ import { Controller } from "@hotwired/stimulus"
2
+
3
+ // Connects to data-controller="input-control-association"
4
+ export default class extends Controller {
5
+ connect() {
6
+ var self = this,
7
+ el = self.element;
8
+ if (!$(el).hasClass("select2-hidden-accessible")) {
9
+ $(el).select2({
10
+ dropdownParent: $(el).parent(),
11
+ ajax: {
12
+ url: el.dataset.collectionPath,
13
+ delay: 250,
14
+ minimumInputLength: 2,
15
+ dataType: 'json',
16
+ processResults: function(data) {
17
+ return { results: data.map(function(map) {
18
+ return { id: map.id, text: map.text || map.name || map.description };
19
+ }) };
20
+ }
21
+ }
22
+ })
23
+ }
24
+ }
25
+ }
@@ -6,8 +6,10 @@
6
6
  %div{ class: section.column_class }
7
7
  - case field.type
8
8
  - when :association
9
- = @f.association field.sym, disabled: !field.editable, input_html: { data: { controller: "input-control-#{field.type}" } }
9
+ - controllers = "#{field.type}-#{@resource.class.name.underscore}-#{field.sym} input-control-#{field.type}"
10
+ - collection_path = polymorphic_path(@resource.class.reflect_on_association(field.sym).klass, format: :json)
11
+ = @f.association field.sym, collection: [@f.object.send(field.sym)].flatten, disabled: !field.editable, input_html: { data: { collection_path: collection_path, controller: controllers } }
10
12
  - when :boolean
11
13
  = @f.input field.sym, disabled: !field.editable, as: field.type.to_sym, input_html: { data: { controller: "input-control-#{field.type}" } }, wrapper: :checkbox
12
14
  - else
13
- = @f.input field.sym, disabled: !field.editable, as: field.type.to_sym, input_html: { data: { controller: "input-control-#{field.type}" } }
15
+ = @f.input field.sym, disabled: !field.editable, as: field.type.to_sym, input_html: { rows: 10, data: { controller: "input-control-#{field.type}" } }
@@ -0,0 +1,24 @@
1
+ module Olivander
2
+ module Resources
3
+ module ApplicationRecord
4
+ extend ActiveSupport::Concern
5
+
6
+ included do
7
+ def self.audited_as klazz
8
+ # Rails.logger.debug "#{self.class.name} is audited as #{klazz.name}"
9
+ @@audited_user_class = klazz
10
+
11
+ belongs_to :created_by, class_name: klazz.name
12
+ belongs_to :updated_by, class_name: klazz.name
13
+
14
+ before_validation :set_audit_user
15
+ end
16
+
17
+ def set_audit_user
18
+ self.created_by ||= @@audited_user_class.current
19
+ self.updated_by = @@audited_user_class.current
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -33,16 +33,16 @@ module Olivander
33
33
  self.resource_field_group_collection
34
34
  end
35
35
 
36
- def self.auto_resource_fields(columns: 2, only: [])
36
+ def self.auto_resource_fields(columns: 2, only: [], editable: true)
37
37
  return unless ActiveRecord::Base.connection.table_exists?(table_name)
38
38
 
39
39
  if current_resource_field_group.nil?
40
40
  resource_field_group do
41
- auto_resource_fields(columns: columns, only: only)
41
+ auto_resource_fields(columns: columns, only: only, editable: editable)
42
42
  end
43
43
  elsif current_resource_field_group.forced_section.nil?
44
44
  resource_field_section(columns) do
45
- auto_resource_fields(columns: columns, only: only)
45
+ auto_resource_fields(columns: columns, only: only, editable: editable)
46
46
  end
47
47
  else
48
48
  if only.size.zero?
@@ -59,21 +59,19 @@ module Olivander
59
59
  type = att.type
60
60
  next unless inc == sym
61
61
 
62
- resource_field sym, type
62
+ resource_field sym, type, editable: editable
63
63
  end
64
64
 
65
65
  reflections.map{ |x| x[1] }
66
66
  .filter{ |x| x.foreign_key == inc || x.name == inc }
67
67
  .each do |r|
68
- sym = r.name
69
- type = :association
70
- resource_field sym, type
68
+ resource_field r.name, :association, editable: editable
71
69
  end
72
70
 
73
71
  next unless respond_to?(:attachment_definitions)
74
72
 
75
73
  attachment_definitions.filter{ |x| x == inc }.each do |ad|
76
- resource_field ad[0], :file
74
+ resource_field ad[0], :file, editable: editable
77
75
  end
78
76
  end
79
77
  end
@@ -0,0 +1,38 @@
1
+ module Olivander
2
+ module Resources
3
+ module CrudController
4
+ extend ActiveSupport::Concern
5
+
6
+ included do
7
+ include Effective::CrudController
8
+ layout 'olivander/adminlte/main'
9
+
10
+ def index
11
+ if params[:term].present?
12
+ index_search
13
+ else
14
+ super
15
+ end
16
+ end
17
+
18
+ def index_search
19
+ self.resources ||= resource_scope.all if resource_scope.respond_to?(:all)
20
+ if resource_scope.respond_to?(:search_for)
21
+ self.resources = self.resources.search_for(params[:term])
22
+ else
23
+ k = resources.klass
24
+ like_term = "%#{ActiveRecord::Base.sanitize_sql_like(params[:term])}%"
25
+ fields = %w[name title description text].keep_if{ |field| k.respond_to?(field) }
26
+ clauses = fields.map{ |field| "#{field} ilike '#{like_term}'" }.join(' or ')
27
+ orders = fields.join(', ')
28
+ self.resources = self.resources.where(clauses).order(orders) if clauses.length.positive?
29
+ end
30
+ end
31
+
32
+ def permitted_params
33
+ params.fetch(resource_klass.name.underscore.gsub('/', '_').to_sym, {}).permit!
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,41 @@
1
+ class CustomFormBuilder < SimpleForm::FormBuilder
2
+ def initialize(*)
3
+ super
4
+ end
5
+
6
+ def association(association, options = {}, &block)
7
+ resolve_custom_input_association(association, options)
8
+ super(association, options, &block)
9
+ end
10
+
11
+ def resolve_custom_input_association(association, options)
12
+ return if options[:as].present?
13
+
14
+ [
15
+ "#{object.class.name.demodulize.underscore}_#{association.to_s}".to_sym, association
16
+ ].each do |key|
17
+ camelized = "#{key.to_s.camelize}Input"
18
+ mapping = attempt_mapping_with_custom_namespace(camelized) ||
19
+ attempt_mapping(camelized, Object) ||
20
+ attempt_mapping(camelized, self.class)
21
+
22
+ next unless mapping.present?
23
+
24
+ options[:as] = key
25
+ break
26
+ end
27
+ end
28
+
29
+ private
30
+
31
+ def fetch_association_collection(reflection, options)
32
+ options_method = "options_for_#{reflection.name}".to_sym
33
+ if object.respond_to?(options_method) then
34
+ options.fetch(:collection) do
35
+ object.send(options_method)
36
+ end
37
+ else
38
+ super(reflection, options)
39
+ end
40
+ end
41
+ end
@@ -1,5 +1,5 @@
1
1
  - read_only = !%w[new create edit update].include?(action_name)
2
- = simple_form_for(@resource) do |f|
2
+ = simple_form_for(@resource, builder: CustomFormBuilder) do |f|
3
3
  .card.card-primary
4
4
  .card-header
5
5
  %h3.card-title= @resource.to_s.blank? ? @resource.model_name.human : @resource
@@ -70,16 +70,49 @@ SimpleForm.setup do |config|
70
70
  config.wrappers :checkbox, class: "form-check",
71
71
  hint_class: :field_with_hint, error_class: :field_with_errors, valid_class: :field_without_errors do |b|
72
72
  b.use :html5
73
- b.use :placeholder
74
- b.optional :maxlength
75
- b.optional :minlength
76
- b.optional :pattern
77
- b.optional :min_max
78
73
  b.optional :readonly
79
- b.use :input, class: 'form-check-input'
80
- b.use :label #, class: 'form-control'
81
- b.use :hint, wrap_with: { tag: :span, class: :hint }
82
- b.use :error, wrap_with: { tag: :span, class: "text-danger" }
74
+ b.wrapper :legend_tag, tag: 'legend', class: 'col-form-label pt-0' do |ba|
75
+ ba.use :label_text
76
+ end
77
+ b.use :input, class: 'form-check-input', error_class: 'is-invalid', valid_class: 'is-valid'
78
+ b.use :full_error, wrap_with: { tag: 'div', class: 'invalid-feedback d-block' }
79
+ b.use :hint, wrap_with: { tag: 'small', class: 'form-text text-muted' }
80
+ end
81
+
82
+ # vertical input for boolean
83
+ config.wrappers :vertical_boolean, tag: 'fieldset', class: 'form-group', error_class: 'form-group-invalid', valid_class: 'form-group-valid' do |b|
84
+ b.use :html5
85
+ b.optional :readonly
86
+ b.wrapper :form_check_wrapper, tag: 'div', class: 'form-check' do |bb|
87
+ bb.use :input, class: 'form-check-input' #, error_class: 'is-invalid', valid_class: 'is-valid'
88
+ bb.use :label, class: 'form-check-label'
89
+ bb.use :full_error, wrap_with: { tag: 'div', class: 'invalid-feedback' }
90
+ bb.use :hint, wrap_with: { tag: 'small', class: 'form-text text-muted' }
91
+ end
92
+ end
93
+
94
+ # vertical input for radio buttons and check boxes
95
+ config.wrappers :vertical_collection, item_wrapper_class: 'form-check', item_label_class: 'form-check-label', tag: 'fieldset', class: 'form-group', error_class: 'form-group-invalid', valid_class: 'form-group-valid' do |b|
96
+ b.use :html5
97
+ b.optional :readonly
98
+ b.wrapper :legend_tag, tag: 'legend', class: 'col-form-label pt-0' do |ba|
99
+ ba.use :label_text
100
+ end
101
+ b.use :input, class: 'form-check-input', error_class: 'is-invalid', valid_class: 'is-valid'
102
+ b.use :full_error, wrap_with: { tag: 'div', class: 'invalid-feedback d-block' }
103
+ b.use :hint, wrap_with: { tag: 'small', class: 'form-text text-muted' }
104
+ end
105
+
106
+ # vertical input for inline radio buttons and check boxes
107
+ config.wrappers :vertical_collection_inline, item_wrapper_class: 'form-check form-check-inline', item_label_class: 'form-check-label', tag: 'fieldset', class: 'form-group', error_class: 'form-group-invalid', valid_class: 'form-group-valid' do |b|
108
+ b.use :html5
109
+ b.optional :readonly
110
+ b.wrapper :legend_tag, tag: 'legend', class: 'col-form-label pt-0' do |ba|
111
+ ba.use :label_text
112
+ end
113
+ b.use :input, class: 'form-check-input', error_class: 'is-invalid', valid_class: 'is-valid'
114
+ b.use :full_error, wrap_with: { tag: 'div', class: 'invalid-feedback d-block' }
115
+ b.use :hint, wrap_with: { tag: 'small', class: 'form-text text-muted' }
83
116
  end
84
117
 
85
118
  config.wrappers :switch, class: "custom-control custom-switch",
@@ -170,10 +203,24 @@ SimpleForm.setup do |config|
170
203
  # Custom wrappers for input types. This should be a hash containing an input
171
204
  # type as key and the wrapper that will be used for all inputs with specified type.
172
205
  # config.wrapper_mappings = { string: :prepend }
206
+ config.wrapper_mappings = {
207
+ boolean: :vertical_boolean,
208
+ check_boxes: :check_box,
209
+ # date: :horizontal_multi_select,
210
+ # datetime: :horizontal_multi_select,
211
+ # file: :horizontal_file,
212
+ # radio_buttons: :horizontal_collection,
213
+ # range: :horizontal_range,
214
+ # time: :horizontal_multi_select
215
+ }
173
216
 
174
217
  # Namespaces where SimpleForm should look for custom input classes that
175
218
  # override default inputs.
176
- # config.custom_inputs_namespaces << "CustomInputs"
219
+ Dir.glob('app/inputs/**/')
220
+ .map{ |x| x.gsub('app/inputs/', '').split('/').reject(&:blank?).join('/').camelize }
221
+ .reject(&:blank?).each do |d|
222
+ config.custom_inputs_namespaces << d
223
+ end
177
224
 
178
225
  # Default priority for time_zone inputs.
179
226
  # config.time_zone_priority = nil
@@ -2,23 +2,17 @@ module Olivander
2
2
  class ApplicationContext
3
3
  attr_accessor :name, :logo, :company, :menu_items, :route_builder, :sign_out_path, :sidebar_background_class
4
4
 
5
- def self.default
6
- ctx = ApplicationContext.new
7
- ctx.company.name = 'Company Name'
5
+ def initialize(**kwargs)
6
+ self.name = kwargs[:name] || ENV['OLIVANDER_APP_NAME'] || 'Application Name'
7
+ self.logo = kwargs[:logo] || Logo.new(url: kwargs[:logo_url], alt: kwargs[:logo_alt])
8
+ self.company = kwargs[:company] || Company.new(name: kwargs[:company_name], url: kwargs[:company_url])
9
+ self.sign_out_path = kwargs[:sign_out_path] || '/sign_out'
10
+ self.menu_items = kwargs[:menu_items] || []
8
11
  begin
9
- ctx.route_builder = RouteBuilder.new
10
- rescue
11
- ctx.route_builder = OpenStruct.new(resources: [])
12
+ self.route_builder = RouteBuilder.new
13
+ rescue NameError
14
+ self.route_builder = OpenStruct.new(resources: [])
12
15
  end
13
- ctx
14
- end
15
-
16
- def initialize(name: 'Application Name', logo: Logo.new, company: Company.new, sign_out_path: '/sign_out', menu_items: [])
17
- self.name = name
18
- self.logo = logo
19
- self.company = company
20
- self.sign_out_path = sign_out_path
21
- self.menu_items = menu_items
22
16
  end
23
17
 
24
18
  def visible_modules
@@ -41,18 +35,18 @@ module Olivander
41
35
  class Logo
42
36
  attr_accessor :url, :alt
43
37
 
44
- def initialize(url: nil, alt: 'Logo')
45
- self.url = url
46
- self.alt = alt
38
+ def initialize(**kwargs)
39
+ self.url = kwargs[:url] || ENV['OLIVANDER_LOGO_URL'] || '/images/olivander_logo.png'
40
+ self.alt = kwargs[:alt] || ENV['OLIVANDER_LOGO_ALT'] || 'Logo Image'
47
41
  end
48
42
  end
49
43
 
50
44
  class Company
51
45
  attr_accessor :name, :url
52
46
 
53
- def initialize(name: nil, url: nil)
54
- self.url = url
55
- self.name = name
47
+ def initialize(**kwargs)
48
+ self.url = kwargs[:url] || ENV['OLIVANDER_COMPANY_URL'] || '/'
49
+ self.name = kwargs[:name] || ENV['OLIVANDER_COMPANY_NAME'] || 'Company Name'
56
50
  end
57
51
  end
58
52
  end
@@ -62,7 +56,7 @@ module Olivander
62
56
  attribute :user, :ability
63
57
 
64
58
  def application_context
65
- @application_context ||= ::Olivander::ApplicationContext.default
59
+ @application_context ||= ::Olivander::ApplicationContext.new
66
60
  end
67
61
  end
68
62
  end
@@ -1,3 +1,3 @@
1
1
  module Olivander
2
- VERSION = '0.2.0.1'.freeze
2
+ VERSION = '0.2.0.2'.freeze
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: five-two-nw-olivander
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0.1
4
+ version: 0.2.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Eric Dennis
@@ -208,6 +208,7 @@ files:
208
208
  - app/assets/javascripts/adminlte/select2_defaults.coffee
209
209
  - app/assets/javascripts/controllers/datatable_expandable_chart_controller.js
210
210
  - app/assets/javascripts/controllers/datatable_index_charts_controller.js
211
+ - app/assets/javascripts/controllers/input_control_association_controller.js
211
212
  - app/assets/javascripts/controllers/turbo_flash_controller.js
212
213
  - app/assets/javascripts/olivander/flash_toast.js
213
214
  - app/assets/stylesheets/adminlte.css
@@ -228,15 +229,17 @@ files:
228
229
  - app/components/olivander/components/table_portlet_component.html.haml
229
230
  - app/components/olivander/components/table_portlet_component.rb
230
231
  - app/components/olivander/components/table_portlet_component/table_component.html.haml
232
+ - app/controllers/concerns/olivander/resources/application_record.rb
231
233
  - app/controllers/concerns/olivander/resources/auto_form_attributes.rb
234
+ - app/controllers/concerns/olivander/resources/crud_controller.rb
232
235
  - app/controllers/concerns/olivander/resources/route_builder.rb
233
236
  - app/controllers/olivander/application_controller.rb
234
237
  - app/datatables/olivander/datatable.rb
235
238
  - app/helpers/olivander/application_helper.rb
239
+ - app/inputs/custom_form_builder.rb
236
240
  - app/inputs/date_time_input.rb
237
241
  - app/jobs/olivander/application_job.rb
238
242
  - app/mailers/olivander/application_mailer.rb
239
- - app/models/olivander/application_record.rb
240
243
  - app/views/application/_form.html.haml
241
244
  - app/views/application/_resource_form_actions.html.haml
242
245
  - app/views/application/edit.html.haml
@@ -1,20 +0,0 @@
1
- module Olivander
2
- class ApplicationRecord < ActiveRecord::Base
3
- self.abstract_class = true
4
-
5
- def self.audited_as klazz
6
- # Rails.logger.debug "#{self.class.name} is audited as #{klazz.name}"
7
- @@audited_user_class = klazz
8
-
9
- belongs_to :created_by, class_name: klazz.name
10
- belongs_to :updated_by, class_name: klazz.name
11
-
12
- before_validation :set_audit_user
13
- end
14
-
15
- def set_audit_user
16
- self.created_by ||= @@audited_user_class.current
17
- self.updated_by = @@audited_user_class.current
18
- end
19
- end
20
- end