para 0.5.4 → 0.6.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 +4 -4
- data/app/assets/javascripts/para/admin/async-progress.coffee +29 -0
- data/app/assets/javascripts/para/admin/filters-form.coffee +1 -1
- data/app/assets/javascripts/para/admin/importers.coffee +38 -0
- data/app/assets/javascripts/para/admin/table.coffee +1 -1
- data/app/assets/javascripts/para/admin/tabs.coffee +1 -1
- data/app/assets/javascripts/para/admin/theme_actions.coffee +1 -1
- data/app/assets/javascripts/para/admin/tree.coffee +5 -5
- data/app/assets/javascripts/para/admin.coffee +2 -1
- data/app/assets/javascripts/para/inputs/nested_many.coffee +1 -1
- data/app/assets/javascripts/para/lib/remote-file-forms.coffee +60 -0
- data/app/assets/javascripts/para/lib/turbolinks-loading.coffee +1 -1
- data/app/assets/javascripts/para/lib/turbolinks-reloader.coffee +19 -0
- data/app/assets/stylesheets/para/admin/src/datetimepicker.sass +3 -1
- data/app/assets/stylesheets/para/admin/src/fuelux.sass +4 -2
- data/app/assets/stylesheets/para/admin/src/nested_many.sass +5 -0
- data/app/assets/stylesheets/para/admin/src/redactor.sass +8 -5
- data/app/assets/stylesheets/para/admin/src/selectize.sass +7 -4
- data/app/assets/stylesheets/para/admin/theme/_breadcrumb.sass +20 -12
- data/app/assets/stylesheets/para/admin/theme/_buttons.sass +6 -2
- data/app/assets/stylesheets/para/admin/theme/_checkable.sass +4 -2
- data/app/assets/stylesheets/para/admin/theme/_commonds.sass +6 -3
- data/app/assets/stylesheets/para/admin/theme/_dropdown.sass +3 -1
- data/app/assets/stylesheets/para/admin/theme/_form.sass +4 -2
- data/app/assets/stylesheets/para/admin/theme/_list.sass +7 -5
- data/app/assets/stylesheets/para/admin/theme/_navigation.sass +12 -66
- data/app/assets/stylesheets/para/admin/theme/_navtabs.sass +18 -14
- data/app/assets/stylesheets/para/admin/theme/_orderable.sass +7 -3
- data/app/assets/stylesheets/para/admin/theme/_panel.sass +19 -13
- data/app/assets/stylesheets/para/admin/theme/_tree.sass +4 -2
- data/app/assets/stylesheets/para/overrides/theme.sass +14 -10
- data/app/controllers/para/admin/base_controller.rb +0 -5
- data/app/controllers/para/admin/crud_resources_controller.rb +5 -19
- data/app/controllers/para/admin/{singleton_resources_controller.rb → form_resources_controller.rb} +4 -4
- data/app/controllers/para/admin/imports_controller.rb +68 -0
- data/app/controllers/para/admin/resources_controller.rb +0 -1
- data/app/decorators/para/component/base_decorator.rb +6 -18
- data/app/decorators/para/component/crud_decorator.rb +3 -3
- data/app/decorators/para/component/{singleton_resource_decorator.rb → form_decorator.rb} +6 -6
- data/app/helpers/para/admin/components_helper.rb +12 -1
- data/app/helpers/para/admin/decorators_helper.rb +13 -0
- data/app/helpers/para/markup_helper.rb +4 -0
- data/app/helpers/para/search_helper.rb +1 -4
- data/app/models/para/component/base.rb +17 -14
- data/app/models/para/component/crud.rb +17 -0
- data/app/models/para/component/form.rb +36 -0
- data/app/models/para/component/resource.rb +9 -20
- data/app/models/para/component/settings.rb +1 -1
- data/app/models/para/library/file.rb +23 -0
- data/app/models/para/library.rb +5 -0
- data/app/views/para/admin/form_resources/show.html.haml +4 -0
- data/app/views/para/admin/imports/_completed.html.haml +16 -0
- data/app/views/para/admin/imports/_failed.html.haml +7 -0
- data/app/views/para/admin/imports/_progress.html.haml +5 -0
- data/app/views/para/admin/imports/new.html.haml +14 -0
- data/app/views/para/admin/imports/show.html.haml +10 -0
- data/app/views/para/admin/resources/_fields.html.haml +1 -4
- data/app/views/para/admin/resources/_imports_menu.html.haml +17 -20
- data/app/views/para/admin/resources/_tree.html.haml +1 -1
- data/app/views/para/admin/shared/_breadcrumbs.html.haml +1 -4
- data/app/views/para/admin/shared/_navigation.html.haml +2 -2
- data/app/views/para/form/_tabs.html.haml +1 -1
- data/config/locales/en.yml +10 -0
- data/config/locales/fr.yml +12 -2
- data/db/migrate/20160905134106_create_para_library_files.rb +9 -0
- data/lib/generators/para/importer/templates/base_importer.rb +8 -1
- data/lib/generators/para/install/install_generator.rb +1 -2
- data/lib/generators/para/install/templates/components.rb +9 -5
- data/lib/generators/para/tree_item/tree_item_generator.rb +17 -0
- data/lib/para/attribute_field/base.rb +12 -4
- data/lib/para/attribute_field/enum.rb +7 -3
- data/lib/para/component/importable.rb +4 -4
- data/lib/para/component.rb +1 -1
- data/lib/para/components_cleaner.rb +66 -0
- data/lib/para/components_configuration.rb +3 -1
- data/lib/para/engine.rb +36 -3
- data/lib/para/ext/active_job_status.rb +13 -0
- data/lib/para/ext/paperclip.rb +10 -0
- data/lib/para/ext/simple_form_extension.rb +6 -0
- data/lib/para/ext.rb +1 -0
- data/lib/para/form_builder/nested_form.rb +5 -2
- data/lib/para/importer/base.rb +84 -7
- data/lib/para/inputs/nested_many_input.rb +1 -1
- data/lib/para/logging/active_job_log_subscriber.rb +48 -0
- data/lib/para/logging.rb +8 -0
- data/lib/para/markup/resources_table.rb +2 -4
- data/lib/para/model_field_parsers/enums.rb +19 -0
- data/lib/para/model_field_parsers/relations.rb +1 -1
- data/lib/para/model_field_parsers/store.rb +1 -1
- data/lib/para/model_field_parsers.rb +1 -0
- data/lib/para/plugins/routes.rb +2 -4
- data/lib/para/postgres_extensions_checker.rb +30 -0
- data/lib/para/routes.rb +5 -4
- data/lib/para/routing/component_controller_constraint.rb +36 -0
- data/lib/para/routing.rb +7 -0
- data/lib/para/sti/root_model.rb +8 -2
- data/lib/para/version.rb +1 -1
- data/lib/para.rb +10 -0
- data/lib/rails/routing_mapper.rb +59 -27
- data/lib/tasks/para_tasks.rake +21 -11
- metadata +73 -15
- data/app/models/para/component/singleton_resource.rb +0 -35
- data/app/views/para/admin/singleton_resources/show.html.haml +0 -4
|
@@ -1,23 +1,23 @@
|
|
|
1
1
|
module Para
|
|
2
2
|
module Component
|
|
3
|
-
module
|
|
3
|
+
module FormDecorator
|
|
4
4
|
include Para::Component::BaseDecorator
|
|
5
5
|
|
|
6
|
-
def path(
|
|
7
|
-
find_path([:admin, self,
|
|
6
|
+
def path(namespace: :resource, **options)
|
|
7
|
+
find_path([:admin, self, namespace], options)
|
|
8
8
|
end
|
|
9
9
|
|
|
10
10
|
def relation_path(controller_or_resource, *nested_resources, **options)
|
|
11
11
|
nested = nested_resources.any?
|
|
12
|
-
nested_resources << :resource unless nested
|
|
13
12
|
|
|
14
13
|
if Hash === controller_or_resource
|
|
15
14
|
options = controller_or_resource
|
|
16
15
|
end
|
|
17
16
|
|
|
18
17
|
options[:action] = action_option_for(options, nested: nested)
|
|
19
|
-
data = [:admin, self, *nested_resources]
|
|
20
|
-
|
|
18
|
+
data = [:admin, self, :resource, *nested_resources]
|
|
19
|
+
|
|
20
|
+
find_path(data, options)
|
|
21
21
|
end
|
|
22
22
|
|
|
23
23
|
def action_option_for(options, nested: false)
|
|
@@ -1,7 +1,18 @@
|
|
|
1
1
|
module Para
|
|
2
2
|
module Admin::ComponentsHelper
|
|
3
|
+
# Return the sections / components structure, with components properly
|
|
4
|
+
# decorated
|
|
5
|
+
#
|
|
6
|
+
def admin_component_sections
|
|
7
|
+
@admin_component_sections ||= begin
|
|
8
|
+
Para::ComponentSection.ordered.includes(:components).tap do |sections|
|
|
9
|
+
sections.flat_map(&:components).each(&method(:decorate))
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
|
|
3
14
|
def ordered_components
|
|
4
|
-
|
|
15
|
+
admin_component_sections.each_with_object([]) do |section, components|
|
|
5
16
|
section.components.each do |component|
|
|
6
17
|
components << component if can?(:read, component)
|
|
7
18
|
end
|
|
@@ -9,10 +9,7 @@ module Para
|
|
|
9
9
|
end
|
|
10
10
|
|
|
11
11
|
def searchable_attributes(attributes)
|
|
12
|
-
whitelist = attributes.select
|
|
13
|
-
[:string, :text].include?(attribute.type.to_sym) &&
|
|
14
|
-
!attribute.name.match(/password/)
|
|
15
|
-
end
|
|
12
|
+
whitelist = attributes.select(&:searchable?)
|
|
16
13
|
|
|
17
14
|
whitelist.map do |attribute|
|
|
18
15
|
attribute.attribute_column_path.join('_')
|
|
@@ -3,13 +3,19 @@ module Para
|
|
|
3
3
|
class Base < ActiveRecord::Base
|
|
4
4
|
self.table_name = 'para_components'
|
|
5
5
|
|
|
6
|
-
class_attribute :component_name
|
|
6
|
+
class_attribute :component_name
|
|
7
7
|
|
|
8
8
|
def self.register(name, component)
|
|
9
9
|
self.component_name = name
|
|
10
10
|
Para::Component.registered_components[name] = component
|
|
11
11
|
end
|
|
12
12
|
|
|
13
|
+
def self.configurable_on(key, options = {})
|
|
14
|
+
store_accessor(:configuration, key)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
configurable_on :controller
|
|
18
|
+
|
|
13
19
|
belongs_to :component_section, class_name: 'Para::ComponentSection'
|
|
14
20
|
|
|
15
21
|
validates :identifier, :type, presence: true
|
|
@@ -37,19 +43,6 @@ module Para
|
|
|
37
43
|
@model_name ||= ModelName.new(self)
|
|
38
44
|
end
|
|
39
45
|
|
|
40
|
-
def self.configurable_on(key, options = {})
|
|
41
|
-
store_accessor(:configuration, key)
|
|
42
|
-
configurable_attributes[key] = options
|
|
43
|
-
end
|
|
44
|
-
|
|
45
|
-
def self.configurable?
|
|
46
|
-
configurable_attributes.length > 0
|
|
47
|
-
end
|
|
48
|
-
|
|
49
|
-
def self.configurable_attributes
|
|
50
|
-
@configurable_attributes ||= {}
|
|
51
|
-
end
|
|
52
|
-
|
|
53
46
|
def default_form_actions
|
|
54
47
|
[:submit, :submit_and_edit, :submit_and_add_another, :cancel]
|
|
55
48
|
end
|
|
@@ -58,6 +51,16 @@ module Para
|
|
|
58
51
|
slug
|
|
59
52
|
end
|
|
60
53
|
|
|
54
|
+
# This method is used by the components configuration system to assign
|
|
55
|
+
# updated attributes from the config file to the component.
|
|
56
|
+
#
|
|
57
|
+
# This is meant to be overriden by components that have to define specific
|
|
58
|
+
# behavior, like for the Crud component
|
|
59
|
+
#
|
|
60
|
+
def update_with(attributes)
|
|
61
|
+
assign_attributes(attributes)
|
|
62
|
+
end
|
|
63
|
+
|
|
61
64
|
private
|
|
62
65
|
|
|
63
66
|
def ensure_slug
|
|
@@ -13,6 +13,8 @@ module Para
|
|
|
13
13
|
has_many :component_resources, class_name: 'Para::ComponentResource',
|
|
14
14
|
foreign_key: :component_id, autosave: true, dependent: :destroy
|
|
15
15
|
|
|
16
|
+
before_validation :ensure_model_type
|
|
17
|
+
|
|
16
18
|
def namespaced?
|
|
17
19
|
case namespaced
|
|
18
20
|
when 'true' then true
|
|
@@ -32,6 +34,17 @@ module Para
|
|
|
32
34
|
component_resources.where(resource: resource).first.destroy
|
|
33
35
|
end
|
|
34
36
|
|
|
37
|
+
def update_with(attributes)
|
|
38
|
+
# If no model_type is provided in the configuration file, default to
|
|
39
|
+
# the singular and camelized version of the identifier, allowing to
|
|
40
|
+
# create crud components without setting the :model_type option, when
|
|
41
|
+
# given a conventional name
|
|
42
|
+
attributes[:model_type] ||= identifier.to_s.camelize.singularize if identifier
|
|
43
|
+
attributes[:controller] ||= '/para/admin/crud_resources'
|
|
44
|
+
|
|
45
|
+
super
|
|
46
|
+
end
|
|
47
|
+
|
|
35
48
|
private
|
|
36
49
|
|
|
37
50
|
def namespaced_resources
|
|
@@ -42,6 +55,10 @@ module Para
|
|
|
42
55
|
para_component_resources: { component_id: id }
|
|
43
56
|
)
|
|
44
57
|
end
|
|
58
|
+
|
|
59
|
+
def ensure_model_type
|
|
60
|
+
self.model_type ||= identifier
|
|
61
|
+
end
|
|
45
62
|
end
|
|
46
63
|
end
|
|
47
64
|
end
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
module Para
|
|
2
|
+
module Component
|
|
3
|
+
class Form < Para::Component::Resource
|
|
4
|
+
register :form, self
|
|
5
|
+
|
|
6
|
+
configurable_on :model_type
|
|
7
|
+
|
|
8
|
+
has_one :component_resource, class_name: 'Para::ComponentResource',
|
|
9
|
+
foreign_key: :component_id, autosave: true, dependent: :destroy
|
|
10
|
+
|
|
11
|
+
def resource
|
|
12
|
+
build_component_resource(resource: model.new) unless component_resource
|
|
13
|
+
component_resource.resource ||= model.new
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def resource=(value)
|
|
17
|
+
build_component_resource(resource: value) unless component_resource
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def default_form_actions
|
|
21
|
+
[:submit]
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def update_with(attributes)
|
|
25
|
+
# If no model_type is provided in the configuration file, default to
|
|
26
|
+
# the camelized version of the identifier, allowing to create
|
|
27
|
+
# form components without setting the :model_type option,
|
|
28
|
+
# when given a conventional name
|
|
29
|
+
attributes[:model_type] ||= identifier.to_s.camelize.singularize if identifier
|
|
30
|
+
attributes[:controller] ||= '/para/admin/form_resources'
|
|
31
|
+
|
|
32
|
+
super
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
@@ -1,33 +1,22 @@
|
|
|
1
1
|
module Para
|
|
2
2
|
module Component
|
|
3
3
|
class Resource < Para::Component::Base
|
|
4
|
+
class ModelNotFound < NameError; end
|
|
5
|
+
|
|
4
6
|
def model
|
|
5
7
|
@model ||= model_type.presence && model_type.constantize
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
next true if name.match(/^HABTM_/)
|
|
14
|
-
next true if name.match(/Component$/)
|
|
15
|
-
next true if name.match(/^Para::Component/)
|
|
16
|
-
next true if excluded_models.include?(name)
|
|
17
|
-
|
|
18
|
-
false
|
|
19
|
-
end
|
|
8
|
+
rescue NameError
|
|
9
|
+
raise ModelNotFound,
|
|
10
|
+
"The model #{ model_type } was not found. You may need to set " +
|
|
11
|
+
"the :model_type option in your component definition in the " +
|
|
12
|
+
"config/components.rb file. If no component should actually " +
|
|
13
|
+
"reference this model, you may need to run the " +
|
|
14
|
+
"`rake para:components:clean` task to clean up your components index."
|
|
20
15
|
end
|
|
21
16
|
|
|
22
17
|
def model_table_name
|
|
23
18
|
model && model.table_name
|
|
24
19
|
end
|
|
25
|
-
|
|
26
|
-
private
|
|
27
|
-
|
|
28
|
-
def excluded_models
|
|
29
|
-
%w(FriendlyId::Slug)
|
|
30
|
-
end
|
|
31
20
|
end
|
|
32
21
|
end
|
|
33
22
|
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
module Para
|
|
2
|
+
module Library
|
|
3
|
+
class File < ActiveRecord::Base
|
|
4
|
+
has_attached_file :attachment
|
|
5
|
+
|
|
6
|
+
validates :attachment, presence: true
|
|
7
|
+
do_not_validate_attachment_file_type :attachment
|
|
8
|
+
|
|
9
|
+
# Return attachment.path or attachment.url depending on the storage
|
|
10
|
+
# backend, allowing 'openuri' and 'roo' libraries to load easily the
|
|
11
|
+
# file at the right path, on filesystem or othe storage systems, like S3.
|
|
12
|
+
#
|
|
13
|
+
def attachment_path
|
|
14
|
+
return unless attachment?
|
|
15
|
+
|
|
16
|
+
case attachment.options[:storage]
|
|
17
|
+
when :filesystem then attachment.path
|
|
18
|
+
else attachment.url
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
= modal.body do
|
|
2
|
+
- if status[:errors].any?
|
|
3
|
+
.alert.alert-warning
|
|
4
|
+
= t('para.flash.shared.import.success_with_errors')
|
|
5
|
+
|
|
6
|
+
%ul
|
|
7
|
+
- status[:errors].each do |message|
|
|
8
|
+
%li= message.html_safe
|
|
9
|
+
|
|
10
|
+
- else
|
|
11
|
+
.alert.alert-success
|
|
12
|
+
= t('para.flash.shared.import.success')
|
|
13
|
+
|
|
14
|
+
= modal.footer do
|
|
15
|
+
%button.btn.btn-default{ data: { dismiss: 'modal' } }
|
|
16
|
+
= t('para.shared.close')
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
= modal id: "component-import-#{ @importer.model_name.route_key }" do |modal|
|
|
2
|
+
= modal.header do
|
|
3
|
+
= @importer.model_name.human
|
|
4
|
+
|
|
5
|
+
= simple_form_for @file, as: :file, url: @component.path(namespace: :imports, importer: @importer.name), remote: true do |form|
|
|
6
|
+
= modal.body do
|
|
7
|
+
%p= t('para.import.help_text')
|
|
8
|
+
|
|
9
|
+
= form.input :attachment, label: false, placeholder: t('para.import.placeholder')
|
|
10
|
+
|
|
11
|
+
= modal.footer do
|
|
12
|
+
%button.btn.btn-primary{ type: 'submit' }
|
|
13
|
+
= fa_icon 'upload'
|
|
14
|
+
= t('para.import.name')
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
= modal id: "component-import-#{ @importer.model_name.route_key }", data: { :'import-status-url' => @component.path(namespace: :import, importer: @importer.name, id: @status.job_id) } do |modal|
|
|
2
|
+
= modal.header do
|
|
3
|
+
= @importer.model_name.human
|
|
4
|
+
|
|
5
|
+
- if @status.failed?
|
|
6
|
+
= render partial: 'failed', locals: { modal: modal }
|
|
7
|
+
- elsif @status.completed?
|
|
8
|
+
= render partial: 'completed', locals: { modal: modal, status: @status }
|
|
9
|
+
- else
|
|
10
|
+
= render partial: 'progress', locals: { modal: modal, status: @status }
|
|
@@ -1,22 +1,19 @@
|
|
|
1
1
|
- if component.importable?
|
|
2
|
-
- component.
|
|
3
|
-
=
|
|
4
|
-
.fileinput.fileinput-new.input-group{ data: { provides: 'fileinput' } }
|
|
5
|
-
.form-control.uneditable-input{ data: { trigger: 'fileinput' } }
|
|
6
|
-
%span.fileinput-placeholder
|
|
7
|
-
= t('para.import.placeholder')
|
|
8
|
-
= fa_icon 'file', class: 'fileinput-exists'
|
|
9
|
-
%span.fileinput-filename
|
|
10
|
-
.input-group-btn
|
|
11
|
-
.btn.btn-default.btn-file
|
|
12
|
-
%span.fileinput-new
|
|
13
|
-
= t('para.import.select')
|
|
14
|
-
%span.fileinput-exists
|
|
15
|
-
= t('para.import.change')
|
|
16
|
-
= file_field_tag 'file', class: 'file file-upload'
|
|
17
|
-
.btn.btn-danger.fileinput-exists{ type: 'button', data: { dismiss: 'fileinput' } }
|
|
18
|
-
= fa_icon 'times'
|
|
2
|
+
- if component.importers.length == 1
|
|
3
|
+
- importer = component.importers.first
|
|
19
4
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
5
|
+
= link_to component.path(namespace: :import, action: :new, importer: importer.model_name.singular_route_key), class: 'btn btn-default', remote: true, data: { :'importer-button' => true } do
|
|
6
|
+
= fa_icon 'upload'
|
|
7
|
+
= importer.model_name.human
|
|
8
|
+
|
|
9
|
+
- else
|
|
10
|
+
.btn-group
|
|
11
|
+
%button.btn.btn-default{ type: 'button', data: { toggle: 'dropdown' } }
|
|
12
|
+
= fa_icon 'upload'
|
|
13
|
+
= t('para.import.name')
|
|
14
|
+
%span.caret
|
|
15
|
+
%ul.dropdown-menu
|
|
16
|
+
- component.importers.each do |importer|
|
|
17
|
+
%li
|
|
18
|
+
= link_to component.path(:imports, action: :new, importer: importer.model_name.singular_route_key), remote: true, data: { :'importer-button' => true } do
|
|
19
|
+
= importer.model_name.human
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
.page-content-wrap
|
|
2
2
|
= panel do |panel|
|
|
3
3
|
= panel.header do
|
|
4
|
-
=
|
|
4
|
+
= render partial: find_partial_for(relation, :actions), locals: { relation: relation, component: component, model: model, allow_adding_resource: allow_adding_resource }
|
|
5
5
|
|
|
6
6
|
- if resources.length > 0
|
|
7
7
|
= panel.body do
|
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
= link_to admin_path do
|
|
4
4
|
= t('para.admin.title')
|
|
5
5
|
|
|
6
|
-
- if
|
|
7
|
-
-
|
|
6
|
+
- if admin_component_sections.any?
|
|
7
|
+
- admin_component_sections.each do |component_section|
|
|
8
8
|
- next unless component_section.components.any? { |component| can?(:manage, component) }
|
|
9
9
|
|
|
10
10
|
%li.component-section-item
|
data/config/locales/en.yml
CHANGED
|
@@ -14,6 +14,9 @@ en:
|
|
|
14
14
|
|
|
15
15
|
admin:
|
|
16
16
|
title: "Admin"
|
|
17
|
+
toggle_navigation: "Open navigation"
|
|
18
|
+
back_to_app: "Back to app"
|
|
19
|
+
sign_out: "Sign out"
|
|
17
20
|
|
|
18
21
|
confirmation:
|
|
19
22
|
shared:
|
|
@@ -28,6 +31,9 @@ en:
|
|
|
28
31
|
singleton_resource:
|
|
29
32
|
name: "Resource form"
|
|
30
33
|
|
|
34
|
+
dashboard:
|
|
35
|
+
title: "Dashboard"
|
|
36
|
+
|
|
31
37
|
component_section:
|
|
32
38
|
add: "Add a component section"
|
|
33
39
|
edit: 'Edit section'
|
|
@@ -73,6 +79,10 @@ en:
|
|
|
73
79
|
"true": "Yes"
|
|
74
80
|
"false": "No"
|
|
75
81
|
|
|
82
|
+
admin:
|
|
83
|
+
breadcrumbs:
|
|
84
|
+
home: "Dashboard"
|
|
85
|
+
|
|
76
86
|
activerecord:
|
|
77
87
|
errors:
|
|
78
88
|
relation_length_is_smaller: "must contain at least %{minimum} elements"
|
data/config/locales/fr.yml
CHANGED
|
@@ -15,8 +15,12 @@ fr:
|
|
|
15
15
|
success: "%{model} cloné(e)"
|
|
16
16
|
error: "Impossible de cloner le(a) %{model}"
|
|
17
17
|
import:
|
|
18
|
-
success: "
|
|
19
|
-
|
|
18
|
+
success: "L'import du fichier a été effectué avec succès"
|
|
19
|
+
success_with_errors: |
|
|
20
|
+
L'import du fichier a été effectué, mais certaines lignes n'ont pas
|
|
21
|
+
été prises en compte à causes d'erreurs :
|
|
22
|
+
other_errors: "<br>Et <b>%{count}</b> autres erreurs ..."
|
|
23
|
+
error: "Le fichier choisi contient des erreurs et n'a pu être importé"
|
|
20
24
|
|
|
21
25
|
admin:
|
|
22
26
|
title: "Administration"
|
|
@@ -60,7 +64,12 @@ fr:
|
|
|
60
64
|
name: Importer
|
|
61
65
|
select: "Sélectionnez un fichier"
|
|
62
66
|
change: "Changer"
|
|
67
|
+
help_text: |
|
|
68
|
+
Sélectionnez un fichier Excel (.xls, .xlsx) ou CSV (.csv) à importer et
|
|
69
|
+
cliquez sur le bouton "Importer".
|
|
63
70
|
placeholder: Fichier au format ( .csv .xlsx )
|
|
71
|
+
row_error_prefix: "Ligne %{number} :"
|
|
72
|
+
importing_file: "Le fichier est en cours d'import, merci de patienter quelques instants ..."
|
|
64
73
|
|
|
65
74
|
shared:
|
|
66
75
|
save: "Enregistrer"
|
|
@@ -70,6 +79,7 @@ fr:
|
|
|
70
79
|
save_and_edit: "Enregistrer et éditer"
|
|
71
80
|
save_and_add_another_button: "Enregistrer et créer un(e) autre"
|
|
72
81
|
destroy: "Supprimer"
|
|
82
|
+
close: "Fermer"
|
|
73
83
|
|
|
74
84
|
types:
|
|
75
85
|
boolean:
|
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
class <%= model_importer_name %> < Para::Importer::Base
|
|
2
|
+
# Let the importer rescue ActiveRecord::RecordInvalid errors and display them
|
|
3
|
+
# as flash messages after importing valid records
|
|
4
|
+
#
|
|
5
|
+
# Remove or comment this line to disable this behavior
|
|
6
|
+
#
|
|
7
|
+
allow_import_errors!
|
|
8
|
+
|
|
2
9
|
def import_from_row(row)
|
|
3
10
|
# Add your import logic here
|
|
4
11
|
end
|
|
5
|
-
end
|
|
12
|
+
end
|
|
@@ -24,7 +24,7 @@ module Para
|
|
|
24
24
|
gemfile_contents = File.read(Rails.root.join('Gemfile'))
|
|
25
25
|
|
|
26
26
|
[
|
|
27
|
-
['devise', '
|
|
27
|
+
['devise', '>= 3.0'],
|
|
28
28
|
# Allows for installing default wrappers and bootstrap adapters
|
|
29
29
|
# This should be avoided when add an initializer namespaced to the
|
|
30
30
|
# para environment
|
|
@@ -32,7 +32,6 @@ module Para
|
|
|
32
32
|
['simple_form_extension'],
|
|
33
33
|
# Pull requests are pending, and I don't want to release the gem
|
|
34
34
|
# under another name to be able to depend on it
|
|
35
|
-
['active_decorator', github: 'glyph-fr/active_decorator', branch: 'dev'],
|
|
36
35
|
['kaminari', '>= 0.16.1'],
|
|
37
36
|
['ransack', '>= 1.4.1'],
|
|
38
37
|
['bootstrap-kaminari-views', '>= 0.0.5']
|
|
@@ -3,11 +3,15 @@ Para.components.draw do
|
|
|
3
3
|
# You can translate the section title at: components.section.menu
|
|
4
4
|
#
|
|
5
5
|
# section :menu do
|
|
6
|
-
#
|
|
7
|
-
# #
|
|
8
|
-
#
|
|
9
|
-
#
|
|
6
|
+
# # Creating crud components can be done the following way
|
|
7
|
+
# #
|
|
8
|
+
# component :pages, :crud
|
|
9
|
+
# component :members, :crud, model_type: 'User'
|
|
10
|
+
# component :news, :crud, model_type: 'Page', namespaced: true
|
|
11
|
+
|
|
12
|
+
# # Creating a component allowing you to edit a single resource is done
|
|
13
|
+
# # with the `singleton_resource` component, the following way
|
|
10
14
|
# #
|
|
11
|
-
# component :
|
|
15
|
+
# component :home, :singleton_resource, model_type: 'HomePage'
|
|
12
16
|
# end
|
|
13
17
|
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
module Para
|
|
2
|
+
class TreeItemGenerator < Para::Generators::NamedBase
|
|
3
|
+
include Para::Admin::BaseHelper
|
|
4
|
+
include Para::Generators::FieldHelpers
|
|
5
|
+
|
|
6
|
+
source_root File.expand_path('../../../../../app/views/para/admin/resources', __FILE__)
|
|
7
|
+
|
|
8
|
+
desc 'Para resource tree item generator'
|
|
9
|
+
|
|
10
|
+
def generate_table
|
|
11
|
+
template(
|
|
12
|
+
'_tree_item.html.haml',
|
|
13
|
+
"app/views/admin/#{ plural_namespaced_path }/_tree_item.haml"
|
|
14
|
+
)
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -4,7 +4,7 @@ module Para
|
|
|
4
4
|
class_attribute :_field_options
|
|
5
5
|
cattr_accessor :_field_types
|
|
6
6
|
|
|
7
|
-
attr_reader :model, :name, :type, :field_type, :field_method
|
|
7
|
+
attr_reader :model, :name, :type, :field_type, :field_method, :options
|
|
8
8
|
|
|
9
9
|
def self.field_option(key, method_name, options = {})
|
|
10
10
|
self._field_options ||= []
|
|
@@ -43,9 +43,10 @@ module Para
|
|
|
43
43
|
|
|
44
44
|
def initialize(model, options = {})
|
|
45
45
|
@model = model
|
|
46
|
-
@name = options
|
|
47
|
-
@type = options
|
|
48
|
-
@field_type = options
|
|
46
|
+
@name = options.delete(:name)
|
|
47
|
+
@type = options.delete(:type)
|
|
48
|
+
@field_type = options.delete(:field_type)
|
|
49
|
+
@options = options
|
|
49
50
|
|
|
50
51
|
determine_name_and_field_method!
|
|
51
52
|
end
|
|
@@ -70,6 +71,13 @@ module Para
|
|
|
70
71
|
instance.send(name)
|
|
71
72
|
end
|
|
72
73
|
|
|
74
|
+
#
|
|
75
|
+
def searchable?
|
|
76
|
+
options[:searchable] != false && (
|
|
77
|
+
[:string, :text].include?(type.to_sym) && !name.match(/password/)
|
|
78
|
+
)
|
|
79
|
+
end
|
|
80
|
+
|
|
73
81
|
# Allows parsing input params before they're passed to the model, so
|
|
74
82
|
# it can be easy to edit them according to some field type specific
|
|
75
83
|
# behavior
|