para 0.8.9 → 0.8.14
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/app/assets/stylesheets/para/admin/src/_list.sass +7 -3
- data/app/helpers/para/admin/components_helper.rb +4 -2
- data/app/helpers/para/admin/page_helper.rb +30 -3
- data/app/helpers/para/tag_helper.rb +6 -2
- data/app/models/application_record.rb +3 -0
- data/app/models/para/application_record.rb +20 -0
- data/app/models/para/cache/item.rb +1 -1
- data/app/models/para/component/base.rb +16 -2
- data/app/models/para/component_resource.rb +1 -1
- data/app/models/para/component_section.rb +1 -1
- data/app/models/para/library/file.rb +1 -1
- data/app/models/para/page/section.rb +3 -10
- data/app/models/para/page/section_resource.rb +1 -1
- data/app/views/para/admin/resources/_navigation.html.haml +10 -0
- data/app/views/para/admin/shared/_navigation.html.haml +2 -2
- data/config/locales/en.yml +4 -7
- data/db/migrate/20201210152223_add_parent_component_to_para_components.rb +6 -0
- data/lib/para/components_configuration.rb +64 -13
- data/lib/para/job/base.rb +2 -2
- data/lib/para/markup/resources_table.rb +2 -2
- data/lib/para/version.rb +1 -1
- metadata +6 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 4fdbe5ef6d030b3f6aca6f18209211742914f15de7965bc583190a4480921e0e
|
4
|
+
data.tar.gz: aa514928922edf16906fb54f40027a9afc208e5327c00e1fee34ac24c66bb748
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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)
|
9
|
-
|
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
|
-
|
16
|
-
|
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 = :
|
24
|
-
|
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),
|
@@ -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
|
@@ -1,6 +1,6 @@
|
|
1
1
|
module Para
|
2
2
|
module Component
|
3
|
-
class 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
|
-
|
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,21 +1,14 @@
|
|
1
1
|
module Para
|
2
2
|
module Page
|
3
|
-
class Section <
|
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
|
-
|
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
|
@@ -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.
|
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
|
data/config/locales/en.yml
CHANGED
@@ -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:
|
@@ -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.
|
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
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
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
|
-
|
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
|
-
|
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
|
data/lib/para/job/base.rb
CHANGED
@@ -33,9 +33,9 @@ module Para
|
|
33
33
|
end
|
34
34
|
|
35
35
|
def ensure_total_progress
|
36
|
-
return if @
|
36
|
+
return if @_total_progress
|
37
37
|
|
38
|
-
@
|
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
|
data/lib/para/version.rb
CHANGED
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.
|
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-
|
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
|
-
|
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
|