Cómo agregar un campo personalizado de tema súper básico

Estoy tratando de entender cómo agregar un campo personalizado a los temas y estoy trabajando con un ejemplo muy básico. Objetivo: Agregar un campo personalizado llamado “sample_field” a cada tema creado, con un valor de cadena simple.

He revisado varios ejemplos, como el plugin de encuestas y el plugin de resuelto y esta discusión, pero estos plugins hacen mucho más con sus campos personalizados, por lo que aún no he descifrado el código básico que se necesita.

Así que aún no lo tengo del todo: creo que me falta algo en mi archivo plugin.rb, y aún no he descubierto cómo vincular el valor de la cadena al campo personalizado en el momento en que se crea el tema.

¿Qué necesito para que esto funcione?

Agradezco cualquier ayuda. ¡Gracias!

Esto es lo que tengo hasta ahora:

plugin.rb:
//crear el campo personalizado:\n

  after_initialize do
     Topic.register_custom_field_type('sample_field', :string)
     add_to_serializer(:topic_view, :custom_fields) { object.custom_fields } //si quiero mostrar el campo personalizado en el lado del cliente
  end

assets/javascripts/initializers/topic-custom-field.js.es6:
//inicializar el objeto de campos personalizados y permitir que se envíe al servidor:\n

import { withPluginApi } from 'discourse/lib/plugin-api';

export default {
  name: 'topic-custom-field',
  initialize() {
    withPluginApi('0.8.31', api => {
      api.modifyClass('model:topic', {
        custom_fields: {},
        asJSON() {
          return Object.assign(this._super(), {
            custom_fields: this.custom_fields
          });
        }
      })
    })
  }
}

Entonces, ¿cómo agrego el valor del campo personalizado al tema en el momento en que se guarda?

Creo que la acción clave “save” para un tema ocurre aquí en la base de código:

app/templates/composer.hbs:

  <div class="save-or-cancel">
            {{#unless model.viewFullscreen}}
              {{composer-save-button action=(action "save")
                                     icon=saveIcon
                                     label=saveLabel
                                     disableSubmit=disableSubmit}}
...

¿Cómo hago algo (en este caso, agregar un valor al campo personalizado) cuando ocurre esa acción “save”?

He intentado crear un archivo js bajo initializers, donde podría hacer algo como:

api.modifyClass('component:composer-save-button', {
   actions: {
       topic.set('custom_fields.sample_field', 'aquí hay un valor para el sample_field')
   }
}

Pero necesito poder vincular ese “topic.set” a la acción “save” en composer.hbs, y no sé cómo hacerlo.


Y si hay una forma más sencilla de hacerlo, ¡estaré encantado de escucharla!

2 Me gusta

No tengo conocimiento de un ejemplo perfecto, pero podría intentar desarrollar uno en algún momento.

Podrías echar un vistazo a otros complementos para buscar ejemplos. No estoy seguro de cuál sería a primera vista. Existe un repositorio de Discourse llamado algo como “all-the-plugins”; a menudo lo busco con grep para encontrar cosas.

Apuesto a que el complemento de reacciones que está en pruebas ahora mismo es un buen ejemplo. Mira el banner y echa un vistazo a él.

2 Me gusta

Sí, siempre revisa los plugins existentes.

Aquí tienes un ejemplo:

El cual depende de este conector y componente:

2 Me gusta

Gracias a todos, echaré un vistazo a esto. En la publicación original mencioné que ya había revisado muchos otros ejemplos. ¿Alguna opinión sobre el código que proporcioné?

2 Me gusta

Lo siento. No vi ningún problema obvio (para mí). Aunque estoy mejorando en el desarrollo de complementos, a menudo siento que sé justo lo suficiente como para ser peligroso.

2 Me gusta

Posiblemente demasiado complicado si puedes conformarte con “la forma de Discourse de hacer las cosas”, es decir: editar los datos dentro del área de Metadatos del Tema, y solo más tarde cuando se haga clic en el icono del lápiz.

Solo necesitas renderizar un cuadro de entrada correctamente conectado y asegurarte de haber serializado el valor en la Vista del Tema.

El código de PostRevisor hará la magia de actualizar el campo personalizado.

Consulta el ejemplo del plugin de Ubicaciones. Incluso eso es más de lo que necesitas.

Asegúrate de ejecutar también el plugin de Ubicaciones para ver cómo queda.

2 Me gusta

Aquí tienes otro ejemplo, con un escenario de entrada ligeramente diferente, pero que sigue aprovechando los mismos mecanismos y ganchos:

https://github.com/paviliondev/discourse-topic-previews/blob/master/assets/javascripts/discourse/connectors/edit-topic/select-thumbnail-connector.hbs

4 Me gusta

Gracias. No estoy familiarizado con PostRevisor. Lo estoy investigando ahora.

No estoy seguro de a qué te refieres con “área de Metadatos del Tema”. ¿Es un archivo que tienes en mente? (En cuanto a la interfaz de usuario, sé que existe el compositor para crear, con el editor d dentro, y luego está la propia vista del tema. No estoy seguro de dónde se encuentra el área “Meta” allí.)

2 Me gusta

Considero que la información de Categoría y Etiqueta son metadatos.

2 Me gusta

Aquí tienes un ejemplo básico que funciona actualmente para crear un campo personalizado de tema y luego establecerlo. Esto configura el campo cuando el usuario hace clic en un botón específico en la página de visualización del tema.

Observo que en los plugins que tienen campos personalizados de tema, es común utilizar PostRevisor (como PostRevisor.track_topic_field) y DiscourseEvent.on(:topic_created) do |topic|... en plugin.rb. Estos podrían permitir establecer el campo personalizado sin necesidad de hacer clic en un botón, como por ejemplo al crear el tema. Sin embargo, aún no he logrado averiguar cómo hacerlo.

[EDIT: ¡Si alguien quiere sugerir código para plugin.rb que añada el valor del campo personalizado a un tema en el momento de su creación (en lugar de tener un botón separado que deba ser pulsado), ¡por favor hazlo! :slight_smile: ]

Así que aquí tienes un ejemplo básico que funciona sin esos trucos avanzados:

plugin.rb

Topic.register_custom_field_type('sample_field', :string)
add_to_class(:topic, :sample_field) { self.custom_fields['sample_field'] } ##quizás no sea necesario. Basado en la línea 83 del plugin discourse-locations plugin.rb
	
add_to_serializer(:topic_view, :sample_field, false) { object.topic.sample_field } ##probablemente solo sea necesario si quieres mostrar el resultado del campo personalizado al usuario

connector/[add-button].hbs

//ejemplo aquí: el conector es topic-above-post-stream, que pasa un modelo (topic) en el outlet del plugin

<button {{action "setThatTopic" model}}>Click Here</button>

connector/[add-button].js.es6

import Topic from 'discourse/models/topic';  //quizás no sea necesario

export default {		
    actions: {
       setThatTopic(model){
           model.set('custom_fields.sample_field', 'newValue123')
           console.log('testing that custom field is there = ' + JSON.stringify(model.custom_fields))
        }
     }
}

assets/javascripts/initializers/topic-custom-field.js.es6

//esto quizás no sea necesario. Pero la idea es inicializar el objeto de campos personalizados y permitir que se envíe al servidor:

import { withPluginApi } from 'discourse/lib/plugin-api';

export default {
    name: 'topic-custom-field',
     initialize() {
	   withPluginApi('0.8.31', api => {
		api.modifyClass('model:topic', {
			custom_fields: {},
			asJSON() {
			    return Object.assign(this._super(), {
				custom_fields: this.custom_fields
			   });
			}
	     })
	   })
    }
}
6 Me gusta

Acabo de publicar un “plugin de educación” que demuestra cómo se hace esto

9 Me gusta

Gracias, @angus. Esto es enormemente útil y justo el tipo de recurso que facilita programar con Discourse. Personalmente, me encantaría ver este tipo de material: ejemplos de código directos y sin adornos para implementar una sola funcionalidad a la vez, aplicados a diversas tareas en Discourse. Por ejemplo, campos personalizados para categorías y grupos, también. Este tipo de recurso ahorra muchísimo tiempo.

3 Me gusta