para 0.7.1 → 0.7.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (94) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/javascripts/para/admin/tabs.coffee +20 -1
  3. data/app/assets/javascripts/para/admin.coffee +1 -0
  4. data/app/assets/javascripts/para/inputs/multi-select-input.coffee +5 -3
  5. data/app/assets/javascripts/para/inputs/nested_many.coffee +35 -1
  6. data/app/assets/javascripts/para/lib/remote-file-forms.coffee +6 -7
  7. data/app/assets/javascripts/para/lib/turbolinks-loading.coffee +1 -1
  8. data/app/assets/stylesheets/para/admin/main.sass +1 -0
  9. data/app/assets/stylesheets/para/admin/src/_affix.sass +4 -0
  10. data/app/assets/stylesheets/para/admin/src/_base.sass +4 -1
  11. data/app/assets/stylesheets/para/admin/src/_breadcrumb.sass +12 -2
  12. data/app/assets/stylesheets/para/admin/src/_form.sass +22 -3
  13. data/app/assets/stylesheets/para/admin/src/_navtabs.sass +23 -6
  14. data/app/assets/stylesheets/para/admin/src/_nested-many.sass +5 -0
  15. data/app/assets/stylesheets/para/admin/src/_nested_one.sass +6 -5
  16. data/app/controllers/para/admin/base_controller.rb +5 -0
  17. data/app/controllers/para/admin/crud_resources_controller.rb +1 -1
  18. data/app/controllers/para/admin/exports_controller.rb +2 -1
  19. data/app/controllers/para/admin/nested_forms_controller.rb +13 -0
  20. data/app/controllers/para/admin/resources_controller.rb +14 -3
  21. data/app/controllers/para/admin/search_controller.rb +7 -5
  22. data/app/decorators/para/component/base_decorator.rb +7 -2
  23. data/app/decorators/para/component/crud_decorator.rb +4 -0
  24. data/app/decorators/para/component/form_decorator.rb +6 -0
  25. data/app/exporters/call_for_projects_votes_exporter.rb +79 -0
  26. data/app/helpers/para/admin/base_helper.rb +2 -3
  27. data/app/helpers/para/admin/history_helper.rb +16 -0
  28. data/app/helpers/para/form_helper.rb +9 -1
  29. data/app/helpers/para/model_helper.rb +0 -2
  30. data/app/models/para/cache/item.rb +4 -0
  31. data/app/models/para/component/base.rb +4 -0
  32. data/app/models/para/component/crud.rb +1 -0
  33. data/app/models/para/component/form.rb +2 -0
  34. data/app/models/para/library/file.rb +40 -12
  35. data/app/models/para/page/section.rb +13 -1
  36. data/app/views/admin/para/exporter/bases/_completed.html.haml +1 -1
  37. data/app/views/layouts/para/admin.html.haml +5 -5
  38. data/app/views/para/admin/form_resources/show.html.haml +6 -2
  39. data/app/views/para/admin/nested_forms/show.html.haml +9 -0
  40. data/app/views/para/admin/resources/_exports_menu.html.haml +2 -2
  41. data/app/views/para/admin/resources/_list.html.haml +26 -21
  42. data/app/views/para/admin/resources/_remote_nested_form.html.haml +1 -0
  43. data/app/views/para/admin/resources/edit.html.haml +7 -2
  44. data/app/views/para/admin/resources/history/_index.html.haml +3 -0
  45. data/app/views/para/admin/shared/_header.html.haml +3 -3
  46. data/app/views/para/admin/shared/_navigation.html.haml +1 -1
  47. data/app/views/para/form/_tabs.html.haml +12 -9
  48. data/app/views/para/inputs/_multi_select.html.haml +6 -2
  49. data/app/views/para/inputs/_nested_many.html.haml +4 -4
  50. data/app/views/para/inputs/_nested_one.html.haml +12 -1
  51. data/app/views/para/inputs/multi_select/_no_items.html.haml +8 -4
  52. data/app/views/para/inputs/nested_many/_add.html.haml +2 -2
  53. data/app/views/para/inputs/nested_many/_add_with_subclasses.html.haml +3 -3
  54. data/app/views/para/inputs/nested_many/_container.html.haml +10 -7
  55. data/lib/generators/para/exporter/templates/csv_exporter.rb +24 -0
  56. data/lib/generators/para/exporter/templates/xls_exporter.rb +24 -0
  57. data/lib/para/attribute_field/belongs_to.rb +4 -1
  58. data/lib/para/attribute_field/nested_field.rb +4 -2
  59. data/lib/para/attribute_field/nested_many.rb +1 -1
  60. data/lib/para/attribute_field/nested_one.rb +1 -1
  61. data/lib/para/cache/database_store.rb +14 -1
  62. data/lib/para/cloneable.rb +44 -2
  63. data/lib/para/component/history.rb +15 -0
  64. data/lib/para/component.rb +1 -0
  65. data/lib/para/components_configuration.rb +8 -3
  66. data/lib/para/engine.rb +8 -0
  67. data/lib/para/exporter/base.rb +49 -1
  68. data/lib/para/ext/request_iframe_xhr.rb +17 -0
  69. data/lib/para/ext.rb +1 -0
  70. data/lib/para/form_builder/attributes_mappings_tracker.rb +15 -3
  71. data/lib/para/form_builder/containers.rb +6 -1
  72. data/lib/para/form_builder/nested_form.rb +7 -4
  73. data/lib/para/form_builder/tabs.rb +49 -8
  74. data/lib/para/iframe_transport/middleware.rb +58 -0
  75. data/lib/para/iframe_transport.rb +7 -0
  76. data/lib/para/importer/base.rb +1 -0
  77. data/lib/para/inputs/multi_select_input.rb +27 -8
  78. data/lib/para/inputs/nested_base_input.rb +26 -0
  79. data/lib/para/inputs/nested_many_input.rb +43 -18
  80. data/lib/para/inputs/nested_one_input.rb +18 -4
  81. data/lib/para/inputs.rb +1 -0
  82. data/lib/para/log_config.rb +14 -0
  83. data/lib/para/markup/resources_table.rb +2 -2
  84. data/lib/para/model_field_parsers/relations.rb +12 -1
  85. data/lib/para/page/model.rb +2 -1
  86. data/lib/para/postgres_extensions_checker.rb +15 -11
  87. data/lib/para/routes.rb +3 -3
  88. data/lib/para/search/distinct.rb +1 -1
  89. data/lib/para/version.rb +1 -1
  90. data/lib/para.rb +2 -0
  91. data/lib/rails/routing_mapper.rb +19 -27
  92. data/vendor/assets/javascripts/jquery.iframe-transport.js +260 -0
  93. data/vendor/assets/javascripts/jquery.remote-modal-form.coffee +80 -2
  94. metadata +23 -9
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: ea023e2c7951df293b131af9c362b630a80acedb
4
- data.tar.gz: e4a5edf55b4d9a1f98a7deac738a28169c227dfa
3
+ metadata.gz: 0f2e4cc7267a3d024fb9690cf426b0064bdb5da8
4
+ data.tar.gz: eea345a2e6a7b354420b6fb27d8bcef5bda8d5b9
5
5
  SHA512:
6
- metadata.gz: ac5856d930a5a18d535b5a5636809598ab4676a2f349523265edf1a87bdfdfb7efc5f94ad720315468d56c55b46895f5184ace70f4a95b719747437f1758a37d
7
- data.tar.gz: e001063051553067ba717acb4900368bfd054b97a46e7ea8bbdbdbc0e70369e22d8dbfe41cd53437bbfd545434b968688c61d494847ea234ae8f45f8c383f016
6
+ metadata.gz: 75f8375384ace99363c1d518f82df23c7261cc96d86b925d743dcf6052b8d9d79a767eb2c2d21ebbe549798cf22caa429ca7cd88d1bb32acd96f497bf9afc9b0
7
+ data.tar.gz: ea104d47ae45e079a54d0af2c2af8212dc2d5148722ee432f54764594d09cfff86988ec4ff2b4bdb15f96938c668fbb817e6c19f6774519c3ddcf5f99c96f0a5
@@ -10,13 +10,17 @@ class Para.Tabs extends Vertebra.View
10
10
  @$anchorInput = options.$anchorInput
11
11
  @showActiveTab()
12
12
  @refreshTabsErrors()
13
+ @initializeAffix()
13
14
 
14
15
  showActiveTab: ->
15
16
  if (hash = (location.hash or @$anchorInput?.val()))
16
17
  @findTab(hash).tab('show')
17
18
 
18
19
  onTabShown: (e) =>
19
- tabHash = $(e.target).attr('href')
20
+ $tab = $(e.target)
21
+ return unless $tab.closest('[data-form-tabs]').is('[data-top-level-tabs]')
22
+
23
+ tabHash = $tab.attr('href')
20
24
  history.pushState(null, null, tabHash)
21
25
  @updateAnchorInput()
22
26
 
@@ -31,6 +35,21 @@ class Para.Tabs extends Vertebra.View
31
35
  $panel = @$($tab.attr('href'))
32
36
  $tab.addClass('has-error') if $panel.find('.has-error').length
33
37
 
38
+ #
39
+ initializeAffix: ->
40
+ return unless (@$nav = @$('[data-tabs-nav-affix]')).length
41
+
42
+ headerHeight = $('[data-header]').outerHeight()
43
+ offsetTop = @$nav.offset().top - headerHeight
44
+ sidebarWidth = $('[data-admin-left-sidebar]').outerWidth()
45
+
46
+ @$nav.affix(offset: { top: offsetTop })
47
+ .css(top: headerHeight, left: sidebarWidth)
48
+
49
+ # Fix parent wrapper height to maintain the same scroll position when the
50
+ # nav tabs are fixed to top
51
+ @$nav.closest('[data-nav-tabs-wrapper]').height(@$nav.outerHeight())
52
+
34
53
  onFormInputUpdate: (e) ->
35
54
  $tab = @findTab($(e.currentTarget).attr('id'))
36
55
  @refreshTabErrors($tab)
@@ -9,6 +9,7 @@
9
9
  #= require html5-sortable
10
10
  #= require cocoon
11
11
  #= require jquery.remote-modal-form
12
+ #= require jquery.iframe-transport
12
13
  #= require_self
13
14
  #= require_tree ./lib
14
15
  #= require_tree ./inputs
@@ -12,6 +12,7 @@ class Para.MultiSelectInput extends Vertebra.View
12
12
 
13
13
  @searchURL = @$el.data('search-url')
14
14
  @orderable = @$el.is('[data-orderable]')
15
+ @searchParam = @$searchField.attr('name')
15
16
 
16
17
  @noSelectedItemsTemplate = @$('[data-no-selected-items]').data('no-selected-items')
17
18
  @noAvailableItemsTemplate = @$('[data-no-available-items]').data('no-available-items')
@@ -31,13 +32,14 @@ class Para.MultiSelectInput extends Vertebra.View
31
32
 
32
33
  searchFor: (terms) ->
33
34
  terms = trim(terms)
34
- return if terms is @terms
35
+ return if terms is @terms or (!terms and !@terms)
35
36
  @terms = terms
36
37
  @setLoading(true)
37
38
  @_currentSearchXHR?.abort()
38
- @_currentSearchXHR = $.get(@searchURL, search: terms).done(@onSearchReturn)
39
+ data = @$('[data-search-field-input]').serialize()
40
+ @_currentSearchXHR = $.get(@searchURL, data).done(@onSearchReturn)
39
41
 
40
- onSearchReturn: (results, b, c) =>
42
+ onSearchReturn: (results) =>
41
43
  @_currentSearchXHR = null
42
44
  @setLoading(false)
43
45
  @$('[data-available-items] tbody').html(results)
@@ -48,11 +48,45 @@ class Para.NestedManyField
48
48
 
49
49
  collapseShown: (e) ->
50
50
  $target = $(e.target)
51
+
52
+ if $target.is("[data-rendered]") or $target.data("rendered")
53
+ @initializeCollapseContent($target)
54
+ else
55
+ @loadCollapseContent($target)
56
+ @scrollToTarget($target)
57
+
58
+ initializeCollapseContent: ($target) ->
59
+ @scrollToTarget($target)
60
+ @focusFirstField($target)
61
+
62
+ scrollToTarget: ($target) ->
51
63
  $field = @$field.find("[data-toggle='collapse'][href='##{ $target.attr('id') }']")
52
- scrollOffset = -($('[data-header]').outerHeight() + 20)
64
+ scrollOffset = -($('[data-header]').outerHeight() + 30)
65
+
66
+ if ($affixNavTabs = $("[data-tabs-nav-affix]:eq(0)")).length
67
+ scrollOffset -= $affixNavTabs.outerHeight()
68
+
53
69
  $.scrollTo($field, 200, offset: scrollOffset)
70
+
71
+ focusFirstField: ($target) ->
54
72
  $target.find('input, textarea, select').eq('0').focus()
55
73
 
74
+ loadCollapseContent: ($target) ->
75
+ targetUrl = $target.data("render-path")
76
+ return unless targetUrl
77
+
78
+ data = {
79
+ "id": $target.data("id")
80
+ "object_name": $target.data("object-name")
81
+ "model_name": $target.data("model-name")
82
+ }
83
+
84
+ $.get(targetUrl, data).then (resp) =>
85
+ $content = $(resp)
86
+ $target.find("[data-nested-form-container]:eq(0)").html($content)
87
+ $content.simpleForm()
88
+ @focusFirstField($target)
89
+ $target.data("rendered", true)
56
90
 
57
91
  $.simpleForm.onDomReady ($document) ->
58
92
  $document.find('.nested-many-field').each (i, el) -> new Para.NestedManyField($(el))
@@ -6,9 +6,10 @@
6
6
  # of original rails' remote form requests, to allow existing handling code
7
7
  # to run without any modification.
8
8
  #
9
- class RemoteFileForm
10
- constructor: (options = {}) ->
11
- @$el = $(options.el)
9
+ class @RemoteFileForm extends Vertebra.View
10
+ @supported = FormData isnt undefined
11
+
12
+ initialize: (options = {}) ->
12
13
  @submitForm() if $.rails.fire(@$el, 'ajax:before')
13
14
 
14
15
  submitForm: ->
@@ -28,7 +29,7 @@ class RemoteFileForm
28
29
  success: @success
29
30
  complete: @complete
30
31
  error: @error
31
- crossDomain: $.rails.isCrossDomain(url)
32
+ crossDomain: $.rails.isCrossDomain?(url)
32
33
 
33
34
  buildXHR: =>
34
35
  xhr = $.ajaxSettings.xhr()
@@ -50,10 +51,8 @@ class RemoteFileForm
50
51
  error: (xhr, status, error) =>
51
52
  @$el.trigger('ajax:error', [xhr, status, error])
52
53
 
53
- # TODO : Implement an upload progress bar for heavy files
54
- #
55
54
  progress: (e) =>
56
- # console.log e.loaded, '/', e.total if e.lengthComputable
55
+ @trigger('progress', e)
57
56
 
58
57
  $(document).on 'ajax:aborted:file', (e) ->
59
58
  new RemoteFileForm(el: e.target)
@@ -22,4 +22,4 @@ $(document).on('page:fetch', Para.loadingManager.start)
22
22
 
23
23
  $(document).on 'page:change turbolinks:load', ->
24
24
  Para.loadingManager.stop()
25
- $('body').on('submit', '[data-para-form]', Para.loadingManager.start)
25
+ $('body').on('submit', '[data-para-form]:not([data-remote])', Para.loadingManager.start)
@@ -14,6 +14,7 @@
14
14
  @import "src/table"
15
15
  @import "src/list"
16
16
  @import "src/panel"
17
+ @import "src/affix"
17
18
  @import "src/alert"
18
19
  @import "src/dropdown"
19
20
  @import "src/multi-select"
@@ -0,0 +1,4 @@
1
+ @media (max-width: $screen-md-min)
2
+ .affix
3
+ &.affix-no-mobile
4
+ position: static
@@ -40,9 +40,12 @@ body
40
40
  float: left
41
41
  line-height: 34px
42
42
 
43
+ .admin-main-page-content
44
+ position: relative
45
+
43
46
  .page-content-wrap
44
- background-color: #fff
45
47
  margin: 25px 10px 25px 10px
48
+ background-color: #fff
46
49
  +border-radius($border-radius-small)
47
50
  +material-box-shadow-soft
48
51
  padding: 25px
@@ -7,11 +7,21 @@
7
7
  //## Just a override of bootstrap
8
8
 
9
9
  .breadcrumb
10
+ float: left
11
+ width: calc(100% - 90px)
12
+ max-height: 60px
13
+ margin: 0
14
+
10
15
  border: none
11
16
  +border-radius(0)
12
- margin: 0
13
- float: left
17
+
14
18
  li
19
+ max-width: 30%
20
+ height: 60px
21
+ overflow: hidden
22
+ text-overflow: ellipsis
23
+ white-space: nowrap
24
+
15
25
  a
16
26
  color: $breadcrumb-color
17
27
  font-size: 1em
@@ -57,20 +57,24 @@ legend
57
57
  //
58
58
  //##
59
59
 
60
+ .form-control
61
+ font-size: 14px
62
+
60
63
  .form-inputs,
61
64
  .nested-one-field,
62
65
  .tab-pane
63
66
  +clearfix
64
67
  .form-group:last-of-type,
65
68
  .form-group:only-child,
66
- .nested-one-field:last-of-type
69
+ .nested-one-field:last-of-type
67
70
  margin-bottom: 0
68
71
 
69
72
  .nested-one-field
70
73
  margin-bottom: $form-group-margin-bottom
71
74
 
72
- .form-control
73
- font-size: 14px
75
+ .nested-input-title
76
+ &.has-error
77
+ color: $brand-danger
74
78
 
75
79
 
76
80
  //== Inputs outline
@@ -165,6 +169,21 @@ legend
165
169
  &:active:focus
166
170
  +box-shadow(none)
167
171
 
172
+ //== Color picker
173
+ //
174
+ //##
175
+
176
+ .input-group
177
+ &.color
178
+ max-width: 300px
179
+ .input-group-addon
180
+ padding: 0
181
+ padding-left: 5px
182
+ i
183
+ border: 1px solid #ccc
184
+ width: 25px
185
+ height: 25px
186
+
168
187
  //== Search form filter
169
188
  //
170
189
  //##
@@ -7,22 +7,39 @@
7
7
  //##
8
8
 
9
9
  //** Add negative margin top if the nav tab is the frst content of the page
10
- .page-content-wrap
11
- .nav-tabs
10
+ .page-content-wrap
11
+ .nav-tabs-wrapper
12
12
  margin-top: -25px
13
+
14
+ .nav-tabs
13
15
  +border-radius($border-radius-small)
14
- .form-inputs
15
- .nav-tabs
16
+
17
+ &.affix
18
+ margin-top: 0
19
+ width: 100%
20
+ z-index: $zindex-navbar-fixed - 1
21
+ +material-box-shadow-soft(3)
22
+
23
+ .form-inputs
24
+ .nav-tabs-wrapper
16
25
  margin-top: 0
26
+
27
+ .nav-tabs
17
28
  +border-radius(0)
18
29
 
30
+ .panel-body
31
+ .nav-tabs-wrapper
32
+ margin-top: -25px
33
+
19
34
  //** Override bootstrap nav tabs
20
- .nav-tabs
21
- background-color: $gray-lighter
35
+ .nav-tabs-wrapper
22
36
  margin-right: -25px
23
37
  margin-left: -25px
24
38
  margin-bottom: 25px
25
39
 
40
+ .nav-tabs
41
+ background-color: $gray-lighter
42
+
26
43
  > li > a
27
44
  color: $text-color
28
45
  border: none
@@ -35,6 +35,11 @@
35
35
  display: block
36
36
  width: 100%
37
37
  padding: 30px
38
+ &:hover,
39
+ &:focus
40
+ background-color: #FAFAFA !important
41
+ border-color: #FAFAFA !important
42
+ +material-box-shadow-soft(2)
38
43
 
39
44
  &.open
40
45
  > .dropdown-menu
@@ -8,14 +8,15 @@
8
8
 
9
9
  .form-group.nested_one
10
10
  label.control-label.nested_one
11
- font-weight: 600
12
- font-size: 21px
13
- color: $blue-darker
14
- text-transform: inherit
11
+ width: 100%
15
12
  margin-top: 15px
16
13
  margin-bottom: 15px
14
+ padding-bottom: 10px
15
+ border-bottom: 1px solid $gray-light
16
+ font-weight: 600
17
+ font-size: 18px
17
18
 
18
19
  .tab-pane
19
20
  > .form-group.nested_one
20
21
  label.control-label.nested_one
21
- margin-top: 0
22
+ margin-top: 0
@@ -12,6 +12,7 @@ module Para
12
12
  layout 'para/admin'
13
13
 
14
14
  helper_method :current_admin
15
+ helper_method :admin_body_class
15
16
 
16
17
  def current_admin
17
18
  @current_admin ||= if Para.config.current_admin_method
@@ -27,6 +28,10 @@ module Para
27
28
 
28
29
  private
29
30
 
31
+ def admin_body_class
32
+ 'admin'
33
+ end
34
+
30
35
  # Override cancan controlelr resource class to avoid attributes
31
36
  # assignation issues with resources
32
37
  #
@@ -28,7 +28,7 @@ module Para
28
28
  end
29
29
 
30
30
  def clone
31
- new_resource = resource.deep_clone include: resource.class.cloneable_associations
31
+ new_resource = resource.deep_clone!
32
32
  new_resource.save!
33
33
 
34
34
  if new_resource.save
@@ -8,7 +8,8 @@ module Para
8
8
  def create
9
9
  job = @exporter.perform_later(
10
10
  model_name: @component.try(:model).try(:name),
11
- search: params[:q]
11
+ search: params[:q],
12
+ params: params.permit(@exporter.params_whitelist).to_h
12
13
  )
13
14
 
14
15
  track_job(job)
@@ -0,0 +1,13 @@
1
+ module Para
2
+ module Admin
3
+ class NestedFormsController < ComponentController
4
+ def show
5
+ @model = params[:model_name].constantize
6
+ @object = params[:id] ? @model.find(params[:id]) : @model.new
7
+ @object_name = params[:object_name]
8
+
9
+ render layout: false
10
+ end
11
+ end
12
+ end
13
+ end
@@ -49,7 +49,7 @@ module Para
49
49
  def destroy
50
50
  resource.destroy
51
51
  flash_message(:success, resource)
52
- redirect_to @component.path
52
+ redirect_to after_form_submit_path
53
53
  end
54
54
 
55
55
  def order
@@ -83,14 +83,25 @@ module Para
83
83
 
84
84
  def after_form_submit_path
85
85
  if params[:_save_and_edit]
86
- { action: 'edit', id: resource.id, anchor: current_anchor }
86
+ host_redirect_params.merge(
87
+ action: 'edit',
88
+ id: resource.id,
89
+ anchor: current_anchor
90
+ )
87
91
  elsif params[:_save_and_add_another]
88
- { action: 'new' }
92
+ host_redirect_params.merge(
93
+ action: 'new',
94
+ type: resource.try(:type)
95
+ )
89
96
  else
90
97
  params.delete(:return_to).presence || @component.path
91
98
  end
92
99
  end
93
100
 
101
+ def host_redirect_params
102
+ { subdomain: request.subdomain, domain: request.domain }
103
+ end
104
+
94
105
  def resource_model
95
106
  @resource_model ||= self.class.resource_model
96
107
  end
@@ -1,13 +1,15 @@
1
1
  module Para
2
2
  module Admin
3
3
  class SearchController < ApplicationController
4
- include Para::ModelHelper
5
- include Para::SearchHelper
6
-
7
4
  def index
5
+ # Parse ids that are provided as string into array
6
+ if params[:q] && params[:q][:id_in].is_a?(String)
7
+ params[:q][:id_in] = params[:q][:id_in].split(',')
8
+ end
9
+
8
10
  model = params[:model_name].constantize
9
- attributes = model_field_mappings(model).fields
10
- @results = model.ransack(fulltext_search_param_for(attributes) => params[:search]).result
11
+ @results = model.ransack(params[:q]).result
12
+
11
13
  render layout: false
12
14
  end
13
15
  end
@@ -9,15 +9,20 @@ module Para
9
9
  end
10
10
 
11
11
  def relation_path(controller_or_resource, options = {})
12
- if Hash === controller_or_resource
12
+ if controller_or_resource.is_a?(Hash)
13
13
  options = controller_or_resource
14
14
  controller_or_resource = nil
15
15
  end
16
16
 
17
17
  components = [:admin, self, controller_or_resource].compact
18
+
18
19
  find_path(components, options)
19
20
  end
20
21
 
22
+ def page_container_class
23
+ 'col-xs-12'
24
+ end
25
+
21
26
  private
22
27
 
23
28
  # Try to find a polymorphic path for the given arguments
@@ -28,7 +33,7 @@ module Para
28
33
  #
29
34
  def find_path(path, options)
30
35
  safe_polymorphic_path(path, options).tap do |result|
31
- raise result.class, result.message if Exception === result
36
+ raise result if result.is_a?(Exception)
32
37
  end
33
38
  end
34
39
 
@@ -28,6 +28,10 @@ module Para
28
28
  find_path(data, options)
29
29
  end
30
30
 
31
+ def page_container_class
32
+ history? ? 'col-md-8' : super
33
+ end
34
+
31
35
  private
32
36
 
33
37
  def extract_id_from(object)
@@ -20,6 +20,12 @@ module Para
20
20
  find_path(data, options)
21
21
  end
22
22
 
23
+ def page_container_class
24
+ history? ? 'col-md-8' : super
25
+ end
26
+
27
+ private
28
+
23
29
  def action_option_for(options, nested: false)
24
30
  if !nested && options[:action].try(:to_sym) == :show
25
31
  nil
@@ -0,0 +1,79 @@
1
+ class CallForProjectsVotesExporter < Para::Exporter::Xls
2
+ attr_reader :call_for_projects
3
+
4
+ def name
5
+ 'votes-appel-projets'
6
+ end
7
+
8
+ protected
9
+
10
+ def self.params_whitelist
11
+ [:call_for_projects_id]
12
+ end
13
+
14
+ def resources
15
+ resources = ActsAsVotable::Vote.joins(
16
+ "LEFT JOIN call_for_projects_applications " +
17
+ "ON call_for_projects_applications.id = votes.votable_id " +
18
+ "AND votes.votable_type = 'CallForProjectsApplication'"
19
+ ).includes(:voter, votable: :call_for_projects)
20
+
21
+ # Filter if available
22
+ resources = resources.where(
23
+ call_for_projects_applications: {
24
+ call_for_projects_id: params[:call_for_projects_id]
25
+ }
26
+ ) if params[:call_for_projects_id]
27
+
28
+ resources
29
+ end
30
+
31
+ # Defining the fields that you want to export will export all those fields
32
+ # directly to the XLS file
33
+ #
34
+ def headers
35
+ ['Appel à projets', 'Projet', 'E-mail', 'Nom', 'Prénom', 'Date du vote']
36
+ end
37
+
38
+ # If you need special behavior in the row generation (rendering associated
39
+ # models or other specific logic), you can return an array here that will
40
+ # be written to the XLS
41
+ #
42
+ # For safe XLS writing, use the #encode method on every string in the
43
+ # returned array.
44
+ #
45
+ # Example :
46
+ #
47
+ # fields = [...]
48
+ # fields.map!(&:encode)
49
+ #
50
+ def row_for(resource)
51
+ [
52
+ resource.votable.call_for_projects.title,
53
+ resource.votable.name,
54
+ resource.voter.email,
55
+ resource.voter.last_name,
56
+ resource.voter.first_name,
57
+ I18n.l(resource.created_at)
58
+ ]
59
+ end
60
+
61
+ # If you need complete control over you XLS generation, use the following
62
+ # method instead of the #fields or #row_for methods, and return a valid XLS
63
+ # StringIO object.
64
+ #
65
+ # A `#generate_workbook` method is provided, which will yield the workbook to
66
+ # you so you can just fill it, and then returns a StringIO that can be
67
+ # directly written to the Excel file.
68
+ #
69
+ # Please check the [Spreadsheet](https://github.com/zdavatz/spreadsheet) gem
70
+ # documentation for more informations about how to build your Excel document.
71
+ #
72
+ # def generate
73
+ # generate_workbook do |workbook|
74
+ # sheet = workbook.create_worksheet
75
+ # sheet.row(0).concat ['data', 'row']
76
+ # sheet.row(1).concat ['other', 'row']
77
+ # end
78
+ # end
79
+ end
@@ -39,9 +39,8 @@ module Para
39
39
  end
40
40
 
41
41
  def template_path_lookup(*paths)
42
- paths.find do |path|
43
- lookup_context.find_all(path).any?
44
- end
42
+ path = paths.find { |path| lookup_context.find_all(path).any? }
43
+ path&.gsub(/\/_([^\/]+)\z/, '/\1')
45
44
  end
46
45
 
47
46
  def resource_title_for(resource)
@@ -0,0 +1,16 @@
1
+ module Para
2
+ module Admin
3
+ module HistoryHelper
4
+ def history_for(component, action:, **options)
5
+ return unless component.history?
6
+
7
+ partial_path = find_partial_for(
8
+ (options[:resource] || options[:relation]),
9
+ "history/#{ action }"
10
+ )
11
+
12
+ render partial: partial_path, locals: options
13
+ end
14
+ end
15
+ end
16
+ end
@@ -6,7 +6,15 @@ module Para
6
6
  wrapper: :vertical_form,
7
7
  wrapper_mappings: Para::SimpleFormConfig.wrapper_mappings,
8
8
  track_attribute_mappings: true,
9
- html: { class: '', data: { :'para-form' => true } }
9
+ html: {
10
+ class: '',
11
+ data: { :'para-form' => true },
12
+ # Force multipart forms to allow forms with no file input on creation
13
+ # to fetch nested fields with image inputs through the remote nested
14
+ # form loading system. Without this option, rails does not create a
15
+ # multipart form when there is no file input during the form creation.
16
+ multipart: true
17
+ }
10
18
  }
11
19
 
12
20
  options = default_options.deep_merge(options)
@@ -16,8 +16,6 @@ module Para
16
16
  mappings = options.fetch(:mappings, {})
17
17
  end
18
18
 
19
- store_key = ['model', 'mappings', model.name.underscore].join(':')
20
-
21
19
  Para::AttributeFieldMappings.new(
22
20
  model, whitelist_attributes: whitelist_attributes, mappings: mappings
23
21
  )