Recargar/Actualizar un widget al actualizar otro widget

Hola a todos,

Hemos creado un widget llamado “topic-timeline-bookmark” que muestra el botón de marcador a nivel de tema después del widget de línea de tiempo del tema.

Ahora, cada vez que hacemos clic en el botón de marcador de topic-timeline, se muestra el cuadro de diálogo modal para establecer el marcador. Al guardar el marcador, se actualizan los botones de marcador debajo de los botones first-post-menu y topic-footer-button, pero no se actualiza a sí mismo hasta que el widget topic-timeline se actualice (es decir, hasta que hagamos scroll), y viceversa.

first-post-menu

image


topic-footer-button

image

He descubierto que cada vez que se establece o desestablece un marcador, el widget post-stream se actualiza, por lo que los botones de marcador de post-menu y topic-footer-button funcionan de forma sincronizada.

Entonces, ¿cómo puedo actualizar mi widget “topic-timeline-bookmark” cada vez que se establece o desestablece un marcador, o cuando el widget post-stream se actualiza? A continuación está mi código:

<script type="text/discourse-plugin" version="0.8">
  const { h } = require('virtual-dom');
  const { getOwner } = require("discourse-common/lib/get-owner");
  const topicController = getOwner(this).lookup("controller:topic");

  api.createWidget("topic-timeline-bookmark", {  
      tagName: 'div.discourse-bookmark-button-wrapper',
      buildKey: () => `topic-timeline-bookmark`,
      toggleBookmark() {
        topicController.send('toggleBookmark');
      },
      html(attrs, state) { 
        let contents = [];
        const user = api.getCurrentUser();
        if (user) {
            let tooltip = 'bookmarked.help.bookmark';
            let label = 'bookmarked.title';
            let buttonClass = 'btn btn-default bookmark';
            let icon = "bookmark";  
            let bookmarkedPosts = topicController.model.bookmarked_posts;
            let bookmarkCount = 0;

            if(bookmarkedPosts && bookmarkedPosts.length > 0){
              bookmarkCount =  bookmarkedPosts.length;
              
              //Icono
              if (bookmarkedPosts.some((bookmark) => bookmark.reminder_at))
                icon = "discourse-bookmark-clock";
              else
                icon = "bookmark";

              //Etiqueta
              if (bookmarkCount === 0)               
                  label = "bookmarked.title";          
              else if (bookmarkCount === 1)
                  label = "bookmarked.edit_bookmark"; 
              else 
                  label = "bookmarked.clear_bookmarks";

              //Consejo de herramienta
              if (bookmarkedPosts.length === 1)
                  tooltip = 'bookmarked.help.edit_bookmark';
              else if (bookmarkedPosts.find((x) => x.reminder_at))
                  tooltip = 'bookmarked.help.unbookmark_with_reminder';
              
              //Agregar clase CSS si el marcador está establecido
              if (bookmarkCount > 0) { buttonClass += ' bookmarked' }
            }
    
            contents.push(
            this.attach('button', {
              action: 'toggleBookmark',
              title: tooltip,
              label: label,
              icon: icon,
              className: buttonClass
            })
          );
        }
        return contents;
      }, 
    });
 
  api.decorateWidget('topic-timeline:after', function(helper) {
    return helper.attach('topic-timeline-bookmark');
  });
</script>

Gracias por contactarnos. Uno de nuestros desarrolladores revisará este asunto y te responderá con información útil.

Hola,

No lo he probado localmente, pero algo que podría funcionar:

En tu script principal, agrega esta llamada a la API:

api.dispatchWidgetAppEvent('topic-timeline-bookmark', 'force-refresh', 'post-stream:refresh');

En el código de tu widget, declara esta función:

api.createWidget("topic-timeline-bookmark", {  
  // código omitido

  // quizás puedas nombrarlo schedule-rerender 
  // directamente en la llamada a la API en lugar de force-refresh
  // y evitar tener esta función
  forceRefresh() {
    this.scheduleRerender();
  }
});

Creo que esto debería funcionar. Si no es así, avísame y trataré de construir un ejemplo funcional localmente.

Gracias, @joffreyjaffeux, por la respuesta.

Hemos probado el código que sugeriste, pero no funciona.

  1. Agregamos la siguiente llamada a la API:
    api.dispatchWidgetAppEvent('topic-timeline-bookmark', 'force-refresh', 'post-stream:refresh');
    Y luego añadimos el método forceRefresh() en el widget “topic-timeline-bookmark”.
    Pero no funciona.

  2. También intenté renombrar el segundo parámetro del método dispatchWidgetAppEvent a “schedule-rerender” y eliminar la función forceRefresh del widget. Esto tampoco funciona.

Revisé la implementación del método api.dispatchWidgetAppEvent y observa que recibe 3 argumentos, donde el segundo es widgetKey. Creo que debería ser el valor devuelto por la función buildKey() del widget.
Y el tercer argumento es el appEvent, que se convierte a camelCase y se utiliza como nombre del método para nosotros.

https://github.com/discourse/discourse/blob/main/app/assets/javascripts/discourse/app/lib/plugin-api.js#L1448

¿Estamos olvidando algo?

Lo probaré localmente; probablemente cometí un error.

@saurabhmasc Logré que funcionara localmente, pero tuve que corregir un error en el núcleo y también agregar una nueva función al núcleo. Actualizaré el tema cuando todo esto se haya fusionado.

Gracias, @j.jaffeux.

Hola @j.jaffeux,

¿Tienes alguna idea de cuándo se fusionarán estos cambios?

¡Hola, sí! Acabo de fusionarlo (así que necesitarás desplegarlo primero): DEV: adds a topic level bookmark toggle (#14471) · discourse/discourse@20e70d0 · GitHub

Además, este es un componente de ejemplo que creé para esto:

Avísame si tienes alguna pregunta.

Hola @j.jaffeux,

  1. Ahora hemos observado que antes, al marcar como favorito desde los botones del pie del tema, la primera publicación también se marcaba como favorita, pero ahora la primera publicación no se está marcando. ¿Es esto correcto ahora?

  2. Hemos probado tu componente y todos los casos funcionan correctamente, solo la funcionalidad de “Borrar favoritos” no funciona en sincronía.
    Para que funcione, hemos agregado las siguientes líneas de código, y ahora la funcionalidad de “Borrar favoritos” también funciona correctamente.

  api.dispatchWidgetAppEvent(
    "topic-timeline",
    "topic-timeline-bookmark",
    "post-stream:refresh"
  );

Gracias.

Revisaré el primer punto. En cuanto al segundo, sí, es posible que haya olvidado un caso. El autor principal de los marcadores está ausente por ahora y me gustaría cambiar algunas cosas, pero necesito que regrese. Tu corrección debería estar bien.

Tras varias pruebas, creo que esto es lo esperado (y no está relacionado con el componente).

Gracias, @j.jaffeux, por tus comentarios.

Crearemos un nuevo ticket solicitando que estos cambios principales se apliquen a nuestros entornos de Staging y Producción. Así podremos probarlos en Staging.