pg_rails 7.0.8.pre.alpha → 7.0.8.pre.alpha.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (41) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +3 -0
  3. data/pg_associable/app/assets/stylesheets/pg_associable.scss +39 -40
  4. data/pg_associable/app/helpers/pg_associable/form_builder_methods.rb +45 -1
  5. data/pg_associable/app/helpers/pg_associable/helpers.rb +6 -4
  6. data/pg_associable/app/javascript/asociable_controller.tsx +96 -20
  7. data/pg_associable/app/javascript/modal_controller.js +4 -95
  8. data/pg_associable/app/views/pg_associable/_resultados_inline.html.slim +6 -8
  9. data/pg_associable/app/views/pg_engine/base/_pg_associable_modal.html.slim +5 -32
  10. data/pg_engine/app/assets/stylesheets/pg_rails_b5.scss +49 -41
  11. data/pg_engine/app/controllers/pg_engine/resource_helper.rb +6 -2
  12. data/pg_engine/app/decorators/pg_engine/base_decorator.rb +2 -2
  13. data/pg_engine/app/helpers/pg_engine/flash_helper.rb +2 -2
  14. data/pg_engine/app/helpers/pg_engine/form_helper.rb +70 -0
  15. data/pg_engine/app/helpers/pg_engine/route_helper.rb +14 -6
  16. data/pg_engine/app/views/admin/accounts/_form.html.slim +1 -1
  17. data/pg_engine/app/views/admin/user_accounts/_form.html.slim +1 -1
  18. data/pg_engine/app/views/admin/users/_form.html.slim +1 -1
  19. data/pg_engine/app/views/pg_engine/base/index.html.slim +3 -3
  20. data/pg_engine/config/simple_form/simple_form_bootstrap.rb +17 -9
  21. data/pg_engine/db/migrate/20240222115722_create_active_storage_tables.active_storage.rb +57 -0
  22. data/pg_engine/lib/pg_engine/engine.rb +1 -1
  23. data/pg_engine/lib/pg_engine/route_helpers.rb +1 -0
  24. data/pg_engine/lib/pg_engine/utils/pdf_preview_generator.rb +50 -0
  25. data/pg_engine/lib/pg_engine.rb +3 -0
  26. data/pg_engine/spec/fixtures/test.pdf +0 -0
  27. data/pg_engine/spec/pg_engine/pdf_preview_generator_spec.rb +12 -0
  28. data/pg_layout/app/assets/stylesheets/sidebar.scss +10 -2
  29. data/pg_layout/app/javascript/nested_controller.js +48 -0
  30. data/pg_layout/app/javascript/pg_form_controller.js +13 -0
  31. data/pg_layout/app/javascript/utils.ts +34 -0
  32. data/pg_layout/app/views/layouts/pg_layout/devise.html.slim +1 -1
  33. data/pg_layout/app/views/layouts/pg_layout/layout.html.slim +14 -11
  34. data/pg_layout/app/views/pg_layout/_flash.html.slim +1 -1
  35. data/pg_layout/app/views/pg_layout/_navbar.html.erb +10 -0
  36. data/pg_layout/app/views/pg_layout/_sidebar.html.erb +3 -3
  37. data/pg_layout/index.js +4 -0
  38. data/pg_rails/lib/version.rb +1 -1
  39. data/pg_scaffold/lib/generators/pg_slim/templates/_form.html.slim +2 -2
  40. metadata +9 -3
  41. data/pg_associable/app/views/pg_associable/_resultados.html.slim +0 -11
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a6d74fa06142003ba7e436907908f3f7ca491e8ab6367796424de5af92d19217
4
- data.tar.gz: a8a7545e0881a3fb79d3d2185314619341286488d7b1eeacb265c0adacb1b371
3
+ metadata.gz: 54b808ee15e453ddfc9031c04c599eea58099615a03b4d23abadec9ee3951d8c
4
+ data.tar.gz: 552aabdd132314da31928c4fcb2b59969ad7afe21c7a239f45fbc7738a1356ca
5
5
  SHA512:
6
- metadata.gz: 3f27603a1c050b0c5aada27652696a5b5cff62041d51b31ad99e4b09494a5b5f6b3f2376ce56bf725ae7bc7a3effcbb10d2851e5c9df7530902dec5a2d885f09
7
- data.tar.gz: ce9641619c78d375984b774fd007c7054e8ac6fe605d0f2c95c0f71bddfe498b081f64589c8a566a4da48d82f60b332d20f1359c937aa8cb34c137fa7a497014
6
+ metadata.gz: 5dddf3ab456741e7f671be016484caf643c1ad09a76ba96900707ab4e992049c5eb7da1273ab82b3fd83975278b72797cf4f9c0a178da5097f6343103e7968e7
7
+ data.tar.gz: 87c679f069138a579790599626636fcf31c44ea9a1393bd13314cb2c5268c6add6c46dc89eabcb742739a2d19179d0cf475860bdf108cd981e743183f0ae1a30
data/README.md CHANGED
@@ -86,3 +86,6 @@ be rails pg_engine_engine:install:migrations
86
86
  "build:css:prefix": "postcss ./pg_rails/builds/application.css --use=autoprefixer --output=./pg_rails/builds/application.css",
87
87
  "build:css": "yarn build:css:compile && yarn build:css:prefix",
88
88
 
89
+
90
+ ruby-vips
91
+ pdftoppm
@@ -1,44 +1,47 @@
1
1
  @use 'sass:color';
2
2
 
3
- [data-state=select-item] .show-on-new-item {
4
- display: none;
5
- }
6
- [data-state=new-item] .show-on-select-item {
7
- display: none;
8
- }
9
3
  .pg-form {
10
4
  .pg_associable {
11
5
  .limpiar {
12
6
  display: none;
13
7
  position: absolute;
14
- top: 8px;
15
- right: 10px;
8
+ right: 0.6em;
9
+ top: 0;
10
+ bottom: 0;
11
+
16
12
  i {
13
+ align-self: center;
17
14
  color: #6f7071;
18
15
  }
19
16
  }
20
17
  .pencil {
18
+ display: flex;
21
19
  position: absolute;
22
- top: 6px;
23
- right: 9px;
20
+ right: 0.6em;
21
+ top: 0;
22
+ bottom: 0;
24
23
  color: #6f7071;
25
24
  cursor: pointer;
26
25
  }
26
+ .pencil::before {
27
+ align-self: center;
28
+ }
27
29
  &.focus .pencil {
28
30
  display: none;
29
31
  }
30
32
  input[type=text] {
31
33
  background-color: white;
34
+ padding-right: 2em;
32
35
  }
33
36
  &.filled {
34
37
  .pencil {
35
38
  display: none;
36
39
  }
37
40
  .limpiar {
38
- display: inline-block;
41
+ display: flex;
39
42
  }
40
- input, input:focus {
41
- background-color: color.adjust(#a7b7bb, $saturation: +10%, $lightness: +20%);
43
+ .resultados-wrapper {
44
+ display:none!important;
42
45
  }
43
46
  }
44
47
  .resultados-wrapper {
@@ -46,11 +49,6 @@
46
49
  position: relative;
47
50
  }
48
51
  &:focus-within {
49
- .search-box {
50
- // outline: 1px solid color.adjust(#a7b7bb, $saturation: +30%);
51
- // border-radius: 3px;
52
- }
53
-
54
52
  &:has(.resultados) {
55
53
  input[type=text] {
56
54
  border-bottom-left-radius: 0!important;
@@ -64,36 +62,37 @@
64
62
  display: block;
65
63
  }
66
64
  }
67
- .resultados {
68
- position: absolute;
69
- // top: 30px;
70
- background-color: white;
71
- border: 1px solid #a7b7bb;
72
- border-top: none;
73
- border-radius: 4px;
74
- padding: 5px 11px;
75
- width: 100%;
76
-
77
- border-top-left-radius: 0;
78
- border-top-right-radius: 0;
79
- }
80
- }
81
- }
82
- .modal-asociable {
83
- .buscar input[type=text] {
84
- max-width: 180px;
85
- }
86
- .resultados {
87
- margin-top: 16px;
88
- border: 1px solid #c8c8c8;
89
65
  }
90
66
  }
67
+ // .modal-asociable {
68
+ // .buscar input[type=text] {
69
+ // max-width: 180px;
70
+ // }
71
+ // .resultados {
72
+ // margin-top: 16px;
73
+ // border: 1px solid #c8c8c8;
74
+ // }
75
+ // }
91
76
  .resultados {
92
77
  .list-group-item:hover {
93
78
  background-color: color.adjust(#a7b7bb, $saturation: +10%, $lightness: +20%);
94
79
  }
95
80
  }
81
+ .sub-wrapper {
82
+ overflow: auto;
83
+ box-shadow: 0px 9px 13px -3px rgba(0, 0, 0, 0.5);
84
+ // position: absolute;
85
+ // z-index: 1;
86
+ background-color: white;
87
+ border: 1px solid #a7b7bb;
88
+ border-top: none;
89
+ border-radius: 4px;
90
+ padding: 5px 11px;
91
+ width: 100%;
96
92
 
93
+ border-top-left-radius: 0;
94
+ border-top-right-radius: 0;
95
+ }
97
96
  .modal-asociable .modal-footer {
98
97
  justify-content: space-between;
99
98
  }
@@ -1,3 +1,4 @@
1
+ # TODO: mover a form_builder
1
2
  module PgAssociable
2
3
  module FormBuilderMethods
3
4
  def self.included(mod)
@@ -5,10 +6,53 @@ module PgAssociable
5
6
  mod.include PgEngine::RouteHelper
6
7
  end
7
8
 
9
+ MAXIMO_PARA_SELECT = 10
10
+ # TODO: si está entre 10 y 50, habilitar un buscador por js
11
+
8
12
  def pg_associable(atributo, options = {})
13
+ return input(atributo, options) if options[:disabled]
14
+
15
+ collection, puede_crear = collection_pc(atributo, options)
16
+ options.deep_merge!({ wrapper_html: { 'data-puede-crear': 'true' } }) if puede_crear
17
+
18
+ if !puede_crear && collection.count <= MAXIMO_PARA_SELECT
19
+ select_comun(atributo, options, collection)
20
+ else
21
+ select_pro(atributo, options, collection)
22
+ end
23
+ end
24
+
25
+ def collection_pc(atributo, _options)
26
+ klass = clase_asociacion(atributo)
27
+ user = template.controller.current_user
28
+ in_modal = options[:asociable].present?
29
+ puede_crear = !in_modal && Pundit::PolicyFinder.new(klass).policy.new(user, klass).new?
30
+ collection = Pundit::PolicyFinder.new(klass).scope.new(user, klass).resolve
31
+ [collection, puede_crear]
32
+ end
33
+
34
+ def select_pro(atributo, options, collection)
35
+ if (preload = options.delete(:preload))
36
+ collection = preload.is_a?(Integer) ? collection.limit(preload) : preload
37
+ options.deep_merge!({ wrapper_html: { 'data-preload': collection.decorate.to_json } })
38
+ end
39
+ # TODO: usar una clase más precisa para el modal?
40
+ options.deep_merge!({ wrapper_html: { data: { controller: 'asociable',
41
+ 'asociable-modal-outlet': '.modal' } } })
9
42
  options[:as] = 'pg_associable'
10
- options[:wrapper_html] = { data: { controller: 'asociable', 'asociable-modal-outlet': '.modal' } }
11
43
  association atributo, options
12
44
  end
45
+
46
+ def select_comun(atributo, options, collection)
47
+ options[:collection] = collection
48
+ association atributo, options
49
+ end
50
+
51
+ def clase_asociacion(atributo)
52
+ asociacion = object.class.reflect_on_all_associations.find { |a| a.name == atributo.to_sym }
53
+ nombre_clase = asociacion.options[:class_name]
54
+ nombre_clase = asociacion.name.to_s.camelize if nombre_clase.nil?
55
+ Object.const_get(nombre_clase)
56
+ end
13
57
  end
14
58
  end
@@ -1,5 +1,7 @@
1
1
  module PgAssociable
2
2
  module Helpers
3
+ MAX_RESULTS = 8
4
+
3
5
  def pg_respond_abrir_modal
4
6
  respond_to do |format|
5
7
  format.turbo_stream do
@@ -9,11 +11,11 @@ module PgAssociable
9
11
  end
10
12
 
11
13
  def pg_respond_buscar
12
- partial = params[:partial] || 'pg_associable/resultados'
13
- resultados = params[:resultados] || 'resultados'
14
- @collection = policy_scope(@clase_modelo).kept.query(params[:query]).limit(6)
14
+ partial = 'pg_associable/resultados_inline'
15
+ resultados_prefix = 'resultados-inline'
16
+ @collection = policy_scope(@clase_modelo).kept.query(params[:query]).limit(MAX_RESULTS)
15
17
  render turbo_stream:
16
- turbo_stream.update("#{resultados}-#{params[:id]}",
18
+ turbo_stream.update("#{resultados_prefix}-#{params[:id]}",
17
19
  partial:, locals: { collection: @collection })
18
20
  end
19
21
  end
@@ -6,13 +6,11 @@ export default class extends Controller {
6
6
  static outlets = ['modal']
7
7
 
8
8
  lastValue = null
9
- result = null
9
+ subWrapper = null
10
10
  elemId = null
11
11
  input = null
12
12
 
13
13
  connect () {
14
- console.log('connect asociable')
15
-
16
14
  // ID único para identificar el campo y el modal
17
15
  this.elemId = Math.trunc(Math.random() * 1000000000)
18
16
 
@@ -21,14 +19,22 @@ export default class extends Controller {
21
19
  this.element.setAttribute('data-asociable-modal-outlet', `.modal-${this.elemId}`)
22
20
  this.element.classList.add(`asociable-${this.elemId}`)
23
21
 
24
- this.result = document.createElement('div')
25
- this.result.setAttribute('id', `resultados-inline-${this.elemId}`)
26
- this.result.classList.add('resultados-wrapper')
27
- this.input.parentNode.appendChild(this.result)
22
+ const result = document.createElement('div')
23
+ result.classList.add('resultados-wrapper')
24
+ this.subWrapper = document.createElement('div')
25
+ this.subWrapper.setAttribute('id', `resultados-inline-${this.elemId}`)
26
+ this.subWrapper.classList.add('sub-wrapper')
27
+ this.subWrapper.classList.add('position-absolute')
28
+ this.subWrapper.classList.add('z-1')
29
+ result.appendChild(this.subWrapper)
30
+ this.input.parentNode.appendChild(result)
31
+
32
+ this.resetResultados()
28
33
 
29
34
  const input = this.element.querySelector('input[type=text]')
30
35
  if (input.value) {
31
36
  this.element.classList.add('filled')
37
+ input.setAttribute('readonly', 'true')
32
38
  }
33
39
  this.element.querySelector('.pencil').onclick = () => {
34
40
  input.focus()
@@ -55,6 +61,20 @@ export default class extends Controller {
55
61
  if (this.input.value.length === 0) {
56
62
  this.escribiAlgo()
57
63
  }
64
+
65
+ if (!this.element.closest('.modal')) {
66
+ const wHeight = window.visualViewport.height
67
+ const scrollTop = document.scrollingElement.scrollTop
68
+ const viewPortBottom = scrollTop + wHeight
69
+ const swHeight = parseInt(this.subWrapper.style.maxHeight) + 20
70
+ const elementTop = this.element.getBoundingClientRect().top + scrollTop
71
+ const inputBottom = this.input.getBoundingClientRect().bottom + scrollTop
72
+ const swBottom = inputBottom + swHeight
73
+
74
+ if (swBottom > viewPortBottom) {
75
+ document.scrollingElement.scroll({ top: elementTop })
76
+ }
77
+ }
58
78
  }
59
79
  this.input.onkeyup = (e) => {
60
80
  if (this.input.value.length === 0) {
@@ -72,6 +92,61 @@ export default class extends Controller {
72
92
  return false
73
93
  }
74
94
  }
95
+ this.setMaxHeight()
96
+ }
97
+
98
+ resetResultados () {
99
+ const rows = []
100
+ if (this.element.dataset.puedeCrear) {
101
+ rows.push(
102
+ <a key="new" href="javascript:void(0)"
103
+ className="list-group-item"
104
+ data-action="asociable#crearItem"
105
+ >
106
+ Nuevo
107
+ </a>
108
+ )
109
+ }
110
+ if (this.element.dataset.preload) {
111
+ JSON.parse(this.element.dataset.preload).forEach((object) => {
112
+ rows.push(
113
+ <a key={object.id} href="javascript:void(0)"
114
+ className="list-group-item"
115
+ data-action="asociable#selectItem"
116
+ data-id={object.id}
117
+ data-object={JSON.stringify(object)}
118
+ >
119
+ {object.to_s}
120
+ </a>
121
+ )
122
+ })
123
+ }
124
+ this.subWrapper.innerHTML = renderToStaticMarkup(
125
+ <div className="resultados" tabIndex={-1}>
126
+ <ul className="list-group list-group-flush">
127
+ {rows}
128
+ </ul>
129
+ </div>
130
+ )
131
+ }
132
+
133
+ setMaxHeight () {
134
+ let maxHeight
135
+ if (!this.element.closest('.modal')) {
136
+ const scrollTop = document.scrollingElement.scrollTop
137
+ const inputY = this.input.getBoundingClientRect().bottom + scrollTop
138
+ const bodyHeight = document.body.getBoundingClientRect().height
139
+ maxHeight = bodyHeight - inputY
140
+ if (maxHeight < 200) {
141
+ maxHeight = 200
142
+ }
143
+ if (bodyHeight < inputY + maxHeight) {
144
+ document.body.style.height = `${inputY + maxHeight}px`
145
+ }
146
+ } else {
147
+ maxHeight = 200
148
+ }
149
+ this.subWrapper.style.maxHeight = `${maxHeight - 20}px`
75
150
  }
76
151
 
77
152
  crearItem () {
@@ -82,7 +157,7 @@ export default class extends Controller {
82
157
  }
83
158
 
84
159
  const elem = (
85
- <form method="get" action={this.input.dataset.url_modal} data-turbo-stream="true">
160
+ <form method="get" action={this.input.dataset.urlModal} data-turbo-stream="true">
86
161
  <input type="hidden" name="id" value={this.elemId} />
87
162
  </form>
88
163
  )
@@ -98,7 +173,7 @@ export default class extends Controller {
98
173
  }
99
174
 
100
175
  buscando () {
101
- this.result.innerHTML = renderToStaticMarkup(
176
+ this.subWrapper.innerHTML = renderToStaticMarkup(
102
177
  <div className="resultados" tabIndex={-1}>
103
178
  <div className="fst-italic text-secondary">Buscando...</div>
104
179
  </div>
@@ -111,11 +186,14 @@ export default class extends Controller {
111
186
  } else {
112
187
  this.completarCampo(null)
113
188
  }
114
- this.result.innerHTML = ''
115
189
  }
116
190
 
117
191
  doSearch (force = false) {
192
+ if (this.element.classList.contains('filled')) {
193
+ return
194
+ }
118
195
  if (!force && this.input.value.length < 3) {
196
+ this.resetResultados()
119
197
  return
120
198
  }
121
199
  if (!force && this.input.value === this.lastValue) {
@@ -128,13 +206,13 @@ export default class extends Controller {
128
206
  }, 200)
129
207
  document.addEventListener('turbo:before-stream-render', function () {
130
208
  clearTimeout(timerId)
131
- })
209
+ // TODO: testear
210
+ }, { once: true })
132
211
  const elem = (
133
- <form method="post" action={this.input.dataset.url_search} data-turbo-stream="true">
212
+ <form method="post" action={this.input.dataset.urlSearch} data-turbo-stream="true">
134
213
  <input type="hidden" name="id" value={this.elemId} />
135
- <input type="hidden" name="partial" value="pg_associable/resultados_inline" />
136
- <input type="hidden" name="resultados" value="resultados-inline" />
137
214
  <input type="hidden" name="query" value={this.input.value} />
215
+ <input type="hidden" name="puede_crear" value={this.element.dataset.puedeCrear} />
138
216
  </form>
139
217
  )
140
218
  const form = document.createElement('div')
@@ -150,22 +228,20 @@ export default class extends Controller {
150
228
  if (object) {
151
229
  hiddenField.value = object.id
152
230
  textField.value = object.to_s
231
+ textField.setAttribute('readonly', 'true')
153
232
  this.element.classList.add('filled')
154
233
  this.element.dataset.object = object
155
234
  const event = new CustomEvent('pg_associable:changed', { detail: object })
156
235
  this.element.dispatchEvent(event)
157
236
  } else {
158
- textField.value = null
159
237
  hiddenField.value = null
238
+ textField.value = null
239
+ textField.removeAttribute('readonly')
160
240
  this.element.classList.remove('filled')
161
241
  this.element.dataset.object = null
162
242
  const event = new CustomEvent('pg_associable:changed')
163
243
  this.element.dispatchEvent(event)
164
244
  }
165
- this.result.innerHTML = ''
166
- }
167
-
168
- disconnect () {
169
- console.log('disconnect asociable')
245
+ this.resetResultados()
170
246
  }
171
247
  }
@@ -3,118 +3,27 @@ import * as bootstrap from 'bootstrap'
3
3
 
4
4
  export default class extends Controller {
5
5
  static outlets = ['asociable']
6
- static targets = ['response', 'result', 'searchInput', 'searchForm']
6
+ static targets = ['response']
7
7
 
8
8
  modalPuntero = null
9
- lastValue = ''
10
9
 
11
10
  connect (e) {
12
- console.log('ModalController connected')
13
- const modal = this.targets.element
14
- this.modalPuntero = new bootstrap.Modal(modal)
11
+ this.modalPuntero = new bootstrap.Modal(this.element)
15
12
  this.modalPuntero.show()
16
-
17
- if (this.searchInputTargets.length > 0) {
18
- this.bindSearchInput()
19
- }
20
- }
21
-
22
- debounce (callback, wait) {
23
- let timerId
24
- return (...args) => {
25
- clearTimeout(timerId)
26
- timerId = setTimeout(() => {
27
- callback(...args)
28
- }, wait)
29
- }
30
- }
31
-
32
- bindSearchInput () {
33
- const doSearchBounce = this.debounce((force) => {
34
- this.doSearch(force)
35
- }, 200)
36
- this.searchInputTarget.onkeydown = (e) => {
37
- if (e.keyCode === 13) {
38
- e.preventDefault()
39
- return false
40
- }
41
- }
42
- this.searchInputTarget.onkeyup = (e) => {
43
- if (e.keyCode === 13) {
44
- doSearchBounce(true)
45
- } else {
46
- doSearchBounce()
47
- }
48
- }
49
- }
50
-
51
- buscando () {
52
- this.resultTarget.innerHTML = `
53
- <ul class="resultados list-group list-group-flush" tabindex="-1">
54
- <li class="list-group-item">
55
- <span class="fst-italic text-secondary">Buscando...</span>
56
- </li>
57
- </ul>
58
- `
59
- }
60
-
61
- doSearch (force = false) {
62
- if (!force && this.searchInputTarget.value.length < 3) {
63
- return
64
- }
65
- if (!force && this.searchInputTarget.value === this.lastValue) {
66
- return
67
- }
68
- this.lastValue = this.searchInputTarget.value
69
-
70
- const timerId = setTimeout(() => {
71
- this.buscando()
72
- }, 200)
73
- document.addEventListener('turbo:before-stream-render', function (e) {
74
- clearTimeout(timerId)
75
- })
76
- this.searchFormTarget.requestSubmit()
77
- }
78
-
79
- selectItem (e) {
80
- const asociable = this.asociableOutlet
81
- if (e.target.dataset.object) {
82
- asociable.completarCampo(JSON.parse(e.target.dataset.object))
83
- } else {
84
- asociable.completarCampo(null)
85
- }
86
- this.remove()
87
13
  }
88
14
 
89
15
  responseTargetConnected (e) {
90
16
  const newObject = JSON.parse(e.dataset.response)
91
- const asociable = this.asociableOutlet
92
- asociable.completarCampo(newObject)
93
- this.remove()
94
- }
95
-
96
- remove () {
97
- this.targets.element.remove()
17
+ this.asociableOutlet.completarCampo(newObject)
18
+ this.element.remove()
98
19
  }
99
20
 
100
21
  openModal () {
101
22
  this.modalPuntero.show()
102
23
  }
103
24
 
104
- toggleCrearElegir (e) {
105
- const content = this.element.querySelector('.modal-content')
106
- const state = content.dataset.state
107
- const newValue = state === 'new-item' ? 'select-item' : 'new-item'
108
- content.setAttribute('data-state', newValue)
109
- }
110
-
111
25
  disconnect (e) {
112
- console.log('ModalController disconnected')
113
26
  this.modalPuntero.dispose()
114
27
  document.querySelectorAll('.modal-backdrop').forEach(e => { e.remove() })
115
28
  }
116
-
117
- buscar () {
118
- alert('buscar')
119
- }
120
29
  }
@@ -1,15 +1,13 @@
1
- .resultados tabindex="-1"
2
- - if collection.any?
3
- .list-group.list-group-flush
4
- = link_to 'Crear', 'javascript:void(0)',
1
+ .resultados.inline tabindex="-1"
2
+ ul.list-group.list-group-flush
3
+ - if params[:puede_crear].present?
4
+ = link_to 'Nuevo', 'javascript:void(0)',
5
5
  class: 'list-group-item', data: { action: 'asociable#crearItem' }
6
- = link_to 'Ninguno', 'javascript:void(0)',
7
- class: 'list-group-item', data: { action: 'asociable#selectItem' }
6
+ - if collection.any?
8
7
  - collection.each do |object|
9
8
  = link_to object.to_s, 'javascript:void(0)',
10
9
  class: 'list-group-item',
11
10
  data: { action: 'asociable#selectItem',
12
11
  id: object.id, object: object.decorate.to_json }
13
- - else
14
- ul.list-group.list-group-flush
12
+ - else
15
13
  li.list-group-item No hay resultados para "#{params[:query]}"
@@ -2,40 +2,13 @@
2
2
  tabindex="-1" data-controller="modal"
3
3
  data-modal-asociable-outlet=".asociable-#{params[:id]}"]
4
4
  .modal-dialog
5
- .modal-content.pg_associable data-state="select-item"
5
+ / TODO: pg_associable no va
6
+ .modal-content.pg_associable
6
7
  .modal-header
7
- .modal-title.show-on-new-item
8
+ .modal-title
9
+ / TODO: género "Nuevo/a"
8
10
  h3 Nuevo #{@clase_modelo.nombre_singular.downcase}
9
- .modal-title.show-on-select-item
10
- h3 Buscar #{@clase_modelo.nombre_singular.downcase}
11
11
  a.btn-close[type="button" data-bs-dismiss="modal" aria-label="Close"]
12
12
  .modal-body
13
- .show-on-select-item
14
- - if policy_scope(@clase_modelo).kept.count.zero?
15
- p No hay #{@clase_modelo.nombre_plural.downcase} aún
16
- = link_to "Crear el primer #{@clase_modelo.nombre_singular.downcase}",
17
- 'javascript:void(0)', data: { action: 'modal#toggleCrearElegir' }
18
- - else
19
- = form_tag namespaced_path(@clase_modelo, prefix: :buscar),
20
- data: { 'modal-target': 'searchForm' },
21
- method: :post, class: 'pg-form buscar' do
22
- = hidden_field_tag :id, params[:id]
23
- = text_field_tag :query, '', class: 'form-control',
24
- placeholder: 'Escribí algo para buscar',
25
- autocomplete: 'off',
26
- data: { 'modal-target': 'searchInput' }
27
- / = button_tag 'Buscar'
28
- .resultados-wrapper id="resultados-#{params[:id]}" data-modal-target="result"
29
- #pg-associable-form.show-on-new-item
13
+ .pg-associable-form
30
14
  = render partial: 'form', locals: { object: @clase_modelo.new, asociable: true }
31
-
32
- .modal-footer
33
- = link_to "Buscar #{@clase_modelo.nombre_singular.downcase} existente",
34
- 'javascript:void(0)', class: 'btn btn-primary show-on-new-item',
35
- data: { action: 'modal#toggleCrearElegir' }
36
- = link_to "Nuevo #{@clase_modelo.nombre_singular.downcase}",
37
- 'javascript:void(0)', class: 'btn btn-primary show-on-select-item',
38
- data: { action: 'modal#toggleCrearElegir' }
39
- = link_to "Sin #{@clase_modelo.nombre_singular.downcase}",
40
- 'javascript:void(0)', class: 'btn btn-secondary',
41
- data: { action: 'modal#selectItem' }