para 0.8.9 → 0.8.14

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
- SHA1:
3
- metadata.gz: 21679101c22d1235aad9fbe2305f7dddab8d38f0
4
- data.tar.gz: a1d88c43b137eb2d075e6d9f2c0e206079939f2b
2
+ SHA256:
3
+ metadata.gz: 4fdbe5ef6d030b3f6aca6f18209211742914f15de7965bc583190a4480921e0e
4
+ data.tar.gz: aa514928922edf16906fb54f40027a9afc208e5327c00e1fee34ac24c66bb748
5
5
  SHA512:
6
- metadata.gz: 9e9304958f70e770b5632b8636c42183fbf5aa504d8e5f5bd3f183f7e16588bd1d7bf0e571d47d54091d24526d938bd74af43cd93449931ac20d4a5178d2f77d
7
- data.tar.gz: a2e962254b1001b3930c2a9dc62f8867f5027a9d049cbdb9659f3bc81d7093b07057dcb9855641c65110db7fe605cae6db58f994b1ba838b799186bff0f6d860
6
+ metadata.gz: 242dee3461cd57765d4f3b57e32073cb0a30a863e6bb59858891b621c989a36a1c189924bd78f237b25cc6890149816ab9a4f189b9d093465f7483664f525ac7
7
+ data.tar.gz: a15d5cdab40b3a00b46401b405bd007774bc119dceaf7d6f8423808a2673fafc2e5abf20961bf5176892e6ba670e88c61637d3d9d4a6f10a63ffae3b4f90b5f5
@@ -9,7 +9,11 @@
9
9
  .actions-control
10
10
  list-style: none
11
11
  padding: 0
12
- margin: 0
12
+ margin: 0 15px 0 0
13
+
14
+ &:last-child
15
+ margin-right: 0
16
+
13
17
  li
14
18
  +inline-block
15
19
  padding: 0 5px
@@ -42,7 +46,7 @@
42
46
 
43
47
  .page-list-heading
44
48
  border-bottom: 1px solid $gray-light
45
-
49
+
46
50
  .page-list-body:last-child
47
51
  padding-bottom: 0
48
52
 
@@ -76,7 +80,7 @@
76
80
  color: $gray
77
81
  border-color: transparent
78
82
  &:hover
79
- color: $gray-dark
83
+ color: $gray-dark
80
84
 
81
85
 
82
86
  .page-entries-info
@@ -5,8 +5,10 @@ module Para
5
5
  #
6
6
  def admin_component_sections
7
7
  @admin_component_sections ||= begin
8
- Para::ComponentSection.ordered.includes(:components).tap do |sections|
9
- sections.flat_map(&:components).each(&method(:decorate))
8
+ sections = Para::ComponentSection.ordered.includes(:components, :parent_component)
9
+
10
+ sections.tap do |loaded_sections|
11
+ loaded_sections.flat_map(&:components).each(&method(:decorate))
10
12
  end
11
13
  end
12
14
  end
@@ -2,18 +2,25 @@ module Para
2
2
  module Admin
3
3
  module PageHelper
4
4
  def page_top_bar(options = {})
5
- content_tag(:div, class: 'page-title row') do
5
+ top_bar = content_tag(:div, class: 'page-title row') do
6
6
  content_tag(:h1, options[:title]) +
7
7
 
8
8
  if (actions = actions_for(options[:type]))
9
9
  actions.map(&method(:build_action)).join('').html_safe
10
10
  end
11
11
  end
12
+
13
+ # Return both top bar and component navigation to be displayed at the top of the
14
+ # page.
15
+ top_bar + component_navigation
12
16
  end
13
17
 
14
18
  def build_action(action)
15
- content_tag(:div, class: 'actions-control pull-right') do
16
- link_to(action[:url], class: 'btn btn-default btn-shadow') do
19
+ link_options = action.fetch(:link_options, {})
20
+ link_options[:class] ||= "btn btn-default btn-shadow"
21
+
22
+ content_tag(:div, class: 'actions-control pull-right') do
23
+ link_to(action[:url], link_options) do
17
24
  (
18
25
  (fa_icon(action[:icon], class: 'fa-fw') if action[:icon]) +
19
26
  action[:label]
@@ -27,6 +34,26 @@ module Para
27
34
  instance_eval(&action)
28
35
  end.compact
29
36
  end
37
+
38
+ def component_navigation
39
+ parent_component = @component && (
40
+ @component.parent_component ||
41
+ @component.child_components.any? && @component
42
+ )
43
+
44
+ return unless parent_component
45
+
46
+ # If the component has a `model_type` option, therefore, an associated model,
47
+ # we try to render the partial from the relative path of the model, else we
48
+ # use the component class as the base target path
49
+ partial_target = parent_component.try(:model_type) || parent_component
50
+
51
+ render partial: find_partial_for(partial_target, :navigation),
52
+ locals: {
53
+ parent_component: parent_component,
54
+ active_component: @component
55
+ }
56
+ end
30
57
  end
31
58
  end
32
59
  end
@@ -19,9 +19,13 @@ module Para
19
19
  attributes = model_field_mappings(model).fields
20
20
  relation = options.fetch(:relation, model.name.to_s.underscore.pluralize)
21
21
  allow_adding_resource = options.fetch(:addable, true)
22
+ force_list = options.fetch(:force_list, false)
22
23
 
23
- partial = :list
24
- partial = :tree if model.respond_to?(:roots) && can?(:tree, model)
24
+ partial = if !force_list && model.respond_to?(:roots) && can?(:tree, model)
25
+ :tree
26
+ else
27
+ :list
28
+ end
25
29
 
26
30
  render(
27
31
  partial: find_partial_for(relation, partial),
@@ -1,3 +1,6 @@
1
+ # Base class used for the `AdminUser` model class as parent but automatically overriden
2
+ # by application's own ApplicationRecord definition in Rails 5+
3
+ #
1
4
  class ApplicationRecord < ActiveRecord::Base
2
5
  self.abstract_class = true
3
6
  end
@@ -0,0 +1,20 @@
1
+ module Para
2
+ # Base class for all para-specific models.
3
+ #
4
+ class ApplicationRecord < ActiveRecord::Base
5
+ self.abstract_class = true
6
+
7
+ private
8
+
9
+ # Adds the `optional: true` option to the belongs_to calls inside the provided block,
10
+ # but only for Rails 5.1+
11
+ #
12
+ def self.with_belongs_to_optional_option_if_needed(&block)
13
+ if ActiveRecord::Associations::Builder::BelongsTo.valid_options({}).include?(:optional)
14
+ with_options(optional: true, &block)
15
+ else
16
+ block.call
17
+ end
18
+ end
19
+ end
20
+ end
@@ -3,7 +3,7 @@
3
3
  #
4
4
  module Para
5
5
  module Cache
6
- class Item < ActiveRecord::Base
6
+ class Item < Para::ApplicationRecord
7
7
  def value
8
8
  Marshal.load(::Base64.decode64(self[:value])) if self[:value].present?
9
9
  end
@@ -1,6 +1,6 @@
1
1
  module Para
2
2
  module Component
3
- class Base < ActiveRecord::Base
3
+ class Base < Para::ApplicationRecord
4
4
  self.table_name = 'para_components'
5
5
 
6
6
  class_attribute :component_name
@@ -16,7 +16,14 @@ module Para
16
16
 
17
17
  configurable_on :controller
18
18
 
19
- belongs_to :component_section, class_name: 'Para::ComponentSection'
19
+ with_belongs_to_optional_option_if_needed do
20
+ belongs_to :component_section, class_name: 'Para::ComponentSection'
21
+ belongs_to :parent_component, class_name: 'Para::Component::Base'
22
+ end
23
+
24
+ has_many :child_components, -> { ordered },
25
+ class_name: 'Para::Component::Base',
26
+ foreign_key: 'parent_component_id'
20
27
 
21
28
  validates :identifier, :type, presence: true
22
29
 
@@ -31,6 +38,13 @@ module Para
31
38
  )
32
39
  end
33
40
 
41
+ def main_navigation_name
42
+ ::I18n.t(
43
+ "components.main_navigation.#{ identifier }",
44
+ default: name
45
+ )
46
+ end
47
+
34
48
  def exportable?
35
49
  false
36
50
  end
@@ -1,5 +1,5 @@
1
1
  module Para
2
- class ComponentResource < ActiveRecord::Base
2
+ class ComponentResource < Para::ApplicationRecord
3
3
  belongs_to :component, class_name: 'Para::Component::Base'
4
4
  belongs_to :resource, polymorphic: true
5
5
  end
@@ -1,5 +1,5 @@
1
1
  module Para
2
- class ComponentSection < ActiveRecord::Base
2
+ class ComponentSection < Para::ApplicationRecord
3
3
  has_many :components, -> { ordered }, class_name: 'Para::Component::Base',
4
4
  autosave: true, foreign_key: :component_section_id,
5
5
  dependent: :destroy
@@ -1,6 +1,6 @@
1
1
  module Para
2
2
  module Library
3
- class File < ActiveRecord::Base
3
+ class File < Para::ApplicationRecord
4
4
  if defined?(ActiveStorage)
5
5
  has_one_attached :attachment
6
6
 
@@ -1,21 +1,14 @@
1
1
  module Para
2
2
  module Page
3
- class Section < ActiveRecord::Base
3
+ class Section < Para::ApplicationRecord
4
4
  self.table_name = 'para_page_sections'
5
5
 
6
6
  acts_as_orderable parent: :page, as: :sections
7
7
 
8
- page_relation_options = { polymorphic: true }
9
-
10
- # Make Rails 5+ belongs_to relation optional for the parent page, to allow
11
- # using sections in other contexts that directly included into pages
12
- #
13
- if ActiveRecord::Associations::Builder::BelongsTo.valid_options({}).include?(:optional)
14
- page_relation_options[:optional] = true
8
+ with_belongs_to_optional_option_if_needed do
9
+ belongs_to :page, polymorphic: true
15
10
  end
16
11
 
17
- belongs_to :page, page_relation_options
18
-
19
12
  def css_class
20
13
  @css_class ||= self.class.name.demodulize.underscore.gsub(/_/, '-')
21
14
  end
@@ -1,6 +1,6 @@
1
1
  module Para
2
2
  module Page
3
- class SectionResource < ActiveRecord::Base
3
+ class SectionResource < Para::ApplicationRecord
4
4
  self.table_name = 'para_page_section_resources'
5
5
 
6
6
  acts_as_orderable parent: :section, as: :section_resources
@@ -0,0 +1,10 @@
1
+ .top-nav-tabs-affix-placeholder
2
+ %ul.top-nav-tabs-affix.nav.nav-tabs{ role: "tablist", "data-top-level-affix": true }
3
+ %li{ class: ("active" if active_component == parent_component) }
4
+ = link_to parent_component.path do
5
+ = parent_component.name
6
+
7
+ - parent_component.child_components.each do |child_component|
8
+ %li{ class: ("active" if active_component == child_component) }
9
+ = link_to child_component.path do
10
+ = child_component.name
@@ -15,8 +15,8 @@
15
15
  %ul.component-section-list-items.collapse.in{ id: "collapse-section-#{index}" }
16
16
  - component_section.components.each do |component|
17
17
  - if can?(:manage, component) && show_component?(component)
18
- %li.component-item{ class: (@component == component) && 'active' }
19
- = link_to component.name, component.path
18
+ %li.component-item{ class: (@component == component || @component.parent_component == component) && 'active' }
19
+ = link_to component.main_navigation_name, component.path
20
20
 
21
21
  - else
22
22
  %li.component-section-item
@@ -13,14 +13,14 @@ en:
13
13
  error: "Could not delete %{model}"
14
14
  clone:
15
15
  success: "%{model} cloned"
16
- error: "Could not clone %{model}"
17
-
16
+ error: "Could not clone %{model}"
17
+
18
18
  jobs:
19
19
  para/importer/base:
20
20
  progressing: "The file is being imported, please wait a few moments ..."
21
21
  success: "The import of the file was successfully completed"
22
22
  success_with_errors: |
23
- The import of the file was done, but some lines
23
+ The import of the file was done, but some lines
24
24
  were not taken into account due to errors :
25
25
  other_errors: "<br>And <b>%{count}</b> others errors ..."
26
26
  error: "The selected file contains errors and could not be imported"
@@ -40,9 +40,6 @@ en:
40
40
  confirmation:
41
41
  shared:
42
42
  destroy: 'Are you sure that you want to delete %{model} ?'
43
-
44
- component:
45
- none_created: "No components yet ..."
46
43
 
47
44
  component:
48
45
  create: "Create a component"
@@ -146,7 +143,7 @@ en:
146
143
  type: "Type"
147
144
  model_type: "Resource"
148
145
  namespaced: "Only list component's resources"
149
-
146
+
150
147
  activemodel:
151
148
  models:
152
149
  settings_rails/form:
@@ -0,0 +1,6 @@
1
+ class AddParentComponentToParaComponents < ActiveRecord::Migration[5.0]
2
+ def change
3
+ add_reference :para_components, :parent_component, foreign_key: false
4
+ add_foreign_key :para_components, :para_components, column: :parent_component_id
5
+ end
6
+ end
@@ -1,7 +1,7 @@
1
1
  module Para
2
2
  class ComponentsConfiguration
3
- class UndefinedComponentTypeError < StandardError
4
- end
3
+ class UndefinedComponentTypeError < StandardError; end
4
+ class ComponentTooDeepError < StandardError; end
5
5
 
6
6
  def draw(&block)
7
7
  return unless components_installed?
@@ -48,7 +48,24 @@ module Para
48
48
  end
49
49
 
50
50
  def component_configuration_for(identifier)
51
- sections.map(&:components).flatten.find { |c| c.identifier.to_s == identifier.to_s }
51
+ sections.each do |section|
52
+ section.components.each do |component|
53
+ # If one of the section component has the searched identifier return it
54
+ if component.identifier.to_s == identifier.to_s
55
+ return component
56
+ else
57
+ component.child_components.each do |child_component|
58
+ # If one of the component children has the searched identifier return it
59
+ if child_component.identifier.to_s == identifier.to_s
60
+ return child_component
61
+ end
62
+ end
63
+ end
64
+ end
65
+ end
66
+
67
+ # Return nil if the identifier was not found
68
+ nil
52
69
  end
53
70
 
54
71
  private
@@ -60,6 +77,10 @@ module Para
60
77
 
61
78
  section.components.each do |component|
62
79
  components_ids_hash[component.identifier] = component.model.id
80
+
81
+ component.child_components.each do |child_component|
82
+ components_ids_hash[child_component.identifier] = child_component.model.id
83
+ end
63
84
  end
64
85
  end
65
86
  end
@@ -129,8 +150,8 @@ module Para
129
150
  instance_eval(&block)
130
151
  end
131
152
 
132
- def component(*args)
133
- components << Component.new(*args)
153
+ def component(*args, &block)
154
+ components << Component.new(*args, &block)
134
155
  end
135
156
 
136
157
  def components
@@ -149,13 +170,17 @@ module Para
149
170
  end
150
171
 
151
172
  class Component
152
- attr_accessor :identifier, :type, :shown_if, :options, :model
173
+ attr_accessor :identifier, :type, :shown_if, :options, :model, :parent
153
174
 
154
- def initialize(identifier, type_identifier, shown_if: nil, **options)
155
- self.identifier = identifier.to_s
156
- self.type = Para::Component.registered_components[type_identifier]
157
- self.options = options
158
- self.shown_if = shown_if
175
+ def initialize(identifier, type_identifier, shown_if: nil, **options, &block)
176
+ @identifier = identifier.to_s
177
+ @type = Para::Component.registered_components[type_identifier]
178
+ @options = options
179
+ @shown_if = shown_if
180
+ @parent = options.delete(:parent)
181
+
182
+ # Build child components if a block is provided
183
+ instance_eval(&block) if block
159
184
 
160
185
  unless type
161
186
  raise UndefinedComponentTypeError.new(
@@ -165,10 +190,29 @@ module Para
165
190
  end
166
191
  end
167
192
 
193
+ def component(*args, **child_options, &block)
194
+ # Do not allow nesting components more than one level as the display of illimited
195
+ # child nesting deepness is not implemented
196
+ if parent
197
+ raise ComponentTooDeepError, "Cannot nest components more than one level"
198
+ end
199
+
200
+ child_component_options = child_options.merge(parent: self)
201
+ child_components << Component.new(*args, **child_component_options, &block)
202
+ end
203
+
204
+ def child_components
205
+ @child_components ||= []
206
+ end
207
+
168
208
  def refresh(attributes = {})
169
- self.model = type.where(identifier: identifier).first_or_initialize
209
+ @model = type.where(identifier: identifier).first_or_initialize
170
210
  model.update_with(attributes.merge(options_with_defaults))
171
211
  model.save!
212
+
213
+ child_components.each_with_index do |child_component, child_index|
214
+ child_component.refresh(component_section: nil, position: child_index)
215
+ end
172
216
  end
173
217
 
174
218
  # Ensures unset :configuration store options are set to nil to allow
@@ -179,7 +223,14 @@ module Para
179
223
  configurable_keys += options.keys
180
224
  configurable_keys.uniq!
181
225
 
182
- configurable_keys.each_with_object({}) do |key, hash|
226
+ options_with_defaults = {}
227
+
228
+ # Assign parent component resource to the final attribute options, assigning nil
229
+ # if the `:parent` option is empty, to allow extracting a component from its
230
+ # parent by just moving the component call outside of its parent block.
231
+ options_with_defaults[:parent_component] = parent&.model
232
+
233
+ configurable_keys.each_with_object(options_with_defaults) do |key, hash|
183
234
  hash[key] = options[key]
184
235
  end
185
236
  end
@@ -33,9 +33,9 @@ module Para
33
33
  end
34
34
 
35
35
  def ensure_total_progress
36
- return if @total_progress
36
+ return if @_total_progress
37
37
 
38
- @total_progress ||= if respond_to?(:total_progress, true)
38
+ @_total_progress ||= if respond_to?(:total_progress, true)
39
39
  progress.total = total_progress
40
40
  else
41
41
  progress[:total]
@@ -92,9 +92,9 @@ module Para
92
92
  end
93
93
 
94
94
  content_tag(:th, options) do
95
- if (sort = options.delete(:sort))
95
+ if search && (sort = options.delete(:sort))
96
96
  view.sort_link(search, *sort, label, hide_indicator: true)
97
- elsif searchable?(field_name)
97
+ elsif search && searchable?(field_name)
98
98
  view.sort_link(search, field_name, label, hide_indicator: true)
99
99
  else
100
100
  label
@@ -1,3 +1,3 @@
1
1
  module Para
2
- VERSION = '0.8.9'
2
+ VERSION = '0.8.14'
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: para
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.8.9
4
+ version: 0.8.14
5
5
  platform: ruby
6
6
  authors:
7
7
  - Valentin Ballestrino
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-10-22 00:00:00.000000000 Z
11
+ date: 2020-12-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -595,6 +595,7 @@ files:
595
595
  - app/helpers/para/tree_helper.rb
596
596
  - app/models/application_record.rb
597
597
  - app/models/para/ability.rb
598
+ - app/models/para/application_record.rb
598
599
  - app/models/para/cache/item.rb
599
600
  - app/models/para/component/base.rb
600
601
  - app/models/para/component/crud.rb
@@ -629,6 +630,7 @@ files:
629
630
  - app/views/para/admin/resources/_form.html.haml
630
631
  - app/views/para/admin/resources/_imports_menu.html.haml
631
632
  - app/views/para/admin/resources/_list.html.haml
633
+ - app/views/para/admin/resources/_navigation.html.haml
632
634
  - app/views/para/admin/resources/_per_page_select.html.haml
633
635
  - app/views/para/admin/resources/_remote_nested_form.html.haml
634
636
  - app/views/para/admin/resources/_subclassable_add_button.html.haml
@@ -670,6 +672,7 @@ files:
670
672
  - db/migrate/20160905134106_create_para_library_files.rb
671
673
  - db/migrate/20161006105728_create_para_cache_items.rb
672
674
  - db/migrate/20170324125547_create_para_page_section_resources.rb
675
+ - db/migrate/20201210152223_add_parent_component_to_para_components.rb
673
676
  - lib/generators/para/admin_user/admin_user_generator.rb
674
677
  - lib/generators/para/component/component_generator.rb
675
678
  - lib/generators/para/component/crud/crud_generator.rb
@@ -851,8 +854,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
851
854
  - !ruby/object:Gem::Version
852
855
  version: '0'
853
856
  requirements: []
854
- rubyforge_project:
855
- rubygems_version: 2.6.11
857
+ rubygems_version: 3.1.4
856
858
  signing_key:
857
859
  specification_version: 4
858
860
  summary: Rails admin engine