five-two-nw-olivander 0.2.0.1 → 0.2.0.3

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: 2e9d0ccea420078110d4af7de4d7eec3c0ac04e8a8a2533302d5792a1d599c58
4
+ data.tar.gz: '09b69957d70478ef092e8eff4a979ee867ac74c903fe1572793016d8ab26f531'
5
5
  SHA512:
6
- metadata.gz: 336beef33e5b2f9b3242a654d9de9b5cb2b19ef30b25b62ccb0b2bbb74753afbdddf027a289ec6dc65d873e9a53acab6998983f0394aa8162a1c516976c8f8f7
7
- data.tar.gz: aee825f87643bebac907ccfdf499b1f8d76f1a8e4049f58fa35856eaea663f8d175f808f7b04aa56b1ff0b704f7e1a7c322d6568e945b555c01423c0e6ec29e9
6
+ metadata.gz: 07ce6181e19ada53a8d78cf650c8b4cef82ccb4d38b33a09cca9b340d71567d2a4889f613c5986afb85fb6cc32b0b6010999f9af05fe40ab1ff7ff3a45f291e5
7
+ data.tar.gz: 67fbcc49d403734676c0f8d46052585ed70e127878bd6f4490f7d94f104d02aa8bcd7827da5d39957182a4a7b9dcc3947b41e69425189844a34e1812684efe15
@@ -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
@@ -0,0 +1,42 @@
1
+ (function() {
2
+ var destroySelect2s, logEvent;
3
+
4
+ $.extend(true, $.fn.dataTable.Buttons.defaults, {
5
+ dom: {
6
+ button: {
7
+ className: 'btn btn-outline-primary btn-sm'
8
+ }
9
+ }
10
+ });
11
+
12
+ $.extend(true, $.fn.dataTable.ext.classes, {
13
+ sProcessing: "dataTables_processing card overlay-wrapper"
14
+ });
15
+
16
+ destroySelect2s = function() {
17
+ $('.effective-datatables-filters').find('select').select2('destroy');
18
+ return $('.dataTables_wrapper').each(function(_, o) {
19
+ try {
20
+ return $(o).find('.dataTables_length select.select2-hidden-accessible').addClass('no-select2').removeAttr('name').select2('destroy');
21
+ } catch (error) {}
22
+ });
23
+ };
24
+
25
+ logEvent = function(e) {
26
+ return console.log(e);
27
+ };
28
+
29
+ $(document).ready(function(e) {
30
+ return destroySelect2s();
31
+ });
32
+
33
+ // $(document).ready(function(e) {
34
+ // return $('.effective-datatables-filters input').click(function() {
35
+ // var $form, $table;
36
+ // $form = $(event.currentTarget).closest('.effective-datatables-filters');
37
+ // $table = $('#' + $form.attr('aria-controls'));
38
+ // return $table.DataTable().draw();
39
+ // });
40
+ // });
41
+
42
+ }).call(this);
@@ -11,13 +11,25 @@ $.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
+ try
16
+ evt.target.parent.querySelector('.select2-search__field').focus()
17
+ catch ex
18
+ evt.target.parentElement.querySelector('.select2-search__field').focus()
19
+
16
20
 
17
21
  initSelect2s = () -> $('select').not('.no-select2').each (k,v) =>
18
22
  $(v).select2({ dropdownParent: $(v).parent() })
19
23
 
20
- $(document).ready -> initSelect2s()
24
+ # $(document).ready -> initSelect2s()
21
25
  $(document).on 'show.bs.modal', (e) =>
22
26
  $('select').not('.no-select2').each (k,v) =>
23
27
  $(v).select2({ dropdownParent: $(v).parent() })
28
+
29
+ $(document).ready =>
30
+ $('.effective-datatables-filters').find('select').select2('destroy');
31
+ $('.dataTables_wrapper').each (_, o) =>
32
+ try
33
+ return $(o).find('.dataTables_length select.select2-hidden-accessible').addClass('no-select2').removeAttr('name').select2('destroy');
34
+ catch error
35
+ # don't care
@@ -19,3 +19,4 @@
19
19
  //= require "adminlte/dist/js/adminlte.js"
20
20
  //= require 'olivander/flash_toast'
21
21
  //= require "effective_datatables"
22
+ //= require "adminlte/datatable.fix.js"
@@ -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
+ }
@@ -5,9 +5,20 @@
5
5
  - section.fields.each do |field|
6
6
  %div{ class: section.column_class }
7
7
  - case field.type
8
- - when :association
9
- = @f.association field.sym, disabled: !field.editable, input_html: { data: { controller: "input-control-#{field.type}" } }
8
+ - when :association, :belongs_to_association, :has_many_association, :has_many_through_association, :has_and_belongs_to_many_reflection, :has_one_through_association
9
+ - reflection = @f.object.class.reflect_on_association(field.sym)
10
+ - controllers = "#{field.type}-#{@resource.class.name.underscore.gsub('/', '_')}-#{field.sym} input-control-association"
11
+ - begin
12
+ - collection_path = polymorphic_path(@resource.class.reflect_on_association(field.sym).klass, format: :json)
13
+ - rescue
14
+ - collection_path = ''
15
+ - collection = @f.object.send(field.sym)
16
+ - case field.type
17
+ - when :has_one_through_association
18
+ = @f.input field.sym, selected: collection, collection: [collection].flatten, disabled: !field.editable, input_html: { data: { collection_path: collection_path, controller: controllers } }
19
+ -else
20
+ = @f.association field.sym, collection: [collection].flatten, disabled: !field.editable, input_html: { data: { collection_path: collection_path, controller: controllers } }
10
21
  - when :boolean
11
22
  = @f.input field.sym, disabled: !field.editable, as: field.type.to_sym, input_html: { data: { controller: "input-control-#{field.type}" } }, wrapper: :checkbox
12
23
  - else
13
- = @f.input field.sym, disabled: !field.editable, as: field.type.to_sym, input_html: { data: { controller: "input-control-#{field.type}" } }
24
+ = @f.input field.sym, disabled: !field.editable, as: field.type.to_sym, input_html: { rows: 10, data: { controller: "input-control-#{field.type}" } }
@@ -23,14 +23,20 @@
23
23
  - when :boolean
24
24
  - icon_class = val ? 'fa-check text-success' : 'fa-times text-danger'
25
25
  %i.fa{ class: icon_class }
26
- - when :association
26
+ - when :association, :belongs_to_association, :has_many_association, :has_many_through_association, :has_and_belongs_to_many_reflection, :has_one_through_association
27
27
  - if val.present?
28
28
  - if val.is_a?(ActiveRecord::Associations::CollectionProxy)
29
29
  %ul
30
30
  - val.each do |val1|
31
- %li= link_to val1
31
+ - begin
32
+ %li= link_to val1
33
+ - rescue
34
+ %li= val1
32
35
  - else
33
- = link_to val if val.present?
36
+ - begin
37
+ = link_to val if val.present?
38
+ - rescue
39
+ = val if val.present?
34
40
  - when :file
35
41
  - if val.present?
36
42
  - if val.content_type.include?('image')
@@ -38,7 +44,6 @@
38
44
  - else
39
45
  = link_to val, val.expiring_url
40
46
  - else
41
- = f.type
42
47
  = val
43
48
  - (section.columns-slice.size).times do
44
49
  %th
@@ -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: [], except: [], 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, except: except, 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, except: except, editable: editable)
46
46
  end
47
47
  else
48
48
  if only.size.zero?
@@ -53,27 +53,30 @@ module Olivander
53
53
  only << attachment_definitions.select{ |x| x[0] } if respond_to?(:attachment_definitions)
54
54
  only = only.flatten - SKIPPED_ATTRIBUTES
55
55
  end
56
+ only = only - except
56
57
  only.each do |inc|
57
58
  self.columns.each do |att|
58
59
  sym = att.name.to_sym
59
60
  type = att.type
60
61
  next unless inc == sym
61
62
 
62
- resource_field sym, type
63
+ resource_field sym, type, editable: editable
63
64
  end
64
65
 
65
66
  reflections.map{ |x| x[1] }
66
67
  .filter{ |x| x.foreign_key == inc || x.name == inc }
67
68
  .each do |r|
68
- sym = r.name
69
- type = :association
70
- resource_field sym, type
69
+ begin
70
+ resource_field(r.name, r.association_class.name.demodulize.underscore.to_sym, editable: editable)
71
+ rescue NotImplementedError
72
+ resource_field(r.name, :association, editable: editable)
73
+ end
71
74
  end
72
75
 
73
76
  next unless respond_to?(:attachment_definitions)
74
77
 
75
78
  attachment_definitions.filter{ |x| x == inc }.each do |ad|
76
- resource_field ad[0], :file
79
+ resource_field ad[0], :file, editable: editable
77
80
  end
78
81
  end
79
82
  end
@@ -0,0 +1,39 @@
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 request.format == :json && params[:_type].present? && params[:_type] == 'query'
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
+ self.resources = self.resources.limit(25)
31
+ end
32
+
33
+ def permitted_params
34
+ params.fetch(resource_klass.name.underscore.gsub('/', '_').to_sym, {}).permit!
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
@@ -3,12 +3,12 @@ module Olivander
3
3
  class ResourceAction
4
4
  attr_accessor :sym, :action, :verb, :confirm, :turbo_frame, :collection,
5
5
  :controller, :crud_action, :show_in_form, :show_in_datatable,
6
- :no_route, :path_helper, :confirm_with
6
+ :no_route, :path_helper, :confirm_with, :primary
7
7
 
8
8
  def initialize(sym, action: nil, controller: nil, verb: :get, confirm: false,
9
9
  turbo_frame: nil, collection: false, crud_action: false,
10
10
  show_in_form: true, show_in_datatable: true, no_route: false,
11
- path_helper: nil, confirm_with: nil)
11
+ path_helper: nil, confirm_with: nil, primary: nil)
12
12
  self.sym = sym
13
13
  self.action = action || sym
14
14
  self.controller = controller
@@ -22,6 +22,7 @@ module Olivander
22
22
  self.no_route = no_route
23
23
  self.path_helper = path_helper
24
24
  self.confirm_with = confirm_with
25
+ self.primary = primary || crud_action
25
26
  end
26
27
 
27
28
  def args_hash(options = nil)
@@ -131,7 +132,7 @@ module Olivander
131
132
 
132
133
  def action(sym, verb: :get, confirm: false, turbo_frame: nil, collection: false, show_in_datatable: true,
133
134
  show_in_form: true, no_route: false, controller: nil, action: nil, path_helper: nil,
134
- confirm_with: nil
135
+ confirm_with: nil, primary: nil
135
136
  )
136
137
  raise 'Must be invoked in a resource block' unless current_resource.present?
137
138
 
@@ -139,7 +140,7 @@ module Olivander
139
140
  current_resource.actions << ResourceAction.new(
140
141
  sym, action: action, controller: controller, verb: verb, confirm: confirm, turbo_frame: turbo_frame, collection: collection,
141
142
  show_in_datatable: show_in_datatable, show_in_form: show_in_form, no_route: no_route, path_helper: path_helper,
142
- confirm_with: confirm_with
143
+ confirm_with: confirm_with, primary: primary
143
144
  )
144
145
  end
145
146
 
@@ -73,6 +73,14 @@ module Olivander
73
73
  render partial: 'resource_form_actions', locals: { actions: authorized_resource_actions(resource, for_action: for_action).select(&:show_in_form) }
74
74
  end
75
75
 
76
+ def resource_form_action_tooltip(resource, action)
77
+ key = resource.class.name.underscore
78
+ return I18n.t("activerecord.actions.#{key}.#{action}-tooltip") if I18n.exists?("activerecord.actions.#{key}.#{action}-tooltip")
79
+ return I18n.t("activerecord.actions.#{action}-tooltip") if I18n.exists?("activerecord.actions.#{action}-tooltip")
80
+
81
+ action.to_s.titleize
82
+ end
83
+
76
84
  def resource_form_action_label(resource, action)
77
85
  key = resource.class.name.underscore
78
86
  return I18n.t("activerecord.actions.#{key}.#{action}") if I18n.exists?("activerecord.actions.#{key}.#{action}")
@@ -95,7 +103,7 @@ module Olivander
95
103
  end
96
104
 
97
105
  def current_user
98
- Olivander::CurrentContext.user || OpenStruct.new({ display_name: 'No User Set' })
106
+ Olivander::CurrentContext.user
99
107
  end
100
108
 
101
109
  def current_ability
@@ -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
@@ -4,21 +4,27 @@
4
4
  -# - data = a.turbo_frame.present? ? { turbo: true, turbo_frame: a.turbo_frame } : {}
5
5
  -# = dropdown_link_to resource_form_action_label(resource, a.sym), path, data: data
6
6
  - actions = authorized_resource_actions(resource, for_action: action_name).select{ |x| x.show_in_datatable }
7
- - crud_actions = actions.select{ |a| a.crud_action }
8
- - non_crud_actions = actions.select{ |a| !a.crud_action }
7
+ - primary_actions = actions.select{ |a| a.primary }
8
+ - non_primary_actions = actions.select{ |a| !a.primary }
9
9
  .btn-group
10
- - if non_crud_actions.size.positive?
10
+ - if non_primary_actions.size.positive?
11
11
  .btn-group
12
12
  %button.btn.btn-sm.dropdown-toggle{ type: :button, data: { toggle: 'dropdown' }}
13
13
  %ul.dropdown-menu
14
- - non_crud_actions.each do |a|
14
+ - non_primary_actions.each do |a|
15
15
  - path = a.path_helper.is_a?(Proc) ? a.path_helper.call(resource) : send(a.path_helper, resource.id)
16
- - data = a.turbo_frame.present? ? { turbo: true, turbo_frame: a.turbo_frame } : {}
16
+ - hash = {}
17
+ - data = a.turbo_frame.present? ? { turbo: true, turbo_frame: a.turbo_frame, turbo_method: a.verb } : {}
18
+ - hash[:data] = data
19
+ - hash[:method] = a.verb unless a.turbo_frame.present?
17
20
  %li
18
- = dropdown_link_to resource_form_action_label(resource, a.sym), path, data: data, method: a.verb
19
- - crud_actions.each do |a|
21
+ = dropdown_link_to resource_form_action_label(resource, a.sym), path, hash
22
+ - primary_actions.each do |a|
20
23
  - path = a.path_helper.is_a?(Proc) ? a.path_helper.call(resource) : send(a.path_helper, resource.id)
21
24
  - icon_class = (a.verb == :delete ? '' : '')
22
- = link_to path, a.args_hash(title: resource_form_action_label(resource, a.sym), class: "btn btn-sm #{icon_class}") do
23
- %i{ class: resource_form_action_icon(resource, a.sym), style: 'display: block; font-size: 10px' }
24
- %span{ style: 'font-size: 12px' }= resource_form_action_label(resource, a.sym)
25
+ = link_to path, a.args_hash(title: resource_form_action_tooltip(resource, a.sym), class: "btn btn-sm #{icon_class}") do
26
+ - action_label = resource_form_action_label(resource, a.sym)
27
+ - icon_font_size = action_label.blank? ? '18px' : '10px'
28
+ %i{ class: resource_form_action_icon(resource, a.sym), style: "display: block; font-size: #{icon_font_size}" }
29
+ - unless action_label.blank?
30
+ %span{ style: 'font-size: 12px' }= action_label
@@ -101,20 +101,21 @@
101
101
  -# %a.dropdown-item.dropdown-footer{:href => "#"} See All Notifications
102
102
  %li.nav-item.dropdown.user-menu
103
103
  %a.nav-link.dropdown-toggle{"data-toggle" => "dropdown", :href => "#"}
104
- %img.user-image.img-circle.elevation-2{:alt => "User Image", :src => image_path(user_image_path(current_user))}/
104
+ %img.user-image.img-circle.elevation-2{:alt => "User Image", :src => image_path(user_image_path(Olivander::CurrentContext.user))}/
105
105
 
106
- %span.d-none.d-md-inline= current_user.display_name
106
+ %span.d-none.d-md-inline= Olivander::CurrentContext.user.display_name
107
107
  %ul.dropdown-menu.dropdown-menu-lg.dropdown-menu-right
108
108
  / User image
109
109
  %li.user-header.bg-primary
110
- %img.img-circle.elevation-2{:alt => "User Image", src: image_path(user_image_path(current_user))}/
111
- %p= current_user.display_name
110
+ %img.img-circle.elevation-2{:alt => "User Image", src: image_path(user_image_path(Olivander::CurrentContext.user))}/
111
+ %p= Olivander::CurrentContext.user.display_name
112
112
  / Menu Footer
113
- %li.user-footer
114
- = link_to user_path(current_user), class: 'btn btn-default btn-flat' do
115
- Profile
116
- = link_to Olivander::CurrentContext.application_context.sign_out_path, method: :delete, class: 'btn btn-default btn-flat float-right' do
117
- Sign out
113
+ - unless Olivander::CurrentContext.user.is_a?(OpenStruct)
114
+ %li.user-footer
115
+ = link_to polymorphic_path(Olivander::CurrentContext.user), class: 'btn btn-default btn-flat' do
116
+ Profile
117
+ = link_to Olivander::CurrentContext.application_context.sign_out_path, method: :delete, class: 'btn btn-default btn-flat float-right' do
118
+ Sign out
118
119
  %li.nav-item
119
120
  %a.nav-link{title: 'Full Screen Mode', "data-widget" => "fullscreen", :href => "#", :role => "button"}
120
121
  %i.fas.fa-expand-arrows-alt
@@ -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
@@ -61,8 +55,30 @@ module Olivander
61
55
  attribute :application_context
62
56
  attribute :user, :ability
63
57
 
64
- def application_context
65
- @application_context ||= ::Olivander::ApplicationContext.default
58
+ def build(&block)
59
+ self.application_context ||= ::Olivander::ApplicationContext.new
60
+ self.user ||= build_dummy_user
61
+ self.ability ||= build_dummy_ability
62
+ yield(self, application_context, user, ability) if block_given?
63
+ self
64
+ end
65
+
66
+ private
67
+
68
+ def build_dummy_user
69
+ OpenStruct.new({ display_name: 'No User Set' })
70
+ end
71
+
72
+ def build_dummy_ability
73
+ Class.new do
74
+ def can?(_action, _resource)
75
+ true
76
+ end
77
+
78
+ def authorize!(_action, _resource)
79
+ true
80
+ end
81
+ end.new
66
82
  end
67
83
  end
68
84
  end
@@ -1,3 +1,3 @@
1
1
  module Olivander
2
- VERSION = '0.2.0.1'.freeze
2
+ VERSION = '0.2.0.3'.freeze
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
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.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Eric Dennis
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-02-13 00:00:00.000000000 Z
11
+ date: 2024-02-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: chartkick
@@ -175,6 +175,7 @@ files:
175
175
  - app/assets/images/default-150x150.png
176
176
  - app/assets/images/icons.png
177
177
  - app/assets/javascripts/adminlte.js
178
+ - app/assets/javascripts/adminlte/datatable.fix.js
178
179
  - app/assets/javascripts/adminlte/dist/css/adminlte.min.css
179
180
  - app/assets/javascripts/adminlte/dist/js/adminlte.js
180
181
  - app/assets/javascripts/adminlte/plugins/bootstrap/js/bootstrap.bundle.min.js
@@ -208,6 +209,7 @@ files:
208
209
  - app/assets/javascripts/adminlte/select2_defaults.coffee
209
210
  - app/assets/javascripts/controllers/datatable_expandable_chart_controller.js
210
211
  - app/assets/javascripts/controllers/datatable_index_charts_controller.js
212
+ - app/assets/javascripts/controllers/input_control_association_controller.js
211
213
  - app/assets/javascripts/controllers/turbo_flash_controller.js
212
214
  - app/assets/javascripts/olivander/flash_toast.js
213
215
  - app/assets/stylesheets/adminlte.css
@@ -228,15 +230,17 @@ files:
228
230
  - app/components/olivander/components/table_portlet_component.html.haml
229
231
  - app/components/olivander/components/table_portlet_component.rb
230
232
  - app/components/olivander/components/table_portlet_component/table_component.html.haml
233
+ - app/controllers/concerns/olivander/resources/application_record.rb
231
234
  - app/controllers/concerns/olivander/resources/auto_form_attributes.rb
235
+ - app/controllers/concerns/olivander/resources/crud_controller.rb
232
236
  - app/controllers/concerns/olivander/resources/route_builder.rb
233
237
  - app/controllers/olivander/application_controller.rb
234
238
  - app/datatables/olivander/datatable.rb
235
239
  - app/helpers/olivander/application_helper.rb
240
+ - app/inputs/custom_form_builder.rb
236
241
  - app/inputs/date_time_input.rb
237
242
  - app/jobs/olivander/application_job.rb
238
243
  - app/mailers/olivander/application_mailer.rb
239
- - app/models/olivander/application_record.rb
240
244
  - app/views/application/_form.html.haml
241
245
  - app/views/application/_resource_form_actions.html.haml
242
246
  - 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