5
0
Fork 0
mirror of https://0xacab.org/sutty/sutty synced 2024-11-22 15:56:20 +00:00

feat: new_has_one

This commit is contained in:
f 2024-06-03 17:52:53 -03:00
parent ff3042da90
commit 96aebb1346
No known key found for this signature in database
10 changed files with 104 additions and 11 deletions

View file

@ -40,10 +40,18 @@ class PostsController < ApplicationController
render layout: false
end
# El formulario de un Post, si pasamos el uuid, estamos editando, sino
def new_has_one
@uuid = params.require(:value).strip
@indexed_post = site.indexed_posts.find_by!(post_id: @uuid)
render layout: false
end
# El formulario de un Post, si pasamos el UUID, estamos editando, sino
# estamos creando.
def form
uuid = params.permit(:uuid).try(:[], :uuid)
uuid = params.permit(:uuid).try(:[], :uuid).presence
locale
@post =
@ -111,7 +119,7 @@ class PostsController < ApplicationController
params: params)
@post = service.create
if @post.persisted?
if post.persisted?
site.touch
forget_content
end
@ -119,11 +127,11 @@ class PostsController < ApplicationController
# @todo Enviar la creación a otro endpoint para evitar tantas
# condiciones.
if htmx?
if @post.persisted?
if post.persisted?
swap_modals
@value = @post.title.value
@uuid = @post.uuid.value
@value = post.title.value
@uuid = post.uuid.value
@name = params.require(:name)
render render_path_from_attribute, layout: false
@ -133,8 +141,8 @@ class PostsController < ApplicationController
render 'posts/form', layout: false, post: post, site: site, **params.permit(:form, :base, :dir, :locale)
end
elsif @post.persisted?
redirect_to site_post_path(@site, @post)
elsif post.persisted?
redirect_to site_post_path(site, post)
else
render 'posts/new'
end
@ -235,7 +243,7 @@ class PostsController < ApplicationController
# @param triggers [Hash] Otros disparadores
def swap_modals(triggers = {})
params.permit(:show, :hide).each_pair do |key, value|
triggers["modal:#{key}"] = { id: value }
triggers["modal:#{key}"] = { id: value } if value.present?
end
headers['HX-Trigger'] = triggers.to_json if triggers.present?
@ -247,6 +255,7 @@ class PostsController < ApplicationController
when 'new_has_many' then 'posts/new_has_many_value'
when 'new_belongs_to' then 'posts/new_belongs_to_value'
when 'new_has_and_belongs_to_many' then 'posts/new_has_many_value'
when 'new_has_one' then 'posts/new_has_one_value'
else 'nothing'
end
end

View file

@ -18,9 +18,23 @@ export default class extends Controller {
window.removeEventListener("modal:hide", this.hideEvent);
}
/*
* Abrir otro modal, enviando el ID a toda la ventana.
*/
showAnother(event = undefined) {
event?.preventDefault();
if (!event.target?.dataset?.modalShowValue) return;
window.dispatchEvent(new CustomEvent("modal:show", { detail: { id: event.target.dataset.modalShowValue } }));
}
/*
* Podemos enviar la orden de apertura como un click o como un
* CustomEvent incluyendo el id del modal como detail.
*
* El elemento clicleable puede tener un valor que se refiera a otro
* modal también.
*/
show(event = undefined) {
event?.preventDefault();

View file

@ -0,0 +1,6 @@
# frozen_string_literal: true
# Nueva interfaz para relaciones 1:1
class MetadataNewHasOne < MetadataHasOne
include Metadata::UnusedValuesConcern
end

View file

@ -61,8 +61,8 @@
= errors.first
-# Parámetros para HTMX
%input{ type: 'hidden', name: 'hide', value: params.require((post.errors.empty? ? :show : :hide)) }
%input{ type: 'hidden', name: 'show', value: params.require((post.errors.empty? ? :hide : :show)) }
%input{ type: 'hidden', name: 'hide', value: params.permit((post.errors.empty? ? :show : :hide)).try(:values).try(:first) }
%input{ type: 'hidden', name: 'show', value: params.permit((post.errors.empty? ? :hide : :show)).try(:values).try(:first) }
%input{ type: 'hidden', name: 'name', value: params.require(:name) }
%input{ type: 'hidden', name: 'base', value: params.require(:base) }
%input{ type: 'hidden', name: 'form', value: options[:id] }

View file

@ -0,0 +1,2 @@
= render 'posts/new_related_post', post: post
%input{ type: 'hidden', name: name, value: value }

View file

@ -0,0 +1,6 @@
%tr{ id: attribute }
%th= post_label_t(attribute, post: post)
%td{ dir: dir, lang: locale }
- p = metadata.has_one
- if p
= link_to p.title.value, site_post_path(site, p.id)

View file

@ -0,0 +1,53 @@
-#
Genera un listado de radios entre los que se puede elegir solo uno para
guardar. Podemos elegir entre los artículos ya cargados o agregar uno
nuevo.
Al agregar uno nuevo, se abre un segundo modal que carga el formulario
correspondiente vía HTMX. El formulario tiene que cargarse por fuera
del formulario principal porque no se pueden anidar.
:ruby
id = random_id
name = "#{base}[#{attribute}]"
target_id = random_id
form_id = random_id
modal_id = random_id
post_id = random_id
post_form_id = random_id
post_modal_id = random_id
post_form_loaded_id = random_id
value_list_id = random_id
layout = metadata.filter[:layout]
%div{ data: { controller: 'modal' }}
.form-group
= hidden_field_tag name, ''
.d-flex.align-items-center.justify-content-between
= label_tag id, post_label_t(attribute, post: post), class: 'h3'
= render 'bootstrap/btn', content: t('.edit'), action: 'modal#showAnother', data: { 'modal-show-value': modal_id }
-# Aquí se reemplaza por la tarjeta y el UUID luego de guardar
.row.row-cols-1.no-gutters.placeholder-glow{ id: target_id }
-# @todo issue-7537
- if !metadata.empty? && (indexed_post = site.indexed_posts.find_by(post_id: metadata.value))
= render 'posts/new_has_one', post: indexed_post, name: name, value: metadata.value
-#
El modal se genera por fuera del formulario, para poder enviar los
datos y recibir su UUID en respuesta.
- content_for :post_form do
%div{ id: modal_id, data: { controller: 'modal' }}
- if layout.is_a?(String)
= render 'bootstrap/modal', id: id, modal_content_attributes: { class: 'h-100' } do
- content_for :"#{id}_body" do
-# @todo ocultar el modal después de guardar
.placeholder-glow{ 'hx-get': site_posts_form_path(site, layout: layout, base: id, name: name, form: form_id, swap: 'innerHTML', target: target_id, attribute: 'new_has_one', hide: modal_id, uuid: metadata.value), 'hx-trigger': 'load' }
%span.placeholder.w-100.h-100
- content_for :"#{id}_footer" do
= render 'bootstrap/btn', form: form_id, content: t('.save'), type: 'submit', class: 'm-0 mt-1 mr-1'
= render 'bootstrap/btn', content: t('.cancel'), action: 'modal#hide', class: 'm-0 mt-1 mr-1'
- else
Nada

View file

@ -0,0 +1 @@
= render 'posts/new_has_one', post: @indexed_post, name: params.require(:name), value: @uuid

View file

@ -0,0 +1 @@
= render 'posts/new_has_one', post: @post.to_index, name: params.require(:name), value: @uuid

View file

@ -103,6 +103,7 @@ Rails.application.routes.draw do
get :'posts/new_array', to: 'posts#new_array'
get :'posts/new_array_value', to: 'posts#new_array_value'
get :'posts/new_related_post', to: 'posts#new_related_post'
get :'posts/new_has_one', to: 'posts#new_has_one'
get :'posts/form', to: 'posts#form'
resources :posts do