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
@@ -5,9 +5,19 @@ module Para
5
5
  input_html_options[:class] << "nested-one"
6
6
 
7
7
  parent_model = object.class
8
- model = parent_model.reflect_on_association(attribute_name).klass
9
- resource = object.send(:"#{ attribute_name }") ||
10
- object.send(:"#{ attribute_name }=", model.new)
8
+ association = object.association(attribute_name)
9
+ relation = parent_model.reflect_on_association(attribute_name)
10
+ model = relation.klass
11
+
12
+ unless (resource = object.send(:"#{ attribute_name }"))
13
+ # Build association without trying to save the new record
14
+ resource = case association
15
+ when ActiveRecord::Associations::HasOneAssociation
16
+ association.replace(model.new, false)
17
+ else
18
+ association.replace(model.new)
19
+ end
20
+ end
11
21
 
12
22
  template.render(
13
23
  partial: 'para/inputs/nested_one',
@@ -11,9 +11,7 @@ module Para
11
11
  @orderable = model.orderable?
12
12
  end
13
13
 
14
- if !options.key?(:actions) || options.delete(:actions)
15
- @actions = true
16
- end
14
+ @actions = options.fetch(:actions, true)
17
15
 
18
16
  merge_class!(options, 'table')
19
17
  merge_class!(options, 'para-component-relation-table')
@@ -72,10 +70,23 @@ module Para
72
70
  cells.join("\n").html_safe
73
71
  end
74
72
 
75
- def header_for(field_name, sort: field_name)
76
- label = model.human_attribute_name(field_name)
73
+ def header_for(field_name = nil, options = {}, &block)
74
+ if Hash === field_name
75
+ options = field_name
76
+ field_name = nil
77
+ end
78
+
79
+ sort = options.delete(:sort) || field_name
77
80
 
78
- content_tag(:th) do
81
+ label = if Symbol === field_name
82
+ model.human_attribute_name(field_name)
83
+ elsif block
84
+ capture { block.call }
85
+ else
86
+ field_name
87
+ end
88
+
89
+ content_tag(:th, options) do
79
90
  if sort != field_name
80
91
  view.sort_link(search, *sort, label, hide_indicator: true)
81
92
  elsif searchable?(field_name)
@@ -94,10 +105,12 @@ module Para
94
105
  # - a single value : The value to display in the cell directly
95
106
  # which will be processed to be shorter than 100 chars
96
107
  #
97
- def data_for(*args)
108
+ def data_for(*args, &block)
98
109
  value = if args.length >= 2
99
110
  resource, field_name, type = args
100
111
  view.field_value_for(resource, field_name, type).to_s
112
+ elsif block
113
+ capture { block.call }
101
114
  else
102
115
  view.excerpt_value_for(args.first)
103
116
  end
@@ -119,9 +132,11 @@ module Para
119
132
  def actions_cell(resource)
120
133
  content_tag(:td) do
121
134
  content_tag(:div, class: 'pull-right btn-group') do
122
- edit_button(resource) +
123
- clone_button(resource) +
124
- delete_button(resource)
135
+ edit = edit_button(resource) if action?(:edit)
136
+ clone = clone_button(resource) if action?(:clone)
137
+ delete = delete_button(resource) if action?(:delete)
138
+
139
+ edit + clone + delete
125
140
  end
126
141
  end
127
142
  end
@@ -129,37 +144,42 @@ module Para
129
144
  def clone_button(resource)
130
145
  return unless resource.class.cloneable?
131
146
 
132
- view.link_to(
133
- component.relation_path(
134
- resource, action: :clone, return_to: view.request.fullpath
135
- ),
147
+ path = component.relation_path(
148
+ resource, action: :clone, return_to: view.request.fullpath
149
+ )
150
+
151
+ options = {
136
152
  method: :post,
137
153
  class: 'btn btn-info'
138
- ) do
154
+ }
155
+
156
+ view.link_to(path, options) do
139
157
  content_tag(:i, '', class: 'fa fa-refresh')
140
158
  end
141
159
  end
142
160
 
143
161
  def edit_button(resource)
144
- view.link_to(
145
- component.relation_path(
146
- resource, action: :edit, return_to: view.request.fullpath
147
- ),
148
- class: 'btn btn-primary'
149
- ) do
162
+ path = component.relation_path(
163
+ resource, action: :edit, return_to: view.request.fullpath
164
+ )
165
+
166
+ view.link_to(path, class: 'btn btn-primary') do
150
167
  content_tag(:i, '', class: 'fa fa-pencil')
151
168
  end
152
169
  end
153
170
 
154
171
  def delete_button(resource)
155
- view.link_to(
156
- component.relation_path(resource),
172
+ path = component.relation_path(resource)
173
+
174
+ options = {
157
175
  method: :delete,
158
176
  data: {
159
177
  confirm: I18n.t('para.list.delete_confirmation')
160
178
  },
161
179
  class: 'btn btn-danger'
162
- ) do
180
+ }
181
+
182
+ view.link_to(path, options) do
163
183
  content_tag(:i, '', class: 'fa fa-trash')
164
184
  end
165
185
  end
@@ -173,6 +193,10 @@ module Para
173
193
  def searchable?(field_name)
174
194
  model.columns_hash.keys.include?(field_name.to_s)
175
195
  end
196
+
197
+ def action?(type)
198
+ actions == true || actions.include?(type)
199
+ end
176
200
  end
177
201
  end
178
202
  end
@@ -0,0 +1,36 @@
1
+ module Para
2
+ module Markup
3
+ class ResourceTree < Para::Markup::Component
4
+ def tree_list(resources, options = {}, &block)
5
+ options[:class] ||= ''
6
+ options[:class] << ' tree-list'
7
+
8
+ content_tag(:ul, options) do
9
+ resources.each do |resource|
10
+ block.call(resource)
11
+ end
12
+ end
13
+ end
14
+
15
+ def tree_node(resource: nil, label: nil, children: [], **options, &block)
16
+ options[:class] ||= ''
17
+ options[:class] << ' node'
18
+
19
+ content_tag(:li, options) do
20
+ node_row(resource, label) +
21
+ node_children(children, &block)
22
+ end
23
+ end
24
+
25
+ def node_row(resource, label)
26
+ content_tag(:div, class: 'node-row') do
27
+ label
28
+ end
29
+ end
30
+
31
+ def node_children(children, &block)
32
+ tree_list(children, &block) if children.length > 0
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,23 @@
1
+ module Para
2
+ module ModelFieldParsers
3
+ class Store < Para::ModelFieldParsers::Base
4
+ register :json, self
5
+
6
+ def parse!
7
+ model.stored_attributes.each do |store_key, field_names|
8
+ fields_hash.delete(store_key)
9
+
10
+ field_names.each do |field_name|
11
+ fields_hash[field_name] = AttributeField::Base.new(
12
+ model, name: field_name, type: :string
13
+ )
14
+ end
15
+ end
16
+ end
17
+
18
+ def applicable?
19
+ !model.stored_attributes.empty?
20
+ end
21
+ end
22
+ end
23
+ end
@@ -20,3 +20,4 @@ require 'para/model_field_parsers/orderable'
20
20
  require 'para/model_field_parsers/relations'
21
21
  require 'para/model_field_parsers/redactor'
22
22
  require 'para/model_field_parsers/globalize'
23
+ require 'para/model_field_parsers/store'
@@ -4,11 +4,14 @@ module Para
4
4
 
5
5
  included do
6
6
  scope :ordered, -> { order('position ASC') }
7
- before_create :orederable_assign_position
7
+ before_create :orderable_assign_position
8
8
  end
9
9
 
10
- def orederable_assign_position
11
- last_resource = self.class.order('position DESC')
10
+ def orderable_assign_position
11
+ return if attribute_present?(:position)
12
+
13
+ last_resource = self.class.unscoped
14
+ .order('position DESC')
12
15
  .where.not(position: nil)
13
16
  .select(:position)
14
17
  .first
@@ -0,0 +1,25 @@
1
+ module Para
2
+ module Plugins
3
+ class Routes
4
+ attr_reader :router
5
+
6
+ def initialize(router)
7
+ @router = router
8
+ end
9
+
10
+ def plugin(identifier, &block)
11
+ # Store router reference in closure to allow accessing it from
12
+ # inside the below block
13
+ router = self.router
14
+
15
+ router.instance_eval do
16
+ namespace :admin do
17
+ scope module: :acl do
18
+ router.instance_eval(&block)
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,11 @@
1
+ module Para
2
+ module Plugins
3
+ extend ActiveSupport::Autoload
4
+
5
+ autoload :Routes
6
+
7
+ def self.module_name_for(identifier)
8
+ ['Para', identifier.to_s.camelize].join('::')
9
+ end
10
+ end
11
+ end
data/lib/para/routes.rb CHANGED
@@ -7,37 +7,14 @@ module Para
7
7
  end
8
8
 
9
9
  def draw(mount_location = '/', &block)
10
- routes = self
11
-
12
10
  router.instance_eval do
13
11
  scope mount_location do
14
12
  scope module: :para do
15
13
  namespace :admin do
16
14
  get '/' => 'main#index'
17
15
 
18
- component :crud do
19
- scope ':model' do
20
- resources :crud_resources, path: '/' do
21
- collection do
22
- patch :order
23
- patch :tree
24
- get :export
25
- end
26
-
27
- member do
28
- post :clone
29
- end
30
- end
31
- end
32
- end
33
-
34
- component :singleton_resource, path: 'resource-form' do
35
- resource :singleton_resource, path: 'resource', only: [:create, :update]
36
- end
37
-
38
- component :settings do
39
- resource :settings_form, controller: 'settings_form', only: [:update]
40
- end
16
+ crud_component :crud, scope: ':model'
17
+ singleton_resource_component :singleton, scope: ':model'
41
18
  end
42
19
  end
43
20
 
data/lib/para/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Para
2
- VERSION = "0.4.0"
2
+ VERSION = "0.5.0"
3
3
  end
data/lib/para.rb CHANGED
@@ -3,7 +3,6 @@ require 'paperclip'
3
3
  require 'simple_form'
4
4
  require 'simple_form_extension'
5
5
  require 'active_decorator'
6
- require 'friendly_id'
7
6
  require 'haml-rails'
8
7
  require 'truncate_html'
9
8
  require 'cocoon'
@@ -13,7 +12,6 @@ require 'request_store'
13
12
  require 'sass-rails'
14
13
  require 'selectize-rails'
15
14
  require 'bootstrap-sass'
16
- require 'compass-rails'
17
15
  require 'font-awesome-rails'
18
16
 
19
17
  require 'rails/routing_mapper'
@@ -23,6 +21,7 @@ require 'para/ext'
23
21
  require 'para/errors'
24
22
  require 'para/config'
25
23
  require 'para/model_field_parsers'
24
+ require 'para/attribute_field'
26
25
  require 'para/attribute_field_mappings'
27
26
  require 'para/inputs'
28
27
  require 'para/cloneable'
@@ -32,6 +31,7 @@ require 'para/markup'
32
31
  require 'para/engine'
33
32
  require 'para/components_configuration'
34
33
  require 'para/exporter'
34
+ require 'para/importer'
35
35
 
36
36
  module Para
37
37
  extend ActiveSupport::Autoload
@@ -41,6 +41,8 @@ module Para
41
41
  autoload :Component
42
42
  autoload :Generators
43
43
  autoload :Routes
44
+ autoload :Plugins
45
+ autoload :Breadcrumbs
44
46
  end
45
47
 
46
48
  def self.config(&block)
@@ -3,6 +3,10 @@ module ActionDispatch
3
3
  class Mapper
4
4
  def para_at(mount_location, &block)
5
5
  Para::Routes.new(self).draw(mount_location, &block)
6
+
7
+ Para::Config.plugins.each do |plugin|
8
+ draw_plugin_routes(plugin)
9
+ end
6
10
  end
7
11
 
8
12
  def para_plugin(plugin_name)
@@ -11,16 +15,71 @@ module ActionDispatch
11
15
  end
12
16
 
13
17
  def component(component_name, options = {}, &block)
18
+ as, controller, endpoint = component_informations_from(
19
+ component_name, options
20
+ )
21
+
22
+ get endpoint => "#{ controller }#show", as: as
23
+ scope(endpoint, as: component_name, &block) if block
24
+ end
25
+
26
+ def crud_component(component_name, options = {}, &block)
27
+ as, controller, endpoint = component_informations_from(
28
+ component_name, options
29
+ )
30
+
31
+ controller = [component_name.to_s.singularize, 'resources'].join('_')
32
+
33
+ scope endpoint, as: as do
34
+ resources :resources, controller: controller do
35
+ scope options[:scope] do
36
+ collection do
37
+ patch :order
38
+ patch :tree
39
+ get :export
40
+ post :import
41
+ end
42
+
43
+ member do
44
+ post :clone
45
+ end
46
+
47
+ instance_eval(&block) if block
48
+ end
49
+ end
50
+ end
51
+ end
52
+
53
+ def singleton_resource_component(component_name, options = {}, &block)
54
+ as, _, endpoint = component_informations_from(
55
+ component_name, options
56
+ )
57
+
58
+ controller = [component_name, 'resources'].join('_')
59
+
60
+ scope endpoint, as: as do
61
+ resource :resource, controller: controller, only: [:show, :create, :update]
62
+ end
63
+ end
64
+
65
+ private
66
+
67
+ def draw_plugin_routes(identifier)
68
+ routes = [
69
+ Para::Plugins.module_name_for(identifier),
70
+ 'Routes'
71
+ ].join('::').constantize
72
+
73
+ routes.new(self).draw
74
+ end
75
+
76
+ def component_informations_from(component_name, options)
14
77
  path = options.fetch(:path, component_name.to_s)
15
78
  as = options.fetch(:as, component_name)
16
79
  controller = options.fetch(:controller, "#{ component_name }_component")
17
-
18
80
  endpoint = "#{ path }/:component_id"
19
81
 
20
- get endpoint => "#{ controller }#show", as: as
21
- delete endpoint => "#{ controller }#destroy", as: "destroy_#{as}"
22
-
23
- scope(endpoint, as: component_name, &block) if block
82
+ [as, controller, endpoint]
24
83
  end
25
84
  end
26
85
  end