para 0.4.0 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/app/assets/images/para/admin/loading-spinner.gif +0 -0
- data/app/assets/javascripts/para/admin/theme_actions.coffee +0 -1
- data/app/assets/javascripts/para/lib/turbolinks-forms.coffee +23 -0
- data/app/assets/javascripts/para/lib/turbolinks-loading.coffee +25 -0
- data/app/assets/stylesheets/para/{overrides → admin/src}/datetimepicker.sass +1 -3
- data/app/assets/stylesheets/para/{overrides → admin/src}/fuelux.sass +5 -8
- data/app/assets/stylesheets/para/{overrides → admin/src}/jasny.bootstrap.sass +1 -2
- data/app/assets/stylesheets/para/admin/src/page-loading.sass +24 -0
- data/app/assets/stylesheets/para/{overrides → admin/src}/redactor.sass +5 -7
- data/app/assets/stylesheets/para/{overrides → admin/src}/selectize.sass +4 -6
- data/app/assets/stylesheets/para/{overrides → admin/src}/slider.sass +0 -1
- data/app/assets/stylesheets/para/admin/theme/_base.sass +5 -3
- data/app/assets/stylesheets/para/admin/theme/_breadcrumb.sass +54 -16
- data/app/assets/stylesheets/para/admin/theme/_buttons.sass +0 -1
- data/app/assets/stylesheets/para/admin/theme/_checkable.sass +5 -6
- data/app/assets/stylesheets/para/admin/theme/_commonds.sass +10 -16
- data/app/assets/stylesheets/para/admin/theme/_dropdown.sass +1 -4
- data/app/assets/stylesheets/para/admin/theme/_form.sass +11 -3
- data/app/assets/stylesheets/para/admin/theme/_list.sass +5 -6
- data/app/assets/stylesheets/para/admin/theme/_navigation.sass +105 -109
- data/app/assets/stylesheets/para/admin/theme/_navtabs.sass +35 -15
- data/app/assets/stylesheets/para/admin/theme/_orderable.sass +2 -5
- data/app/assets/stylesheets/para/admin/theme/_panel.sass +20 -50
- data/app/assets/stylesheets/para/admin/theme/_sorting.sass +5 -7
- data/app/assets/stylesheets/para/admin/theme/_tree.sass +2 -4
- data/app/assets/stylesheets/para/admin.sass +1 -0
- data/app/assets/stylesheets/para/lib/_variables.scss +12 -12
- data/app/assets/stylesheets/para/overrides/responsive.sass +1 -2
- data/app/assets/stylesheets/para/overrides/theme.sass +10 -17
- data/app/controllers/para/admin/base_controller.rb +16 -5
- data/app/controllers/para/admin/crud_resources_controller.rb +43 -2
- data/app/controllers/para/admin/main_controller.rb +1 -1
- data/app/controllers/para/admin/resources_controller.rb +1 -1
- data/app/controllers/para/admin/settings_component_controller.rb +1 -3
- data/app/controllers/para/application_controller.rb +3 -3
- data/app/decorators/para/component/crud_decorator.rb +6 -2
- data/app/decorators/para/component/singleton_resource_decorator.rb +5 -1
- data/app/helpers/para/admin/base_helper.rb +9 -4
- data/app/helpers/para/admin/components_helper.rb +7 -0
- data/app/helpers/para/form_helper.rb +10 -2
- data/app/helpers/para/tag_helper.rb +12 -0
- data/app/models/para/ability.rb +12 -0
- data/app/models/para/component/base.rb +15 -7
- data/app/models/para/component/crud.rb +3 -1
- data/app/models/para/component/singleton_resource.rb +1 -1
- data/app/views/para/admin/crud_resources/index.html.haml +4 -0
- data/app/views/para/admin/dashboard.html.haml +10 -8
- data/app/views/para/admin/resources/_actions.html.haml +7 -0
- data/app/views/para/admin/resources/_add_button.html.haml +1 -0
- data/app/views/para/admin/resources/_filters.html.haml +1 -1
- data/app/views/para/admin/resources/_imports_menu.html.haml +22 -0
- data/app/views/para/admin/resources/_list.html.haml +8 -5
- data/app/views/para/admin/resources/_subclassable_add_button.html.haml +10 -0
- data/app/views/para/admin/resources/_tree.html.haml +1 -1
- data/app/views/para/admin/resources/_tree_item.html.haml +1 -1
- data/app/views/para/admin/resources/new.html.haml +1 -1
- data/app/views/para/admin/shared/_breadcrumbs.html.haml +8 -0
- data/app/views/para/admin/shared/_header.html.haml +26 -24
- data/app/views/para/admin/shared/_navigation.html.haml +5 -3
- data/app/views/para/form/_tabs.html.haml +13 -0
- data/app/views/para/inputs/_nested_many.html.haml +2 -2
- data/app/views/para/inputs/_nested_many_container.html.haml +1 -3
- data/config/locales/en.yml +10 -0
- data/config/locales/fr.yml +30 -15
- data/db/migrate/20160304113055_add_json_equality_operator_patch_to_postgres.rb +38 -0
- data/lib/generators/para/component/component_generator.rb +9 -29
- data/lib/generators/para/component/crud/crud_generator.rb +41 -0
- data/lib/generators/para/component/templates/component.rb +1 -1
- data/lib/generators/para/component/templates/decorator.rb +3 -0
- data/lib/generators/para/component/templates/resources_controller.rb +4 -0
- data/lib/generators/para/exporter/templates/base_exporter.rb +2 -0
- data/lib/generators/para/exporter/templates/csv_exporter.rb +2 -0
- data/lib/generators/para/filters/filters_generator.rb +16 -0
- data/lib/generators/para/filters/templates/_filters.html.haml +9 -0
- data/lib/generators/para/importer/importer_generator.rb +20 -0
- data/lib/generators/para/importer/templates/base_importer.rb +5 -0
- data/lib/generators/para/install/install_generator.rb +6 -25
- data/lib/generators/para/nested_fields/nested_fields_generator.rb +9 -0
- data/lib/para/attribute_field/base.rb +28 -0
- data/lib/para/attribute_field/belongs_to.rb +2 -0
- data/lib/para/attribute_field/boolean.rb +2 -0
- data/lib/para/attribute_field/datetime.rb +2 -0
- data/lib/para/attribute_field/enum.rb +22 -0
- data/lib/para/attribute_field/file.rb +2 -0
- data/lib/para/attribute_field/has_many.rb +2 -0
- data/lib/para/attribute_field/image.rb +2 -0
- data/lib/para/attribute_field/nested_many.rb +3 -0
- data/lib/para/attribute_field/nested_one.rb +6 -6
- data/lib/para/attribute_field/password.rb +2 -0
- data/lib/para/attribute_field/redactor.rb +2 -0
- data/lib/para/attribute_field/translation.rb +2 -0
- data/lib/para/attribute_field.rb +19 -0
- data/lib/para/attribute_field_mappings.rb +15 -29
- data/lib/para/breadcrumbs/breadcrumb.rb +43 -0
- data/lib/para/breadcrumbs/controller.rb +39 -0
- data/lib/para/breadcrumbs/manager.rb +19 -0
- data/lib/para/breadcrumbs.rb +9 -0
- data/lib/para/component/importable.rb +25 -0
- data/lib/para/component/subclassable.rb +27 -0
- data/lib/para/component.rb +5 -3
- data/lib/para/components_configuration.rb +18 -2
- data/lib/para/config.rb +25 -1
- data/lib/para/exporter/base.rb +13 -0
- data/lib/para/exporter/csv.rb +1 -1
- data/lib/para/form_builder/tabs.rb +56 -0
- data/lib/para/form_builder.rb +2 -0
- data/lib/para/generators/component_helpers.rb +57 -0
- data/lib/para/generators.rb +1 -0
- data/lib/para/importer/base.rb +23 -0
- data/lib/para/importer.rb +10 -0
- data/lib/para/inputs/nested_one_input.rb +13 -3
- data/lib/para/markup/resources_table.rb +48 -24
- data/lib/para/markup/resources_tree.rb +36 -0
- data/lib/para/model_field_parsers/store.rb +23 -0
- data/lib/para/model_field_parsers.rb +1 -0
- data/lib/para/orderable.rb +6 -3
- data/lib/para/plugins/routes.rb +25 -0
- data/lib/para/plugins.rb +11 -0
- data/lib/para/routes.rb +2 -25
- data/lib/para/version.rb +1 -1
- data/lib/para.rb +4 -2
- data/lib/rails/routing_mapper.rb +64 -5
- metadata +50 -64
- data/app/controllers/para/admin/crud_component_controller.rb +0 -17
- data/app/controllers/para/admin/singleton_resource_component_controller.rb +0 -14
- data/app/views/para/admin/component_sections/_form.html.haml +0 -10
- data/app/views/para/admin/component_sections/edit.html.haml +0 -5
- data/app/views/para/admin/component_sections/new.html.haml +0 -5
- data/app/views/para/admin/components/_form.html.haml +0 -15
- data/app/views/para/admin/components/new.html.haml +0 -4
- data/app/views/para/admin/shared/_breadcrumb.html.haml +0 -3
- /data/app/views/para/admin/{singleton_resource_component → singleton_resources}/show.html.haml +0 -0
@@ -157,7 +157,7 @@ $input-border: $gray-light !default;
|
|
157
157
|
$input-border-radius: $border-radius-base !default;
|
158
158
|
$input-border-focus: #C1C1C1 !default;
|
159
159
|
|
160
|
-
$input-color-placeholder: $gray-
|
160
|
+
$input-color-placeholder: $gray-dark !default;
|
161
161
|
|
162
162
|
$input-height-base: ($line-height-computed + ($padding-base-vertical * 2) + 2) !default;
|
163
163
|
$input-height-large: (ceil($font-size-large * $line-height-large) + ($padding-large-vertical * 2) + 2) !default;
|
@@ -260,7 +260,7 @@ $grid-float-breakpoint-max: ($grid-float-breakpoint - 1) !default;
|
|
260
260
|
// -------------------------
|
261
261
|
|
262
262
|
// Basics of a navbar
|
263
|
-
$navbar-height:
|
263
|
+
$navbar-height: 40px !default;
|
264
264
|
$navbar-margin-bottom: $line-height-computed !default;
|
265
265
|
$navbar-border-radius: $border-radius-base !default;
|
266
266
|
$navbar-padding-horizontal: floor($grid-gutter-width / 2) !default;
|
@@ -293,16 +293,16 @@ $navbar-default-toggle-border-color: #ddd !default;
|
|
293
293
|
// Inverted navbar
|
294
294
|
//
|
295
295
|
// Reset inverted navbar basics
|
296
|
-
$navbar-inverse-color:
|
297
|
-
$navbar-inverse-bg: #
|
298
|
-
$navbar-inverse-border:
|
296
|
+
$navbar-inverse-color: #000 !default;
|
297
|
+
$navbar-inverse-bg: #F9F9F9 !default;
|
298
|
+
$navbar-inverse-border: #EEEEEE !default;
|
299
299
|
|
300
300
|
// Inverted navbar links
|
301
|
-
$navbar-inverse-link-color:
|
302
|
-
$navbar-inverse-link-hover-color: #
|
301
|
+
$navbar-inverse-link-color: #626262 !default;
|
302
|
+
$navbar-inverse-link-hover-color: #428bca !default;
|
303
303
|
$navbar-inverse-link-hover-bg: transparent !default;
|
304
304
|
$navbar-inverse-link-active-color: $navbar-inverse-link-hover-color !default;
|
305
|
-
$navbar-inverse-link-active-bg:
|
305
|
+
$navbar-inverse-link-active-bg: #fff !default;
|
306
306
|
$navbar-inverse-link-disabled-color: #444 !default;
|
307
307
|
$navbar-inverse-link-disabled-bg: transparent !default;
|
308
308
|
|
@@ -572,10 +572,10 @@ $badge-border-radius: 10px !default;
|
|
572
572
|
|
573
573
|
// Breadcrumbs
|
574
574
|
// -------------------------
|
575
|
-
$breadcrumb-bg: #
|
576
|
-
$breadcrumb-color: #
|
577
|
-
$breadcrumb-active-color:
|
578
|
-
$breadcrumb-separator: "
|
575
|
+
$breadcrumb-bg: #f7f7f7 !default;
|
576
|
+
$breadcrumb-color: #555 !default;
|
577
|
+
$breadcrumb-active-color: $brand-primary !default;
|
578
|
+
$breadcrumb-separator: "" !default;
|
579
579
|
|
580
580
|
|
581
581
|
// Carousel
|
@@ -1,5 +1,4 @@
|
|
1
1
|
@import "para/admin/theme/variables"
|
2
|
-
@import "compass/css3/shared"
|
3
2
|
|
4
3
|
$experimental-support-for-opera: true
|
5
4
|
|
@@ -39,7 +38,7 @@ $experimental-support-for-opera: true
|
|
39
38
|
@media (min-width: 1025px)
|
40
39
|
.form-fixed-actions
|
41
40
|
.form-actions
|
42
|
-
|
41
|
+
width: calc(100% - 270px)
|
43
42
|
|
44
43
|
/* Medium high devices (desktops, 1200px and up) */
|
45
44
|
@media (min-width: 1200px)
|
@@ -1,13 +1,6 @@
|
|
1
1
|
@import "para/admin/theme/variables"
|
2
|
-
@import "compass/css3/text-shadow"
|
3
|
-
@import "compass/css3/inline-block"
|
4
|
-
@import "compass/css3/transition"
|
5
|
-
@import "compass/css3/box-shadow"
|
6
|
-
@import "compass/css3/border-radius"
|
7
|
-
@import "compass/css3/transform"
|
8
2
|
|
9
3
|
.animated
|
10
|
-
-webkit-animation-duration: 100ms
|
11
4
|
animation-duration: 100ms
|
12
5
|
|
13
6
|
// More button style
|
@@ -18,11 +11,11 @@
|
|
18
11
|
|
19
12
|
@mixin button-hover-focus-active($color-border, $color-bg)
|
20
13
|
position: relative
|
21
|
-
|
22
|
-
|
14
|
+
box-shadow: 0px 2px darken($color-border, 10%)
|
15
|
+
transition: none
|
23
16
|
&:hover
|
24
17
|
top: 1px
|
25
|
-
|
18
|
+
box-shadow: 0px 1px darken($color-border, 10%)
|
26
19
|
background-color: $color-bg
|
27
20
|
border-color: $color-border
|
28
21
|
&:focus,
|
@@ -31,7 +24,7 @@
|
|
31
24
|
.open &.dropdown-toggle
|
32
25
|
background-color: darken($color-bg, 7%)
|
33
26
|
top: 2px
|
34
|
-
|
27
|
+
box-shadow: 0px 0 darken($color-border, 10%)
|
35
28
|
border-color: $color-border
|
36
29
|
&:hover
|
37
30
|
background-color: darken($color-bg, 7%)
|
@@ -39,10 +32,10 @@
|
|
39
32
|
@mixin button-variant-inverse($color-border, $color-bg)
|
40
33
|
color: $color-border
|
41
34
|
background-color: transparent
|
42
|
-
|
43
|
-
|
35
|
+
box-shadow: none
|
36
|
+
transition: all, .2s, linear
|
44
37
|
&:hover
|
45
|
-
|
38
|
+
box-shadow: none
|
46
39
|
top: 0
|
47
40
|
color: #fff
|
48
41
|
background-color: $color-bg
|
@@ -52,7 +45,7 @@
|
|
52
45
|
&:active,
|
53
46
|
&.active,
|
54
47
|
.open &.dropdown-toggle
|
55
|
-
|
48
|
+
box-shadow: none
|
56
49
|
top: 0
|
57
50
|
color: #fff
|
58
51
|
background-color: darken($color-bg, 7%)
|
@@ -64,7 +57,7 @@ input,
|
|
64
57
|
textarea,
|
65
58
|
select,
|
66
59
|
button
|
67
|
-
|
60
|
+
transition: all, .1s, linear
|
68
61
|
&,
|
69
62
|
&:active,
|
70
63
|
&.active
|
@@ -148,7 +141,7 @@ button
|
|
148
141
|
.btn:focus,
|
149
142
|
.btn:active,
|
150
143
|
top: 0
|
151
|
-
|
144
|
+
box-shadow: none
|
152
145
|
|
153
146
|
.form-group-separated
|
154
147
|
&:after
|
@@ -4,31 +4,40 @@ module Para
|
|
4
4
|
include Para::Admin::BaseHelper
|
5
5
|
|
6
6
|
if Para.config.authenticate_admin_method
|
7
|
-
|
7
|
+
before_action Para.config.authenticate_admin_method
|
8
8
|
end
|
9
9
|
|
10
|
-
|
10
|
+
before_action :authorize_admin_access
|
11
|
+
before_action :load_component_sections
|
11
12
|
|
12
13
|
layout 'para/admin'
|
13
14
|
|
15
|
+
helper_method :current_admin
|
16
|
+
|
14
17
|
def current_admin
|
15
|
-
if Para.config.current_admin_method
|
18
|
+
@current_admin ||= if Para.config.current_admin_method
|
16
19
|
send(Para.config.current_admin_method)
|
17
20
|
end
|
18
21
|
end
|
19
22
|
|
20
23
|
def current_ability
|
21
|
-
|
24
|
+
@current_ability ||= if (class_name = Para::Config.ability_class_name)
|
25
|
+
class_name.constantize.new(current_admin)
|
26
|
+
end
|
22
27
|
end
|
23
28
|
|
24
29
|
private
|
25
30
|
|
31
|
+
def authorize_admin_access
|
32
|
+
authorize! :access, :admin
|
33
|
+
end
|
34
|
+
|
26
35
|
def load_component_sections
|
27
36
|
@component_sections = Para::ComponentSection.ordered.includes(:components)
|
28
37
|
end
|
29
38
|
|
30
39
|
def self.load_and_authorize_component(options = {})
|
31
|
-
|
40
|
+
before_action do
|
32
41
|
load_and_authorize_component(options)
|
33
42
|
end
|
34
43
|
end
|
@@ -40,6 +49,8 @@ module Para
|
|
40
49
|
loader.load_and_authorize_resource
|
41
50
|
|
42
51
|
ActiveDecorator::Decorator.instance.decorate(@component) if @component
|
52
|
+
|
53
|
+
add_breadcrumb(@component.name, @component.path) if @component
|
43
54
|
end
|
44
55
|
end
|
45
56
|
end
|
@@ -6,9 +6,23 @@ module Para
|
|
6
6
|
include Para::Admin::ResourceControllerConcerns
|
7
7
|
|
8
8
|
before_filter :load_and_authorize_crud_resource
|
9
|
+
before_filter :add_breadcrumbs, only: [:show, :index, :edit, :new]
|
10
|
+
|
9
11
|
after_filter :attach_resource_to_component, only: [:create]
|
10
12
|
after_filter :remove_resource_from_component, only: [:destroy]
|
11
13
|
|
14
|
+
def index
|
15
|
+
@q = @component.resources.search(params[:q])
|
16
|
+
@resources = @q.result.uniq.page(params[:page])
|
17
|
+
|
18
|
+
# Sort collection for orderable and trees
|
19
|
+
@resources = if @resources.respond_to?(:ordered)
|
20
|
+
@resources.ordered
|
21
|
+
else
|
22
|
+
@resources.order(created_at: :desc)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
12
26
|
def clone
|
13
27
|
new_resource = resource.deep_clone include: resource.class.cloneable_associations
|
14
28
|
new_resource.save!
|
@@ -37,18 +51,41 @@ module Para
|
|
37
51
|
if @component.exportable?
|
38
52
|
exporter = Para::Exporter.for(
|
39
53
|
resource_model.name, params[:format]
|
40
|
-
).new(@component.resources.search(params[:q]).result)
|
54
|
+
).new(@component.resources.search(params[:q]).result.uniq)
|
41
55
|
|
42
56
|
send_data exporter.render, type: exporter.mime_type,
|
43
57
|
disposition: exporter.disposition,
|
44
58
|
filename: exporter.file_name
|
45
59
|
else
|
46
|
-
redirect_to
|
60
|
+
redirect_to @component.path
|
47
61
|
end
|
48
62
|
end
|
49
63
|
|
64
|
+
def import
|
65
|
+
if @component.importable?
|
66
|
+
file = params[:file]
|
67
|
+
if file
|
68
|
+
importer = params[:importer].constantize.new(file.tempfile)
|
69
|
+
importer.run
|
70
|
+
flash_message(:success)
|
71
|
+
else
|
72
|
+
flash_message(:error)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
redirect_to @component.path
|
76
|
+
end
|
77
|
+
|
50
78
|
private
|
51
79
|
|
80
|
+
def resource_model
|
81
|
+
@resource_model ||=
|
82
|
+
if @component.subclassable_with?(params[:type])
|
83
|
+
params[:type].constantize
|
84
|
+
else
|
85
|
+
super
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
52
89
|
def load_and_authorize_crud_resource
|
53
90
|
loader = self.class.cancan_resource_class.new(
|
54
91
|
self, resource_name, parent: false, class: resource_model.name
|
@@ -57,6 +94,10 @@ module Para
|
|
57
94
|
loader.load_and_authorize_resource
|
58
95
|
end
|
59
96
|
|
97
|
+
def add_breadcrumbs
|
98
|
+
add_breadcrumb(resource_title_for(resource)) if resource
|
99
|
+
end
|
100
|
+
|
60
101
|
def attach_resource_to_component
|
61
102
|
return unless resource.persisted? && @component.namespaced?
|
62
103
|
@component.add_resource(resource)
|
@@ -3,6 +3,10 @@ module Para
|
|
3
3
|
module CrudDecorator
|
4
4
|
include Para::Component::BaseDecorator
|
5
5
|
|
6
|
+
def path(options = {})
|
7
|
+
find_path([:admin, self, :resources], options)
|
8
|
+
end
|
9
|
+
|
6
10
|
def relation_path(controller_or_resource, options = {})
|
7
11
|
if (id = extract_id_from(controller_or_resource))
|
8
12
|
options[:id] = id
|
@@ -22,9 +26,9 @@ module Para
|
|
22
26
|
|
23
27
|
def route_key_for(id, options)
|
24
28
|
if id || options[:action].presence && options[:action].to_sym == :new
|
25
|
-
:
|
29
|
+
:resource
|
26
30
|
else
|
27
|
-
:
|
31
|
+
:resources
|
28
32
|
end
|
29
33
|
end
|
30
34
|
end
|
@@ -3,8 +3,12 @@ module Para
|
|
3
3
|
module SingletonResourceDecorator
|
4
4
|
include Para::Component::BaseDecorator
|
5
5
|
|
6
|
+
def path(options = {})
|
7
|
+
find_path([:admin, self], options)
|
8
|
+
end
|
9
|
+
|
6
10
|
def relation_path(controller_or_resource, options = {})
|
7
|
-
|
11
|
+
path
|
8
12
|
end
|
9
13
|
end
|
10
14
|
end
|
@@ -3,7 +3,7 @@ module Para
|
|
3
3
|
module BaseHelper
|
4
4
|
include Para::ApplicationHelper
|
5
5
|
|
6
|
-
def find_partial_for(relation, partial)
|
6
|
+
def find_partial_for(relation, partial, partial_dir: 'admin/resources')
|
7
7
|
if relation.kind_of? ActiveRecord::Base
|
8
8
|
relation = relation.class
|
9
9
|
end
|
@@ -13,7 +13,7 @@ module Para
|
|
13
13
|
if lookup_context.find_all("admin/#{relation}/_#{ partial }").any?
|
14
14
|
"admin/#{ relation }/#{ partial }"
|
15
15
|
else
|
16
|
-
"para
|
16
|
+
"para/#{ partial_dir }/#{ partial }"
|
17
17
|
end
|
18
18
|
end
|
19
19
|
|
@@ -24,8 +24,13 @@ module Para
|
|
24
24
|
end
|
25
25
|
|
26
26
|
def resource_title_for(resource)
|
27
|
-
|
28
|
-
|
27
|
+
if resource.new_record?
|
28
|
+
t('para.form.shared.new.title', model: resource.class.model_name.human)
|
29
|
+
else
|
30
|
+
resource.try(:title).presence ||
|
31
|
+
resource.try(:name).presence ||
|
32
|
+
t('para.form.shared.edit.title', model: resource.class.model_name.human)
|
33
|
+
end
|
29
34
|
end
|
30
35
|
|
31
36
|
def registered_components_options
|
@@ -4,7 +4,7 @@ module Para
|
|
4
4
|
default_options = {
|
5
5
|
as: :resource,
|
6
6
|
wrapper: :horizontal_form,
|
7
|
-
html: { class: '' }
|
7
|
+
html: { class: '', data: { :'para-form' => true } }
|
8
8
|
}
|
9
9
|
|
10
10
|
options = default_options.deep_merge(options)
|
@@ -22,7 +22,15 @@ module Para
|
|
22
22
|
default_options[:html][:class] << ' form-fixed-actions'
|
23
23
|
end
|
24
24
|
|
25
|
-
simple_form_for(resource, options
|
25
|
+
simple_form_for(resource, options) do |form|
|
26
|
+
capture { block.call(form) }.tap do |content|
|
27
|
+
# Append hidden field with type if resource is subclassable
|
28
|
+
# to avoid bad class instantiation in create action
|
29
|
+
if @component.subclassable? && resource.new_record?
|
30
|
+
content << form.hidden_field(:type, value: resource.type)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
26
34
|
end
|
27
35
|
end
|
28
36
|
end
|
@@ -46,5 +46,17 @@ module Para
|
|
46
46
|
locals: options
|
47
47
|
)
|
48
48
|
end
|
49
|
+
|
50
|
+
def add_button_for(component, relation, model)
|
51
|
+
partial_name = if component.subclassable?
|
52
|
+
:subclassable_add_button
|
53
|
+
else
|
54
|
+
:add_button
|
55
|
+
end
|
56
|
+
|
57
|
+
render partial: find_partial_for(relation, partial_name), locals: {
|
58
|
+
component: component, model: model
|
59
|
+
}
|
60
|
+
end
|
49
61
|
end
|
50
62
|
end
|
@@ -10,12 +10,11 @@ module Para
|
|
10
10
|
Para::Component.registered_components[name] = component
|
11
11
|
end
|
12
12
|
|
13
|
-
|
14
|
-
friendly_id :name, use: [:slugged, :finders, :history]
|
13
|
+
belongs_to :component_section, class_name: 'Para::ComponentSection'
|
15
14
|
|
16
15
|
validates :identifier, :type, presence: true
|
17
16
|
|
18
|
-
|
17
|
+
before_validation :ensure_slug
|
19
18
|
|
20
19
|
scope :ordered, -> { order(position: :asc) }
|
21
20
|
|
@@ -30,6 +29,10 @@ module Para
|
|
30
29
|
false
|
31
30
|
end
|
32
31
|
|
32
|
+
def subclassable?
|
33
|
+
false
|
34
|
+
end
|
35
|
+
|
33
36
|
def self.model_name
|
34
37
|
@model_name ||= ModelName.new(self)
|
35
38
|
end
|
@@ -47,14 +50,19 @@ module Para
|
|
47
50
|
@configurable_attributes ||= {}
|
48
51
|
end
|
49
52
|
|
50
|
-
def should_generate_new_friendly_id?
|
51
|
-
slug.blank? || name_changed?
|
52
|
-
end
|
53
|
-
|
54
53
|
def default_form_actions
|
55
54
|
[:submit, :submit_and_edit, :submit_and_add_another, :cancel]
|
56
55
|
end
|
57
56
|
|
57
|
+
def to_param
|
58
|
+
slug
|
59
|
+
end
|
60
|
+
|
61
|
+
private
|
62
|
+
|
63
|
+
def ensure_slug
|
64
|
+
self.slug = identifier.parameterize if slug.blank? || identifier_changed?
|
65
|
+
end
|
58
66
|
end
|
59
67
|
|
60
68
|
class ModelName < ActiveModel::Name
|
@@ -4,12 +4,14 @@ module Para
|
|
4
4
|
register :crud, self
|
5
5
|
|
6
6
|
include Para::Component::Exportable
|
7
|
+
include Para::Component::Importable
|
8
|
+
include Para::Component::Subclassable
|
7
9
|
|
8
10
|
configurable_on :model_type
|
9
11
|
configurable_on :namespaced
|
10
12
|
|
11
13
|
has_many :component_resources, class_name: 'Para::ComponentResource',
|
12
|
-
foreign_key: :component_id, autosave: true
|
14
|
+
foreign_key: :component_id, autosave: true, dependent: :destroy
|
13
15
|
|
14
16
|
def namespaced?
|
15
17
|
case namespaced
|
@@ -6,7 +6,7 @@ module Para
|
|
6
6
|
configurable_on :model_type, as: :selectize, collection: :available_models
|
7
7
|
|
8
8
|
has_one :component_resource, class_name: 'Para::ComponentResource',
|
9
|
-
foreign_key: :component_id, autosave: true
|
9
|
+
foreign_key: :component_id, autosave: true, dependent: :destroy
|
10
10
|
|
11
11
|
def resource
|
12
12
|
build_component_resource(resource: model.new) unless component_resource
|
@@ -1,10 +1,12 @@
|
|
1
1
|
.page-title
|
2
|
-
%h1
|
3
|
-
|
2
|
+
%h1= t('para.dashboard.title')
|
3
|
+
|
4
4
|
.page-content-wrap
|
5
|
-
.
|
6
|
-
.
|
7
|
-
.
|
8
|
-
.
|
9
|
-
|
10
|
-
|
5
|
+
- ordered_components.each_slice(3) do |components|
|
6
|
+
.row
|
7
|
+
- components.each do |component|
|
8
|
+
.col-md-4
|
9
|
+
= link_to component.path, class: 'panel panel-default' do
|
10
|
+
.panel-body
|
11
|
+
= component.name
|
12
|
+
|
@@ -0,0 +1,7 @@
|
|
1
|
+
%ul.panel-controls
|
2
|
+
%li
|
3
|
+
= add_button_for(component, relation, model) if allow_adding_resource
|
4
|
+
%li
|
5
|
+
= render partial: find_partial_for(relation, :exports_menu), locals: { component: component, model: model }
|
6
|
+
%li
|
7
|
+
= render partial: find_partial_for(relation, :imports_menu), locals: { component: component, model: model }
|
@@ -0,0 +1 @@
|
|
1
|
+
= icon_link_to t('para.shared.add'), component.relation_path(model.model_name.singular_route_key, action: :new), icon: 'plus', class: 'btn btn-primary add-button'
|
@@ -3,7 +3,7 @@
|
|
3
3
|
%span.input-group-addon
|
4
4
|
%i.fa.fa-search
|
5
5
|
|
6
|
-
= form.input_field fulltext_search_param_for(attributes), as: :string,
|
6
|
+
= form.input_field fulltext_search_param_for(attributes), as: :string, placeholder: t('para.shared.search'), class: 'form-control'
|
7
7
|
|
8
8
|
%span.input-group-btn
|
9
9
|
= form.submit t('para.shared.search'), class: 'btn btn-default'
|
@@ -0,0 +1,22 @@
|
|
1
|
+
- if component.importable?
|
2
|
+
- component.imports.each do |importer|
|
3
|
+
= form_tag component.relation_path(model.model_name.route_key, action: :import, importer: importer), method: 'post', multipart: 'true' do
|
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'
|
19
|
+
|
20
|
+
%button.btn.btn-default{ type: 'submit' }
|
21
|
+
= fa_icon 'upload'
|
22
|
+
= t('para.import.name')
|
@@ -1,9 +1,7 @@
|
|
1
1
|
.page-content-wrap
|
2
2
|
= panel do |panel|
|
3
3
|
= panel.header do
|
4
|
-
=
|
5
|
-
|
6
|
-
= render partial: find_partial_for(relation, :exports_menu), locals: { component: component, model: model }
|
4
|
+
= render partial: find_partial_for(relation, :actions), locals: { relation: relation, component: component, model: model, allow_adding_resource: allow_adding_resource }
|
7
5
|
|
8
6
|
= panel.body do
|
9
7
|
= render partial: find_partial_for(relation, :filters), locals: { attributes: attributes }
|
@@ -14,8 +12,13 @@
|
|
14
12
|
|
15
13
|
- else
|
16
14
|
= panel.body do
|
17
|
-
= alert class: 'no-margin-bottom', dismissable: false do
|
18
|
-
|
15
|
+
= alert class: 'no-results no-margin-bottom', dismissable: false do
|
16
|
+
- if filtered?(attributes)
|
17
|
+
= t('para.list.no_results')
|
18
|
+
- else
|
19
|
+
= t('para.list.empty')
|
20
|
+
|
21
|
+
= add_button_for(component, relation, model) if allow_adding_resource
|
19
22
|
|
20
23
|
- if resources.total_count > resources.length
|
21
24
|
= panel.footer do
|
@@ -0,0 +1,10 @@
|
|
1
|
+
.btn-group.add-button
|
2
|
+
%button.btn.btn-primary.dropdown-toggle{ type: 'button', data: { toggle: 'dropdown' }, aria: { haspopup: true, expanded: false }}
|
3
|
+
= t('para.shared.add')
|
4
|
+
%span.caret
|
5
|
+
|
6
|
+
%ul.dropdown-menu
|
7
|
+
- component.subclass_names.each do |subclass|
|
8
|
+
%li
|
9
|
+
= link_to component.relation_path(model.model_name.singular_route_key, action: :new, type: subclass) do
|
10
|
+
= subclass.constantize.model_name.human
|
@@ -6,7 +6,7 @@
|
|
6
6
|
- if resources.length > 0
|
7
7
|
= panel.body do
|
8
8
|
%ul.tree.root-tree{ data: { url: component.relation_path(model.model_name.route_key, action: :tree), :"max-depth" => max_depth_for(model) } }
|
9
|
-
= render partial: '
|
9
|
+
= render partial: find_partial_for(model, 'tree_item'), collection: resources.roots, as: :root, locals: { model: model}
|
10
10
|
|
11
11
|
- else
|
12
12
|
= panel.body do
|