para 0.7.4 → 0.8.0
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 +4 -4
- data/app/helpers/para/markup_helper.rb +2 -2
- data/app/views/para/admin/resources/_table.html.haml +1 -1
- data/app/views/para/admin/resources/_tree_item.html.haml +5 -5
- data/lib/generators/para/table/templates/_table.html.haml +1 -1
- data/lib/para/active_storage_downloader.rb +23 -0
- data/lib/para/cloneable/attachments_cloner.rb +36 -0
- data/lib/para/cloneable/include_tree_builder.rb +67 -0
- data/lib/para/cloneable.rb +17 -3
- data/lib/para/job/base.rb +1 -1
- data/lib/para/markup/resources_buttons.rb +61 -0
- data/lib/para/markup/resources_table.rb +9 -52
- data/lib/para/markup.rb +1 -0
- data/lib/para/version.rb +1 -1
- data/lib/para.rb +1 -0
- metadata +6 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 47cd4fad8f6308c2c3ae1948bea744640d0ce772
|
4
|
+
data.tar.gz: e6f7cf338d48a9ef60f696221413c263d34dcc10
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e38d091236ea396e0836560be1128c551393495ea6e967ee6a40f73ccfc301e1ded6e5682b5b23f65e1ae7406c8fc1e820d57a8c9edb3d53fc109735620b1960
|
7
|
+
data.tar.gz: c31d521f7c6a38eadb0646ecdc48f23ca8e258c4b0b285c5b90301013175fde19792716654d7ceeca9180895853d7c4c237dc9c1a10e41d7d5202cad8fb33c41
|
@@ -4,8 +4,8 @@ module Para
|
|
4
4
|
Para::Markup::Alert.new(self).container(message, options, &block)
|
5
5
|
end
|
6
6
|
|
7
|
-
def resources_table(options
|
8
|
-
Para::Markup::ResourcesTable.new(self).container(options, &block)
|
7
|
+
def resources_table(component:, **options, &block)
|
8
|
+
Para::Markup::ResourcesTable.new(component, self).container(options, &block)
|
9
9
|
end
|
10
10
|
|
11
11
|
def panel(options = {}, &block)
|
@@ -4,13 +4,13 @@
|
|
4
4
|
%i.sort-dots
|
5
5
|
%span.node-name
|
6
6
|
= resource_name(root)
|
7
|
+
|
8
|
+
- buttons = Para::Markup::ResourcesButtons.new(@component, self)
|
9
|
+
- actions = Para::Markup::ResourcesTable.default_actions
|
7
10
|
|
8
11
|
.pull-right
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
= link_to @component.relation_path(root), method: :delete, data: { confirm: ::I18n.t('para.list.delete_confirmation') }, class: 'btn btn-icon-danger btn-shadow btn-sm hint--left', :'aria-label' => ::I18n.t('para.shared.destroy') do
|
13
|
-
%i.fa.fa-times
|
12
|
+
- actions.each do |action|
|
13
|
+
= buttons.send(:"#{action}_button", root)
|
14
14
|
|
15
15
|
.clearfix
|
16
16
|
%ul.tree
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Para
|
2
|
+
class ActiveStorageDownloader
|
3
|
+
if defined?(ActiveStorage)
|
4
|
+
include ActiveStorage::Downloading
|
5
|
+
end
|
6
|
+
|
7
|
+
attr_reader :attachment
|
8
|
+
|
9
|
+
delegate :blob, to: :attachment
|
10
|
+
|
11
|
+
def initialize(attachment)
|
12
|
+
@attachment = attachment
|
13
|
+
end
|
14
|
+
|
15
|
+
if defined?(ActiveStorage)
|
16
|
+
public :download_blob_to_tempfile
|
17
|
+
else
|
18
|
+
define_method(:download_blob_to_tempfile) do
|
19
|
+
raise NoMethodError, "ActiveStorage is not included in your application"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module Para
|
2
|
+
module Cloneable
|
3
|
+
class AttachmentsCloner
|
4
|
+
attr_reader :original, :clone
|
5
|
+
|
6
|
+
def initialize(original, clone)
|
7
|
+
@original = original
|
8
|
+
@clone = clone
|
9
|
+
end
|
10
|
+
|
11
|
+
def clone!
|
12
|
+
return unless defined?(ActiveStorage)
|
13
|
+
|
14
|
+
attachment_reflections = original.class.reflections.select { |k, v|
|
15
|
+
k.to_s.match(/_attachment\z/) &&
|
16
|
+
v.options[:class_name] == "ActiveStorage::Attachment"
|
17
|
+
}
|
18
|
+
|
19
|
+
attachment_reflections.each do |name, reflection|
|
20
|
+
original_attachment = original.send(name)
|
21
|
+
next unless original_attachment
|
22
|
+
|
23
|
+
association_name = name.gsub(/_attachment\z/, "")
|
24
|
+
|
25
|
+
Para::ActiveStorageDownloader.new(original_attachment).download_blob_to_tempfile do |tempfile|
|
26
|
+
clone.send(association_name).attach({
|
27
|
+
io: tempfile,
|
28
|
+
filename: original_attachment.blob.filename,
|
29
|
+
content_type: original_attachment.blob.content_type
|
30
|
+
})
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
module Para
|
2
|
+
module Cloneable
|
3
|
+
class IncludeTreeBuilder
|
4
|
+
attr_reader :resource, :cloneable_options
|
5
|
+
|
6
|
+
def initialize(resource, cloneable_options)
|
7
|
+
@resource = resource
|
8
|
+
@cloneable_options = cloneable_options.deep_dup
|
9
|
+
end
|
10
|
+
|
11
|
+
def build
|
12
|
+
include_tree = build_cloneable_tree(resource, cloneable_options[:include])
|
13
|
+
cloneable_options[:include] = clean_include_tree(include_tree)
|
14
|
+
cloneable_options
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def build_cloneable_tree(resource, include)
|
20
|
+
include.each_with_object({}) do |reflection_name, hash|
|
21
|
+
hash[reflection_name] = {}
|
22
|
+
|
23
|
+
if (reflection = resource.class.reflections[reflection_name.to_s])
|
24
|
+
reflection_options = hash[reflection_name]
|
25
|
+
association_target = resource.send(reflection_name)
|
26
|
+
|
27
|
+
if reflection.collection?
|
28
|
+
association_target.each do |nested_resource|
|
29
|
+
add_reflection_options(reflection_options, nested_resource)
|
30
|
+
end
|
31
|
+
else
|
32
|
+
add_reflection_options(reflection_options, association_target)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def add_reflection_options(reflection_options, nested_resource)
|
39
|
+
options = nested_resource.class.try(:cloneable_options)
|
40
|
+
return reflection_options unless options
|
41
|
+
|
42
|
+
include_options = options[:include]
|
43
|
+
target_options = build_cloneable_tree(nested_resource, include_options)
|
44
|
+
reflection_options.deep_merge!(target_options)
|
45
|
+
end
|
46
|
+
|
47
|
+
def clean_include_tree(tree)
|
48
|
+
shallow_relations = []
|
49
|
+
deep_relations = {}
|
50
|
+
|
51
|
+
tree.each do |key, value|
|
52
|
+
if !value || value.empty?
|
53
|
+
shallow_relations << key
|
54
|
+
else
|
55
|
+
deep_relations[key] = clean_include_tree(value)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
if deep_relations.empty?
|
60
|
+
shallow_relations
|
61
|
+
else
|
62
|
+
shallow_relations + [deep_relations]
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
data/lib/para/cloneable.rb
CHANGED
@@ -1,20 +1,30 @@
|
|
1
1
|
module Para
|
2
2
|
module Cloneable
|
3
3
|
extend ActiveSupport::Concern
|
4
|
+
extend ActiveSupport::Autoload
|
4
5
|
|
5
6
|
included do
|
6
7
|
class_attribute :cloneable_options
|
7
8
|
end
|
8
9
|
|
10
|
+
eager_autoload do
|
11
|
+
autoload :IncludeTreeBuilder
|
12
|
+
autoload :AttachmentsCloner
|
13
|
+
end
|
14
|
+
|
9
15
|
# Wraps the deep_cloneable gem #deep_clone method to allow using the
|
10
16
|
# predefined associations and options from our Cloneable.acts_as_cloneable
|
11
17
|
# macro.
|
12
18
|
#
|
13
19
|
def deep_clone!(options = {})
|
14
|
-
|
20
|
+
processed_options = Para::Cloneable::IncludeTreeBuilder.new(self, cloneable_options).build
|
21
|
+
options = options.reverse_merge(processed_options)
|
15
22
|
callback = build_clone_callback(options.delete(:prepare))
|
16
|
-
|
17
|
-
deep_clone(options,
|
23
|
+
|
24
|
+
deep_clone(options) do |original, clone|
|
25
|
+
Para::Cloneable::AttachmentsCloner.new(original, clone).clone!
|
26
|
+
callback&.call(original, clone)
|
27
|
+
end
|
18
28
|
end
|
19
29
|
|
20
30
|
private
|
@@ -49,6 +59,10 @@ module Para
|
|
49
59
|
|
50
60
|
options = args.extract_options!
|
51
61
|
|
62
|
+
# Allow nested STI resources to define their own relations to clone even
|
63
|
+
# if other sibling models don't define those relations
|
64
|
+
options[:skip_missing_associations] = true
|
65
|
+
|
52
66
|
self.cloneable_options = options.reverse_merge({
|
53
67
|
include: args
|
54
68
|
})
|
data/lib/para/job/base.rb
CHANGED
@@ -0,0 +1,61 @@
|
|
1
|
+
module Para
|
2
|
+
module Markup
|
3
|
+
class ResourcesButtons < Para::Markup::Component
|
4
|
+
attr_reader :component
|
5
|
+
|
6
|
+
def initialize(component, view)
|
7
|
+
@component = component
|
8
|
+
super(view)
|
9
|
+
end
|
10
|
+
|
11
|
+
def clone_button(resource)
|
12
|
+
return unless resource.class.cloneable?
|
13
|
+
|
14
|
+
path = component.relation_path(
|
15
|
+
resource, action: :clone, return_to: view.request.fullpath
|
16
|
+
)
|
17
|
+
|
18
|
+
options = {
|
19
|
+
method: :post,
|
20
|
+
class: 'btn btn-sm btn-icon-info btn-shadow hint--left',
|
21
|
+
aria: {
|
22
|
+
label: ::I18n.t('para.shared.copy')
|
23
|
+
}
|
24
|
+
}
|
25
|
+
|
26
|
+
view.link_to(path, options) do
|
27
|
+
content_tag(:i, '', class: 'fa fa-copy')
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def edit_button(resource)
|
32
|
+
path = component.relation_path(
|
33
|
+
resource, action: :edit, return_to: view.request.fullpath
|
34
|
+
)
|
35
|
+
|
36
|
+
view.link_to(path, class: 'btn btn-sm btn-icon-primary btn-shadow hint--left', aria: { label: ::I18n.t('para.shared.edit') }) do
|
37
|
+
content_tag(:i, '', class: 'fa fa-pencil')
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def delete_button(resource)
|
42
|
+
path = component.relation_path(resource, return_to: view.request.fullpath)
|
43
|
+
|
44
|
+
options = {
|
45
|
+
method: :delete,
|
46
|
+
data: {
|
47
|
+
confirm: ::I18n.t('para.list.delete_confirmation')
|
48
|
+
},
|
49
|
+
class: 'btn btn-sm btn-icon-danger btn-shadow hint--left',
|
50
|
+
aria: {
|
51
|
+
label: ::I18n.t('para.shared.destroy')
|
52
|
+
}
|
53
|
+
}
|
54
|
+
|
55
|
+
view.link_to(path, options) do
|
56
|
+
content_tag(:i, '', class: 'fa fa-times')
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -4,11 +4,15 @@ module Para
|
|
4
4
|
class_attribute :default_actions
|
5
5
|
self.default_actions = [:edit, :clone, :delete]
|
6
6
|
|
7
|
-
attr_reader :
|
7
|
+
attr_reader :component, :model, :orderable, :actions
|
8
|
+
|
9
|
+
def initialize(component, view)
|
10
|
+
@component = component
|
11
|
+
super(view)
|
12
|
+
end
|
8
13
|
|
9
14
|
def container(options = {}, &block)
|
10
15
|
@model = options.delete(:model)
|
11
|
-
@component = options.delete(:component)
|
12
16
|
|
13
17
|
if !options.key?(:orderable) || options.delete(:orderable)
|
14
18
|
@orderable = model.orderable?
|
@@ -131,62 +135,15 @@ module Para
|
|
131
135
|
end
|
132
136
|
|
133
137
|
def actions_cell(resource)
|
138
|
+
buttons = ResourcesButtons.new(component, view)
|
139
|
+
|
134
140
|
content_tag(:td, class: 'table-row-actions') do
|
135
141
|
actions.map do |type|
|
136
|
-
send(:"#{ type }_button", resource)
|
142
|
+
buttons.send(:"#{ type }_button", resource)
|
137
143
|
end.compact.join.html_safe
|
138
144
|
end
|
139
145
|
end
|
140
146
|
|
141
|
-
def clone_button(resource)
|
142
|
-
return unless resource.class.cloneable?
|
143
|
-
|
144
|
-
path = component.relation_path(
|
145
|
-
resource, action: :clone, return_to: view.request.fullpath
|
146
|
-
)
|
147
|
-
|
148
|
-
options = {
|
149
|
-
method: :post,
|
150
|
-
class: 'btn btn-sm btn-icon-info btn-shadow hint--left',
|
151
|
-
aria: {
|
152
|
-
label: ::I18n.t('para.shared.copy')
|
153
|
-
}
|
154
|
-
}
|
155
|
-
|
156
|
-
view.link_to(path, options) do
|
157
|
-
content_tag(:i, '', class: 'fa fa-copy')
|
158
|
-
end
|
159
|
-
end
|
160
|
-
|
161
|
-
def edit_button(resource)
|
162
|
-
path = component.relation_path(
|
163
|
-
resource, action: :edit, return_to: view.request.fullpath
|
164
|
-
)
|
165
|
-
|
166
|
-
view.link_to(path, class: 'btn btn-sm btn-icon-primary btn-shadow hint--left', aria: { label: ::I18n.t('para.shared.edit') }) do
|
167
|
-
content_tag(:i, '', class: 'fa fa-pencil')
|
168
|
-
end
|
169
|
-
end
|
170
|
-
|
171
|
-
def delete_button(resource)
|
172
|
-
path = component.relation_path(resource, return_to: view.request.fullpath)
|
173
|
-
|
174
|
-
options = {
|
175
|
-
method: :delete,
|
176
|
-
data: {
|
177
|
-
confirm: ::I18n.t('para.list.delete_confirmation')
|
178
|
-
},
|
179
|
-
class: 'btn btn-sm btn-icon-danger btn-shadow hint--left',
|
180
|
-
aria: {
|
181
|
-
label: ::I18n.t('para.shared.destroy')
|
182
|
-
}
|
183
|
-
}
|
184
|
-
|
185
|
-
view.link_to(path, options) do
|
186
|
-
content_tag(:i, '', class: 'fa fa-times')
|
187
|
-
end
|
188
|
-
end
|
189
|
-
|
190
147
|
private
|
191
148
|
|
192
149
|
def search
|
data/lib/para/markup.rb
CHANGED
data/lib/para/version.rb
CHANGED
data/lib/para.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.
|
4
|
+
version: 0.8.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Valentin Ballestrino
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-
|
11
|
+
date: 2019-04-01 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -701,6 +701,7 @@ files:
|
|
701
701
|
- lib/generators/para/table/templates/_table.html.haml
|
702
702
|
- lib/generators/para/tree_item/tree_item_generator.rb
|
703
703
|
- lib/para.rb
|
704
|
+
- lib/para/active_storage_downloader.rb
|
704
705
|
- lib/para/attribute_field.rb
|
705
706
|
- lib/para/attribute_field/base.rb
|
706
707
|
- lib/para/attribute_field/belongs_to.rb
|
@@ -726,6 +727,8 @@ files:
|
|
726
727
|
- lib/para/cache.rb
|
727
728
|
- lib/para/cache/database_store.rb
|
728
729
|
- lib/para/cloneable.rb
|
730
|
+
- lib/para/cloneable/attachments_cloner.rb
|
731
|
+
- lib/para/cloneable/include_tree_builder.rb
|
729
732
|
- lib/para/component.rb
|
730
733
|
- lib/para/component/exportable.rb
|
731
734
|
- lib/para/component/history.rb
|
@@ -782,6 +785,7 @@ files:
|
|
782
785
|
- lib/para/markup/component.rb
|
783
786
|
- lib/para/markup/modal.rb
|
784
787
|
- lib/para/markup/panel.rb
|
788
|
+
- lib/para/markup/resources_buttons.rb
|
785
789
|
- lib/para/markup/resources_table.rb
|
786
790
|
- lib/para/markup/resources_tree.rb
|
787
791
|
- lib/para/model_field_parsers.rb
|