para 0.4.0 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
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