Comment ajouter un champ personnalisé de sujet super basique

J’essaie de comprendre comment ajouter un champ personnalisé aux sujets et je travaille sur un exemple très basique. Objectif : Ajouter un champ personnalisé nommé “sample_field” à chaque sujet créé, avec une valeur de type chaîne simple.

J’ai examiné divers exemples, comme le plugin poll, le plugin solved et cette discussion, mais ces plugins font beaucoup plus avec leurs champs personnalisés, ce qui m’a empêché de comprendre le code de base nécessaire.

Donc, je n’y suis pas encore tout à fait : mon fichier plugin.rb manque quelque chose (je pense), et je n’ai pas encore trouvé comment lier la valeur de la chaîne au champ personnalisé au moment de la création du sujet.

Que dois-je faire pour que cela fonctionne ?

Toute aide est appréciée. Merci !

Voici ce que j’ai jusqu’à présent

plugin.rb :
//Créer le champ personnalisé :

  after_initialize do
     Topic.register_custom_field_type('sample_field', :string)
     add_to_serializer(:topic_view, :custom_fields) { object.custom_fields } //si je veux afficher le champ personnalisé côté client
  end

assets/javascripts/initializers/topic-custom-field.js.es6 :
//Initialiser l’objet des champs personnalisés et permettre son envoi au serveur :

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
          });
        }
      })
    })
  }
}

Ensuite, comment ajouter la valeur du champ personnalisé au sujet au moment de l’enregistrement ?

Je pense que l’action clé “save” pour un sujet se produit ici dans la base de code :

app/templates/composer.hbs :

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

Comment puis-je faire quelque chose (dans ce cas, ajouter une valeur au champ personnalisé) lorsque cette action “save” se produit ?

J’ai essayé de créer un fichier JS sous initializers, où je pourrais faire quelque chose comme :

api.modifyClass('component:composer-save-button', {
   actions: {
       topic.set('custom_fields.sample_field', 'voici une valeur pour le sample_field')
   }
}

Mais je dois pouvoir lier ce “topic.set” à l’action “save” dans composer.hbs, et je ne sais pas comment faire.


Et s’il existe un moyen plus simple de faire cela, je suis heureux de l’entendre !

2 « J'aime »

Je ne connais pas d’exemple parfait, mais je pourrais essayer d’en développer un à un moment donné.

Vous pourriez consulter d’autres plugins pour trouver des exemples. Je ne suis pas sûr de savoir lequel sur le coup. Il existe un dépôt Discourse appelé quelque chose comme all-the-plugins ; je le parcours souvent avec grep pour chercher des éléments.

Je parie que le plugin de réactions actuellement en test ici est un bon exemple. Regardez la bannière et jetez un coup d’œil à cela.

2 « J'aime »

Oui, consultez toujours les plugins existants.

Voici un exemple :

Qui s’appuie sur ce connecteur et ce composant :

2 « J'aime »

Merci à tous — je vais jeter un coup d’œil à tout cela. J’ai mentionné dans le post original que j’avais déjà examiné un certain nombre d’autres exemples. Des idées concernant le code que j’ai fourni ?

2 « J'aime »

Désolé. Je n’ai pas vu de problème évident (pour moi). Bien que je m’améliore dans le développement de plugins, j’ai souvent l’impression de savoir juste assez pour être dangereux.

2 « J'aime »

Potentiellement trop compliqué si vous pouvez vous contenter de « la façon Discourse de faire les choses », à savoir : modifier les données dans la zone Méta du sujet, et ce uniquement plus tard lorsque l’icône crayon est cliquée.

Vous avez juste besoin de rendre une zone de saisie correctement connectée et de vous assurer que la valeur est sérialisée vers la Vue du sujet.

Le code PostRevisor fera la magie de mettre à jour le champ personnalisé.

Regardez l’exemple du plugin Locations. Même cela est plus que ce dont vous avez besoin.

Assurez-vous d’exécuter également le plugin Locations pour voir à quoi cela ressemble.

2 « J'aime »

Voici un autre exemple, avec un scénario d’entrée légèrement différent, mais exploitant toujours les mêmes mécanismes et hooks :

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

4 « J'aime »

Merci. Je ne connais pas PostRevisor. Je m’y penche dès maintenant.

Je ne suis pas sûr de comprendre ce que vous entendez par zone des métadonnées du sujet. S’agit-il d’un fichier en particulier ? (Du point de vue de l’interface utilisateur, je sais qu’il y a l’éditeur pour la création, avec le d-editor intégré, puis la vue du sujet elle-même. Je ne suis pas sûr de savoir où se trouve la zone « Meta » dans tout cela.)

2 « J'aime »

Je considère que les informations de catégorie et d’étiquette sont des métadonnées.

2 « J'aime »

Voici un exemple de base fonctionnel pour créer un champ personnalisé de sujet, puis le définir. Cela définit le champ lorsque l’utilisateur clique sur un bouton spécifique sur la page de vue du sujet.

Je note que dans les plugins qui utilisent des champs personnalisés de sujet, il est courant d’utiliser PostRevisor (comme PostRevisor.track_topic_field) et DiscourseEvent.on(:topic_created) do |topic|... dans le fichier plugin.rb. Ces approches pourraient permettre de définir le champ personnalisé sans avoir à cliquer sur un bouton — par exemple, lors de la création du sujet. Mais je n’ai pas encore trouvé la solution.

[EDIT : Si quelqu’un souhaite proposer du code pour plugin.rb afin d’ajouter la valeur du champ personnalisé à un sujet au moment de sa création (au lieu d’avoir un bouton séparé à cliquer), n’hésitez pas ! :slight_smile: ]

Voici donc un exemple de base qui fonctionne sans ces fonctionnalités avancées :

plugin.rb

Topic.register_custom_field_type('sample_field', :string)
add_to_class(:topic, :sample_field) { self.custom_fields['sample_field'] } ##peut-être pas nécessaire, basé sur la ligne 83 du plugin discourse-locations plugin.rb
	
add_to_serializer(:topic_view, :sample_field, false) { object.topic.sample_field } ##probablement nécessaire uniquement si vous souhaitez afficher le résultat du champ personnalisé à l'utilisateur

connector/[add-button].hbs

//exemple ici : le connecteur est topic-above-post-stream, qui transmet un modèle (topic) dans l’emplacement du plugin

<button {{action "setThatTopic" model}}>Cliquez ici</button>

connector/[add-button].js.es6

import Topic from 'discourse/models/topic';  //peut-être pas nécessaire

export default {			
    actions: {
       setThatTopic(model){
           model.set('custom_fields.sample_field', 'newValue123')
           console.log('test que le champ personnalisé est présent = ' + JSON.stringify(model.custom_fields))
        }
     }
}

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

//cela peut ne pas être nécessaire. Mais l’idée est d’initialiser l’objet des champs personnalisés et de le rendre envoyable au serveur :

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 « J'aime »

Je viens de publier un « plugin éducatif » montrant comment cela se fait

9 « J'aime »

Merci, @angus. C’est extrêmement utile et exactement le genre de ressource qui rend le développement avec Discourse plus simple. Personnellement, j’adorerais voir ce type de ressource — des exemples de code concis et essentiels pour implémenter une fonctionnalité à la fois — couvrant diverses tâches avec Discourse. Par exemple, des champs personnalisés pour les catégories et les groupes. Ce type de ressource fait gagner un temps précieux.

3 « J'aime »