para 0.4.0 → 0.5.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.
Files changed (133) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/images/para/admin/loading-spinner.gif +0 -0
  3. data/app/assets/javascripts/para/admin/theme_actions.coffee +0 -1
  4. data/app/assets/javascripts/para/lib/turbolinks-forms.coffee +23 -0
  5. data/app/assets/javascripts/para/lib/turbolinks-loading.coffee +25 -0
  6. data/app/assets/stylesheets/para/{overrides → admin/src}/datetimepicker.sass +1 -3
  7. data/app/assets/stylesheets/para/{overrides → admin/src}/fuelux.sass +5 -8
  8. data/app/assets/stylesheets/para/{overrides → admin/src}/jasny.bootstrap.sass +1 -2
  9. data/app/assets/stylesheets/para/admin/src/page-loading.sass +24 -0
  10. data/app/assets/stylesheets/para/{overrides → admin/src}/redactor.sass +5 -7
  11. data/app/assets/stylesheets/para/{overrides → admin/src}/selectize.sass +4 -6
  12. data/app/assets/stylesheets/para/{overrides → admin/src}/slider.sass +0 -1
  13. data/app/assets/stylesheets/para/admin/theme/_base.sass +5 -3
  14. data/app/assets/stylesheets/para/admin/theme/_breadcrumb.sass +54 -16
  15. data/app/assets/stylesheets/para/admin/theme/_buttons.sass +0 -1
  16. data/app/assets/stylesheets/para/admin/theme/_checkable.sass +5 -6
  17. data/app/assets/stylesheets/para/admin/theme/_commonds.sass +10 -16
  18. data/app/assets/stylesheets/para/admin/theme/_dropdown.sass +1 -4
  19. data/app/assets/stylesheets/para/admin/theme/_form.sass +11 -3
  20. data/app/assets/stylesheets/para/admin/theme/_list.sass +5 -6
  21. data/app/assets/stylesheets/para/admin/theme/_navigation.sass +105 -109
  22. data/app/assets/stylesheets/para/admin/theme/_navtabs.sass +35 -15
  23. data/app/assets/stylesheets/para/admin/theme/_orderable.sass +2 -5
  24. data/app/assets/stylesheets/para/admin/theme/_panel.sass +20 -50
  25. data/app/assets/stylesheets/para/admin/theme/_sorting.sass +5 -7
  26. data/app/assets/stylesheets/para/admin/theme/_tree.sass +2 -4
  27. data/app/assets/stylesheets/para/admin.sass +1 -0
  28. data/app/assets/stylesheets/para/lib/_variables.scss +12 -12
  29. data/app/assets/stylesheets/para/overrides/responsive.sass +1 -2
  30. data/app/assets/stylesheets/para/overrides/theme.sass +10 -17
  31. data/app/controllers/para/admin/base_controller.rb +16 -5
  32. data/app/controllers/para/admin/crud_resources_controller.rb +43 -2
  33. data/app/controllers/para/admin/main_controller.rb +1 -1
  34. data/app/controllers/para/admin/resources_controller.rb +1 -1
  35. data/app/controllers/para/admin/settings_component_controller.rb +1 -3
  36. data/app/controllers/para/application_controller.rb +3 -3
  37. data/app/decorators/para/component/crud_decorator.rb +6 -2
  38. data/app/decorators/para/component/singleton_resource_decorator.rb +5 -1
  39. data/app/helpers/para/admin/base_helper.rb +9 -4
  40. data/app/helpers/para/admin/components_helper.rb +7 -0
  41. data/app/helpers/para/form_helper.rb +10 -2
  42. data/app/helpers/para/tag_helper.rb +12 -0
  43. data/app/models/para/ability.rb +12 -0
  44. data/app/models/para/component/base.rb +15 -7
  45. data/app/models/para/component/crud.rb +3 -1
  46. data/app/models/para/component/singleton_resource.rb +1 -1
  47. data/app/views/para/admin/crud_resources/index.html.haml +4 -0
  48. data/app/views/para/admin/dashboard.html.haml +10 -8
  49. data/app/views/para/admin/resources/_actions.html.haml +7 -0
  50. data/app/views/para/admin/resources/_add_button.html.haml +1 -0
  51. data/app/views/para/admin/resources/_filters.html.haml +1 -1
  52. data/app/views/para/admin/resources/_imports_menu.html.haml +22 -0
  53. data/app/views/para/admin/resources/_list.html.haml +8 -5
  54. data/app/views/para/admin/resources/_subclassable_add_button.html.haml +10 -0
  55. data/app/views/para/admin/resources/_tree.html.haml +1 -1
  56. data/app/views/para/admin/resources/_tree_item.html.haml +1 -1
  57. data/app/views/para/admin/resources/new.html.haml +1 -1
  58. data/app/views/para/admin/shared/_breadcrumbs.html.haml +8 -0
  59. data/app/views/para/admin/shared/_header.html.haml +26 -24
  60. data/app/views/para/admin/shared/_navigation.html.haml +5 -3
  61. data/app/views/para/form/_tabs.html.haml +13 -0
  62. data/app/views/para/inputs/_nested_many.html.haml +2 -2
  63. data/app/views/para/inputs/_nested_many_container.html.haml +1 -3
  64. data/config/locales/en.yml +10 -0
  65. data/config/locales/fr.yml +30 -15
  66. data/db/migrate/20160304113055_add_json_equality_operator_patch_to_postgres.rb +38 -0
  67. data/lib/generators/para/component/component_generator.rb +9 -29
  68. data/lib/generators/para/component/crud/crud_generator.rb +41 -0
  69. data/lib/generators/para/component/templates/component.rb +1 -1
  70. data/lib/generators/para/component/templates/decorator.rb +3 -0
  71. data/lib/generators/para/component/templates/resources_controller.rb +4 -0
  72. data/lib/generators/para/exporter/templates/base_exporter.rb +2 -0
  73. data/lib/generators/para/exporter/templates/csv_exporter.rb +2 -0
  74. data/lib/generators/para/filters/filters_generator.rb +16 -0
  75. data/lib/generators/para/filters/templates/_filters.html.haml +9 -0
  76. data/lib/generators/para/importer/importer_generator.rb +20 -0
  77. data/lib/generators/para/importer/templates/base_importer.rb +5 -0
  78. data/lib/generators/para/install/install_generator.rb +6 -25
  79. data/lib/generators/para/nested_fields/nested_fields_generator.rb +9 -0
  80. data/lib/para/attribute_field/base.rb +28 -0
  81. data/lib/para/attribute_field/belongs_to.rb +2 -0
  82. data/lib/para/attribute_field/boolean.rb +2 -0
  83. data/lib/para/attribute_field/datetime.rb +2 -0
  84. data/lib/para/attribute_field/enum.rb +22 -0
  85. data/lib/para/attribute_field/file.rb +2 -0
  86. data/lib/para/attribute_field/has_many.rb +2 -0
  87. data/lib/para/attribute_field/image.rb +2 -0
  88. data/lib/para/attribute_field/nested_many.rb +3 -0
  89. data/lib/para/attribute_field/nested_one.rb +6 -6
  90. data/lib/para/attribute_field/password.rb +2 -0
  91. data/lib/para/attribute_field/redactor.rb +2 -0
  92. data/lib/para/attribute_field/translation.rb +2 -0
  93. data/lib/para/attribute_field.rb +19 -0
  94. data/lib/para/attribute_field_mappings.rb +15 -29
  95. data/lib/para/breadcrumbs/breadcrumb.rb +43 -0
  96. data/lib/para/breadcrumbs/controller.rb +39 -0
  97. data/lib/para/breadcrumbs/manager.rb +19 -0
  98. data/lib/para/breadcrumbs.rb +9 -0
  99. data/lib/para/component/importable.rb +25 -0
  100. data/lib/para/component/subclassable.rb +27 -0
  101. data/lib/para/component.rb +5 -3
  102. data/lib/para/components_configuration.rb +18 -2
  103. data/lib/para/config.rb +25 -1
  104. data/lib/para/exporter/base.rb +13 -0
  105. data/lib/para/exporter/csv.rb +1 -1
  106. data/lib/para/form_builder/tabs.rb +56 -0
  107. data/lib/para/form_builder.rb +2 -0
  108. data/lib/para/generators/component_helpers.rb +57 -0
  109. data/lib/para/generators.rb +1 -0
  110. data/lib/para/importer/base.rb +23 -0
  111. data/lib/para/importer.rb +10 -0
  112. data/lib/para/inputs/nested_one_input.rb +13 -3
  113. data/lib/para/markup/resources_table.rb +48 -24
  114. data/lib/para/markup/resources_tree.rb +36 -0
  115. data/lib/para/model_field_parsers/store.rb +23 -0
  116. data/lib/para/model_field_parsers.rb +1 -0
  117. data/lib/para/orderable.rb +6 -3
  118. data/lib/para/plugins/routes.rb +25 -0
  119. data/lib/para/plugins.rb +11 -0
  120. data/lib/para/routes.rb +2 -25
  121. data/lib/para/version.rb +1 -1
  122. data/lib/para.rb +4 -2
  123. data/lib/rails/routing_mapper.rb +64 -5
  124. metadata +50 -64
  125. data/app/controllers/para/admin/crud_component_controller.rb +0 -17
  126. data/app/controllers/para/admin/singleton_resource_component_controller.rb +0 -14
  127. data/app/views/para/admin/component_sections/_form.html.haml +0 -10
  128. data/app/views/para/admin/component_sections/edit.html.haml +0 -5
  129. data/app/views/para/admin/component_sections/new.html.haml +0 -5
  130. data/app/views/para/admin/components/_form.html.haml +0 -15
  131. data/app/views/para/admin/components/new.html.haml +0 -4
  132. data/app/views/para/admin/shared/_breadcrumb.html.haml +0 -3
  133. /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-light !default;
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: 50px !default;
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: $gray-light !default;
297
- $navbar-inverse-bg: #222 !default;
298
- $navbar-inverse-border: darken($navbar-inverse-bg, 10%) !default;
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: $gray-light !default;
302
- $navbar-inverse-link-hover-color: #fff !default;
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: darken($navbar-inverse-bg, 10%) !default;
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: #e8e8e8 !default;
576
- $breadcrumb-color: #99a0aa !default;
577
- $breadcrumb-active-color: #656d78 !default;
578
- $breadcrumb-separator: "/" !default;
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
- +experimental-value(width, calc(100% - 270px))
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
- +box-shadow(0px 2px darken($color-border, 10%) )
22
- +single-transition(none)
14
+ box-shadow: 0px 2px darken($color-border, 10%)
15
+ transition: none
23
16
  &:hover
24
17
  top: 1px
25
- +box-shadow(0px 1px darken($color-border, 10%) )
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
- +box-shadow(0px 0 darken($color-border, 10%))
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
- +box-shadow(none)
43
- +single-transition(all, .2s, linear)
35
+ box-shadow: none
36
+ transition: all, .2s, linear
44
37
  &:hover
45
- +box-shadow(none)
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
- +box-shadow(none)
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
- +single-transition(all, .1s, linear)
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
- +box-shadow(none)
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
- before_filter Para.config.authenticate_admin_method
7
+ before_action Para.config.authenticate_admin_method
8
8
  end
9
9
 
10
- before_filter :load_component_sections
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
- Ability.new(current_admin)
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
- before_filter do
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 component_path(@component)
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)
@@ -5,4 +5,4 @@ module Para
5
5
  end
6
6
  end
7
7
  end
8
- end
8
+ end
@@ -77,7 +77,7 @@ module Para
77
77
 
78
78
  def after_form_submit_path
79
79
  if params[:_save_and_edit]
80
- { action: 'edit', id: resource.to_param }
80
+ { action: 'edit', id: resource.id }
81
81
  elsif params[:_save_and_add_another]
82
82
  { action: 'new' }
83
83
  else
@@ -1,8 +1,6 @@
1
1
  module Para
2
2
  module Admin
3
- class SettingsComponentController < Para::Admin::BaseController
4
- load_and_authorize_component
5
-
3
+ class SettingsComponentController < Para::Admin::ComponentController
6
4
  def show
7
5
  @settings = SettingsRails::Form.new
8
6
  end
@@ -1,7 +1,7 @@
1
1
  module Para
2
2
  class ApplicationController < ActionController::Base
3
- def current_ability
4
- @current_ability ||= Ability.new(current_admin_user)
5
- end
3
+ include Para::Breadcrumbs::Controller
4
+
5
+ add_breadcrumb :home, :admin
6
6
  end
7
7
  end
@@ -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
- :crud_resource
29
+ :resource
26
30
  else
27
- :crud_resources
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
- polymorphic_path([:admin, self, :singleton_resource].compact, options)
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/admin/resources/#{ partial }"
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
- resource.try(:title) || resource.try(:name) ||
28
- t('para.form.shared.edit.title', model: resource.class.model_name.human)
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
@@ -1,4 +1,11 @@
1
1
  module Para
2
2
  module Admin::ComponentsHelper
3
+ def ordered_components
4
+ @component_sections.each_with_object([]) do |section, components|
5
+ section.components.each do |component|
6
+ components << component
7
+ end
8
+ end.sort_by(&:updated_at)
9
+ end
3
10
  end
4
11
  end
@@ -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, &block)
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
@@ -0,0 +1,12 @@
1
+ module Para
2
+ class Ability
3
+ include CanCan::Ability
4
+
5
+ def initialize(user)
6
+ if user.is_a?(AdminUser)
7
+ can :access, :admin
8
+ can :manage, :all
9
+ end
10
+ end
11
+ end
12
+ end
@@ -10,12 +10,11 @@ module Para
10
10
  Para::Component.registered_components[name] = component
11
11
  end
12
12
 
13
- extend FriendlyId
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
- belongs_to :component_section, class_name: 'Para::ComponentSection'
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
@@ -0,0 +1,4 @@
1
+ .page-title
2
+ %h1= @component.name
3
+
4
+ = listing_for(@resources)
@@ -1,10 +1,12 @@
1
1
  .page-title
2
- %h1
3
- Dashboard
2
+ %h1= t('para.dashboard.title')
3
+
4
4
  .page-content-wrap
5
- .row
6
- .col-md-12
7
- .panel.panel-default
8
- .panel-body
9
- %p Override the dashboard view by Creating a view at :
10
- %pre app/views/admin/dashboard.html.(haml|erb)
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, autofocus: true, label: t('para.shared.search'), class: 'form-control'
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
- = icon_link_to t('para.shared.add'), component.relation_path(model.model_name.singular_route_key, action: :new), icon: 'plus', class: 'btn btn-primary' if allow_adding_resource
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
- = filtered?(attributes) ? t('para.list.no_results') : t('para.list.empty')
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: 'para/admin/resources/tree_item', collection: resources.roots, as: :root
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