Recarregar/Atualizar um widget na atualização de outro widget

Olá a todos,

Criamos um widget “topic-timeline-bookmark” que exibe o botão de Bookmark no nível do tópico após o widget topic-timeline.

Agora, sempre que clicamos no botão de bookmark do topic-timeline, ele exibe a caixa de diálogo para definir o bookmark e, ao salvar o bookmark, atualiza os botões de Bookmark sob os botões first-post-menu e topic-footer-button, mas não se atualiza até que o widget topic-timeline seja atualizado (ou seja, até que façamos a rolagem), e vice-versa.

first-post-menu

image


topic-footer-button

image

Percebi que, sempre que um Bookmark é definido/removido, o widget post-stream é atualizado, então os botões de Bookmark do post-menu e do topic-footer-button funcionam em sincronia.

Então, como posso atualizar meu widget “topic-timeline-bookmark” sempre que um Bookmark for definido/removido ou sempre que o widget post-stream for atualizado? Abaixo está meu 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;
              
              //Ícone
              if (bookmarkedPosts.some((bookmark) => bookmark.reminder_at))
                icon = "discourse-bookmark-clock";
              else
                icon = "bookmark";

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

              //Dica de ferramenta
              if (bookmarkedPosts.length === 1)
                  tooltip = 'bookmarked.help.edit_bookmark';
              else if (bookmarkedPosts.find((x) => x.reminder_at))
                  tooltip = 'bookmarked.help.unbookmark_with_reminder';
              
              //Adiciona classe CSS se o bookmark estiver definido
              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>

Obrigado por entrar em contato. Um de nossos desenvolvedores vai analisar isso e retornar com algumas informações úteis.

Olá,

Não testei localmente, mas algo que pode funcionar:

No seu script principal, adicione esta chamada de API:

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

No código do seu widget, declare esta função:

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

  // talvez seja possível nomeá-la schedule-rerender 
  // diretamente na chamada da API em vez de force-refresh
  // e evitar ter essa função
  forceRefresh() {
    this.scheduleRerender();
  }
});

Acho que isso deve funcionar. Se não funcionar, me avise e tentarei criar um exemplo funcional localmente.

Obrigado, @joffreyjaffeux, pela resposta.

Tentamos o código sugerido por você, mas não funcionou.

  1. Adicionamos a seguinte chamada de API:
    api.dispatchWidgetAppEvent('topic-timeline-bookmark', 'force-refresh', 'post-stream:refresh');
    E então adicionamos o método forceRefresh() no widget “topic-timeline-bookmark”.
    Mas não funcionou.

  2. Também tentamos renomear o segundo parâmetro do método dispatchWidgetAppEvent para “schedule-rerender” e removemos a função forceRefresh do widget. Isso também não funcionou.

Verifiquei a implementação do método api.dispatchWidgetAppEvent; ele aceita 3 argumentos, onde o segundo é o widgetKey. Acredito que deveria ser o valor retornado pela função buildKey() do widget.
E o terceiro argumento é o appEvent, que é convertido para camelCase e usado como nome do método para nós.

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

Está faltando algo?

Vou tentar localmente; provavelmente cometi um erro.

@saurabhmasc Consegui fazer funcionar localmente, mas precisei corrigir um bug no core e também adicionar um novo recurso no core. Atualizarei o tópico quando tudo for mesclado.

Obrigado, @j.jaffeux.

Olá @j.jaffeux,

Você tem alguma ideia de quando essas alterações serão mescladas?

Olá, sim, acabei de mesclá-lo (então você precisará implantá-lo primeiro): DEV: adds a topic level bookmark toggle (#14471) · discourse/discourse@20e70d0 · GitHub

Além disso, este é um componente de exemplo que criei para isso:

Avise-me se tiver alguma dúvida.

Olá @j.jaffeux,

  1. Agora notamos que, anteriormente, ao marcar um post nos botões do rodapé do tópico, o primeiro post também era marcado como salvo, mas agora o primeiro post não está sendo salvo. Isso está correto?

  2. Testamos todos os casos do seu componente e eles estão funcionando corretamente, apenas a funcionalidade de limpar marcadores não está sincronizada.
    Para corrigir isso, adicionamos as linhas de código abaixo, e agora a funcionalidade de limpar marcadores também funciona corretamente.

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

Obrigado.

Vou analisar o primeiro ponto. Quanto ao segundo, sim, é possível que eu tenha esquecido um caso. O autor principal dos bookmarks está ausente no momento e gostaria de alterar algumas coisas, mas preciso que ele esteja de volta. Sua correção deve estar ok.

Após vários testes, acredito que isso seja esperado (e não está relacionado ao componente).

Obrigado, @j.jaffeux, pelo seu feedback.

Criaremos um novo ticket solicitando essas alterações principais para nossos ambientes de Staging e Produção. Assim, poderemos testá-las no Staging.