para 0.7.1 → 0.7.2

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